From 131687b4ade7fdff127269e3b92b01ec3d0872c7 Mon Sep 17 00:00:00 2001 From: Doug Kwan Date: Tue, 13 Jul 2010 20:07:08 +0000 Subject: [PATCH] 2010-07-13 Doug Kwan * arm.cc (Arm_input_section::Arm_input_section): For a SHT_ARM_EXIDX section, always keeps the input sections. (Arm_input_section::set_exidx_section_link): New method. (Arm_exidx_input_section::Arm_exidx_input_section): Initialize has_errors_ to false. (Arm_exidx_input_section::has_errors, Arm_exidx_input_section::set_has_errors): New methods. (Arm_exidx_input_section::has_errors_): New data member. (Arm_relobj::get_exidx_shndx_list): New method. (Arm_output_section::append_text_sections_to_list): Do not skip section without SHF_EXECINSTR. (Arm_output_section::fix_exidx_coverage): Skip input sections with errors. (Arm_relobj::make_exidx_input_section): Add new parameter for text section header. Make error messages more verbose. Check for a non-executable section linked to an EXIDX section. (Arm_relobj::do_read_symbols): Remove error checking, which has been moved to Arm_relobj::make_exidx_input_section. Add an assertion to check that there is no deferred EXIDX section if we exit early. Instead of not making an EXIDX section in case of an error, make one and set the has_errors flag of it. (Target_arm::do_finalize_sections): Fix up links of EXIDX sections in a relocatable link. (Target_arm::do_relax): Look for the EXIDX output section instead of assuming that it is called .ARM.exidx. (Target_arm::fix_exidx_coverage): Add a new parameter for input section list. Do not check for SHF_EXECINSTR section flags but skip any input section with errors. * output.cc (Output_section::Output_section): Initialize always_keeps_input_sections_ to false. (Output_section::add_input_section): Check for always_keeps_input_sections_. * output.h (Output_section::always_keeps_input_sections, Output_section::set_always_keeps_input_sections): New methods. (Output_section::always_keeps_input_sections): New data member. --- gold/ChangeLog | 38 ++++++++ gold/arm.cc | 242 ++++++++++++++++++++++++++++++++++++++----------- gold/output.cc | 10 +- gold/output.h | 15 +++ 4 files changed, 248 insertions(+), 57 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 6dbbceda0d4..4f5833b00b0 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,41 @@ +2010-07-13 Doug Kwan + + * arm.cc (Arm_input_section::Arm_input_section): For a + SHT_ARM_EXIDX section, always keeps the input sections. + (Arm_input_section::set_exidx_section_link): New method. + (Arm_exidx_input_section::Arm_exidx_input_section): Initialize + has_errors_ to false. + (Arm_exidx_input_section::has_errors, + Arm_exidx_input_section::set_has_errors): New methods. + (Arm_exidx_input_section::has_errors_): New data member. + (Arm_relobj::get_exidx_shndx_list): New method. + (Arm_output_section::append_text_sections_to_list): Do not skip + section without SHF_EXECINSTR. + (Arm_output_section::fix_exidx_coverage): Skip input sections with + errors. + (Arm_relobj::make_exidx_input_section): Add new parameter for text + section header. Make error messages more verbose. Check for + a non-executable section linked to an EXIDX section. + (Arm_relobj::do_read_symbols): Remove error checking, which has been + moved to Arm_relobj::make_exidx_input_section. Add an assertion to + check that there is no deferred EXIDX section if we exit early. + Instead of not making an EXIDX section in case of an error, make one + and set the has_errors flag of it. + (Target_arm::do_finalize_sections): Fix up links of EXIDX sections + in a relocatable link. + (Target_arm::do_relax): Look for the EXIDX output section instead of + assuming that it is called .ARM.exidx. + (Target_arm::fix_exidx_coverage): Add a new parameter for input + section list. Do not check for SHF_EXECINSTR section flags but + skip any input section with errors. + * output.cc (Output_section::Output_section): Initialize + always_keeps_input_sections_ to false. + (Output_section::add_input_section): Check for + always_keeps_input_sections_. + * output.h (Output_section::always_keeps_input_sections, + Output_section::set_always_keeps_input_sections): New methods. + (Output_section::always_keeps_input_sections): New data member. + 2010-07-13 Rafael Espindola * fileread.cc (try_extra_search_path, find_file): Move to Input_file. diff --git a/gold/arm.cc b/gold/arm.cc index ddfe543ecbb..aadac32dec9 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -1324,7 +1324,10 @@ class Arm_output_section : public Output_section Arm_output_section(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags) : Output_section(name, type, flags) - { } + { + if (type == elfcpp::SHT_ARM_EXIDX) + this->set_always_keeps_input_sections(); + } ~Arm_output_section() { } @@ -1352,6 +1355,10 @@ class Arm_output_section : public Output_section Symbol_table* symtab, bool merge_exidx_entries); + // Link an EXIDX section into its corresponding text section. + void + set_exidx_section_link(); + private: // For convenience. typedef Output_section::Input_section Input_section; @@ -1376,7 +1383,7 @@ class Arm_exidx_input_section Arm_exidx_input_section(Relobj* relobj, unsigned int shndx, unsigned int link, uint32_t size, uint32_t addralign) : relobj_(relobj), shndx_(shndx), link_(link), size_(size), - addralign_(addralign) + addralign_(addralign), has_errors_(false) { } ~Arm_exidx_input_section() @@ -1409,6 +1416,16 @@ class Arm_exidx_input_section addralign() const { return this->addralign_; } + // Whether there are any errors in the EXIDX input section. + bool + has_errors() const + { return this->has_errors_; } + + // Set has-errors flag. + void + set_has_errors() + { this->has_errors_ = true; } + private: // Object containing this. Relobj* relobj_; @@ -1420,6 +1437,8 @@ class Arm_exidx_input_section uint32_t size_; // Address alignment of this. For ARM 32-bit is sufficient. uint32_t addralign_; + // Whether this has any errors. + bool has_errors_; }; // Arm_relobj class. @@ -1581,6 +1600,22 @@ class Arm_relobj : public Sized_relobj<32, big_endian> merge_flags_and_attributes() const { return this->merge_flags_and_attributes_; } + // Export list of EXIDX section indices. + void + get_exidx_shndx_list(std::vector* list) const + { + list->clear(); + for (Exidx_section_map::const_iterator p = this->exidx_section_map_.begin(); + p != this->exidx_section_map_.end(); + ++p) + { + if (p->second->shndx() == p->first) + list->push_back(p->first); + } + // Sort list to make result independent of implementation of map. + std::sort(list->begin(), list->end()); + } + protected: // Post constructor setup. void @@ -1653,7 +1688,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian> void make_exidx_input_section(unsigned int shndx, const elfcpp::Shdr<32, big_endian>& shdr, - unsigned int text_shndx); + unsigned int text_shndx, + const elfcpp::Shdr<32, big_endian>& text_shdr); // Return the output address of either a plain input section or a // relaxed input section. SHNDX is the section index. @@ -2764,7 +2800,8 @@ class Target_arm : public Sized_target<32, big_endian> // Fix .ARM.exidx section coverage. void - fix_exidx_coverage(Layout*, Arm_output_section*, Symbol_table*); + fix_exidx_coverage(Layout*, const Input_objects*, + Arm_output_section*, Symbol_table*); // Functors for STL set. struct output_section_address_less_than @@ -5655,10 +5692,6 @@ void Arm_output_section::append_text_sections_to_list( Text_section_list* list) { - // We only care about text sections. - if ((this->flags() & elfcpp::SHF_EXECINSTR) == 0) - return; - gold_assert((this->flags() & elfcpp::SHF_ALLOC) != 0); for (Input_section_list::const_iterator p = this->input_sections().begin(); @@ -5731,9 +5764,10 @@ Arm_output_section::fix_exidx_coverage( const Arm_exidx_input_section* exidx_input_section = arm_relobj->exidx_input_section_by_link(shndx); - // If this text section has no EXIDX section, force an EXIDX_CANTUNWIND - // entry pointing to the end of the last seen EXIDX section. - if (exidx_input_section == NULL) + // If this text section has no EXIDX section or if the EXIDX section + // has errors, force an EXIDX_CANTUNWIND entry pointing to the end + // of the last seen EXIDX section. + if (exidx_input_section == NULL || exidx_input_section->has_errors()) { exidx_fixup.add_exidx_cantunwind_as_needed(); continue; @@ -5817,15 +5851,20 @@ Arm_output_section::fix_exidx_coverage( if (processed_input_sections.find(Section_id(p->relobj(), p->shndx())) == processed_input_sections.end()) { - // We only discard a known EXIDX section because its linked - // text section has been folded by ICF. + // We discard a known EXIDX section because its linked + // text section has been folded by ICF. We also discard an + // EXIDX section with error, the output does not matter in this + // case. We do this to avoid triggering asserts. Arm_relobj* arm_relobj = Arm_relobj::as_arm_relobj(p->relobj()); const Arm_exidx_input_section* exidx_input_section = arm_relobj->exidx_input_section_by_shndx(p->shndx()); gold_assert(exidx_input_section != NULL); - unsigned int text_shndx = exidx_input_section->link(); - gold_assert(symtab->is_section_folded(p->relobj(), text_shndx)); + if (!exidx_input_section->has_errors()) + { + unsigned int text_shndx = exidx_input_section->link(); + gold_assert(symtab->is_section_folded(p->relobj(), text_shndx)); + } // Remove this from link. We also need to recount the // local symbols. @@ -5844,6 +5883,28 @@ Arm_output_section::fix_exidx_coverage( this->set_section_offsets_need_adjustment(); } +// Link EXIDX output sections to text output sections. + +template +void +Arm_output_section::set_exidx_section_link() +{ + gold_assert(this->type() == elfcpp::SHT_ARM_EXIDX); + if (!this->input_sections().empty()) + { + Input_section_list::const_iterator p = this->input_sections().begin(); + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(p->relobj()); + unsigned exidx_shndx = p->shndx(); + const Arm_exidx_input_section* exidx_input_section = + arm_relobj->exidx_input_section_by_shndx(exidx_shndx); + gold_assert(exidx_input_section != NULL); + unsigned int text_shndx = exidx_input_section->link(); + Output_section* os = arm_relobj->output_section(text_shndx); + this->set_link_section(os); + } +} + // Arm_relobj methods. // Determine if an input section is scannable for stub processing. SHDR is @@ -6445,28 +6506,57 @@ void Arm_relobj::make_exidx_input_section( unsigned int shndx, const elfcpp::Shdr<32, big_endian>& shdr, - unsigned int text_shndx) + unsigned int text_shndx, + const elfcpp::Shdr<32, big_endian>& text_shdr) { - // Issue an error and ignore this EXIDX section if it points to a text - // section already has an EXIDX section. - if (this->exidx_section_map_[text_shndx] != NULL) - { - gold_error(_("EXIDX sections %u and %u both link to text section %u " - "in %s"), - shndx, this->exidx_section_map_[text_shndx]->shndx(), - text_shndx, this->name().c_str()); - return; - } - // Create an Arm_exidx_input_section object for this EXIDX section. Arm_exidx_input_section* exidx_input_section = new Arm_exidx_input_section(this, shndx, text_shndx, shdr.get_sh_size(), shdr.get_sh_addralign()); - this->exidx_section_map_[text_shndx] = exidx_input_section; - // Also map the EXIDX section index to this. gold_assert(this->exidx_section_map_[shndx] == NULL); this->exidx_section_map_[shndx] = exidx_input_section; + + if (text_shndx == elfcpp::SHN_UNDEF || text_shndx >= this->shnum()) + { + gold_error(_("EXIDX section %s(%u) links to invalid section %u in %s"), + this->section_name(shndx).c_str(), shndx, text_shndx, + this->name().c_str()); + exidx_input_section->set_has_errors(); + } + else if (this->exidx_section_map_[text_shndx] != NULL) + { + unsigned other_exidx_shndx = + this->exidx_section_map_[text_shndx]->shndx(); + gold_error(_("EXIDX sections %s(%u) and %s(%u) both link to text section" + "%s(%u) in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(other_exidx_shndx).c_str(), + other_exidx_shndx, this->section_name(text_shndx).c_str(), + text_shndx, this->name().c_str()); + exidx_input_section->set_has_errors(); + } + else + this->exidx_section_map_[text_shndx] = exidx_input_section; + + // Check section flags of text section. + if ((text_shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + gold_error(_("EXIDX section %s(%u) links to non-allocated section %s(%u) " + " in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(text_shndx).c_str(), text_shndx, + this->name().c_str()); + exidx_input_section->set_has_errors(); + } + else if ((text_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) == 0) + // I would like to make this an error but currenlty ld just ignores + // this. + gold_warning(_("EXIDX section %s(%u) links to non-executable section " + "%s(%u) in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(text_shndx).c_str(), text_shndx, + this->name().c_str()); } // Read the symbol information. @@ -6536,19 +6626,21 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX) { unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_link()); - if (text_shndx >= this->shnum()) - gold_error(_("EXIDX section %u linked to invalid section %u"), - i, text_shndx); - else if (text_shndx == elfcpp::SHN_UNDEF) + if (text_shndx == elfcpp::SHN_UNDEF) deferred_exidx_sections.push_back(i); else - this->make_exidx_input_section(i, shdr, text_shndx); + { + elfcpp::Shdr<32, big_endian> text_shdr(pshdrs + + text_shndx * shdr_size); + this->make_exidx_input_section(i, shdr, text_shndx, text_shdr); + } } } // This is rare. if (!must_merge_flags_and_attributes) { + gold_assert(deferred_exidx_sections.empty()); this->merge_flags_and_attributes_ = false; return; } @@ -6604,15 +6696,14 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) { unsigned int shndx = deferred_exidx_sections[i]; elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size); - unsigned int text_shndx; + unsigned int text_shndx = elfcpp::SHN_UNDEF; Reloc_map::const_iterator it = reloc_map.find(shndx); - if (it != reloc_map.end() - && find_linked_text_section(pshdrs + it->second * shdr_size, - psyms, &text_shndx)) - this->make_exidx_input_section(shndx, shdr, text_shndx); - else - gold_error(_("EXIDX section %u has no linked text section."), - shndx); + if (it != reloc_map.end()) + find_linked_text_section(pshdrs + it->second * shdr_size, + psyms, &text_shndx); + elfcpp::Shdr<32, big_endian> text_shdr(pshdrs + + text_shndx * shdr_size); + this->make_exidx_input_section(shndx, shdr, text_shndx, text_shdr); } } } @@ -8306,6 +8397,17 @@ Target_arm::do_finalize_sections( attributes_section, false, false, false, false); } + + // Fix up links in section EXIDX headers. + for (Layout::Section_list::const_iterator p = layout->section_list().begin(); + p != layout->section_list().end(); + ++p) + if ((*p)->type() == elfcpp::SHT_ARM_EXIDX) + { + Arm_output_section* os = + Arm_output_section::as_arm_output_section(*p); + os->set_exidx_section_link(); + } } // Return whether a direct absolute static relocation needs to be applied. @@ -10969,12 +11071,28 @@ Target_arm::do_relax( group_sections(layout, stub_group_size, stubs_always_after_branch); // Also fix .ARM.exidx section coverage. - Output_section* os = layout->find_output_section(".ARM.exidx"); - if (os != NULL && os->type() == elfcpp::SHT_ARM_EXIDX) + Arm_output_section* exidx_output_section = NULL; + for (Layout::Section_list::const_iterator p = + layout->section_list().begin(); + p != layout->section_list().end(); + ++p) + if ((*p)->type() == elfcpp::SHT_ARM_EXIDX) + { + if (exidx_output_section == NULL) + exidx_output_section = + Arm_output_section::as_arm_output_section(*p); + else + // We cannot handle this now. + gold_error(_("multiple SHT_ARM_EXIDX sections %s and %s in a " + "non-relocatable link"), + exidx_output_section->name(), + (*p)->name()); + } + + if (exidx_output_section != NULL) { - Arm_output_section* exidx_output_section = - Arm_output_section::as_arm_output_section(os); - this->fix_exidx_coverage(layout, exidx_output_section, symtab); + this->fix_exidx_coverage(layout, input_objects, exidx_output_section, + symtab); done_exidx_fixup = true; } } @@ -11425,6 +11543,7 @@ template void Target_arm::fix_exidx_coverage( Layout* layout, + const Input_objects* input_objects, Arm_output_section* exidx_section, Symbol_table* symtab) { @@ -11437,15 +11556,30 @@ Target_arm::fix_exidx_coverage( typedef std::set Sorted_output_section_list; Sorted_output_section_list sorted_output_sections; - Layout::Section_list section_list; - layout->get_allocated_sections(§ion_list); - for (Layout::Section_list::const_iterator p = section_list.begin(); - p != section_list.end(); + + // Find out all the output sections of input sections pointed by + // EXIDX input sections. + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); ++p) { - // We only care about output sections that contain executable code. - if (((*p)->flags() & elfcpp::SHF_EXECINSTR) != 0) - sorted_output_sections.insert(*p); + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(*p); + std::vector shndx_list; + arm_relobj->get_exidx_shndx_list(&shndx_list); + for (size_t i = 0; i < shndx_list.size(); ++i) + { + const Arm_exidx_input_section* exidx_input_section = + arm_relobj->exidx_input_section_by_shndx(shndx_list[i]); + gold_assert(exidx_input_section != NULL); + if (!exidx_input_section->has_errors()) + { + unsigned int text_shndx = exidx_input_section->link(); + Output_section *os = arm_relobj->output_section(text_shndx); + if (os != NULL && (os->flags() & elfcpp::SHF_ALLOC) != 0) + sorted_output_sections.insert(os); + } + } } // Go over the output sections in ascending order of output addresses. diff --git a/gold/output.cc b/gold/output.cc index 3ac8a3ddcc6..a487eb8689c 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -1949,6 +1949,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, is_entsize_zero_(false), section_offsets_need_adjustment_(false), is_noload_(false), + always_keeps_input_sections_(false), tls_offset_(0), checkpoint_(NULL), lookup_maps_(new Output_section_lookup_maps) @@ -2038,8 +2039,10 @@ Output_section::add_input_section(Layout* layout, { // Keep information about merged input sections for rebuilding fast // lookup maps if we have sections-script or we do relaxation. - bool keeps_input_sections = - have_sections_script || parameters->target().may_relax(); + bool keeps_input_sections = (this->always_keeps_input_sections_ + || have_sections_script + || parameters->target().may_relax()); + if (this->add_merge_input_section(object, shndx, sh_flags, entsize, addralign, keeps_input_sections)) { @@ -2100,7 +2103,8 @@ Output_section::add_input_section(Layout* layout, // the future, we keep track of the sections. If the // --section-ordering-file option is used to specify the order of // sections, we need to keep track of sections. - if (have_sections_script + if (this->always_keeps_input_sections_ + || have_sections_script || !this->input_sections_.empty() || this->may_sort_attached_input_sections() || this->must_sort_attached_input_sections() diff --git a/gold/output.h b/gold/output.h index 735571839c9..894773d19c5 100644 --- a/gold/output.h +++ b/gold/output.h @@ -3468,6 +3468,19 @@ class Output_section : public Output_data input_sections() const { return this->input_sections_; } + // Whether this always keeps an input section list + bool + always_keeps_input_sections() const + { return this->always_keeps_input_sections_; } + + // Always keep an input section list. + void + set_always_keeps_input_sections() + { + gold_assert(this->current_data_size_for_child() == 0); + this->always_keeps_input_sections_ = true; + } + private: // We only save enough information to undo the effects of section layout. class Checkpoint_output_section @@ -3784,6 +3797,8 @@ class Output_section : public Output_data bool section_offsets_need_adjustment_ : 1; // Whether this is a NOLOAD section. bool is_noload_ : 1; + // Whether this always keeps input section. + bool always_keeps_input_sections_ : 1; // For SHT_TLS sections, the offset of this section relative to the base // of the TLS segment. uint64_t tls_offset_; -- 2.30.2