diff options
-rw-r--r-- | gold/ChangeLog | 38 | ||||
-rw-r--r-- | gold/arm.cc | 242 | ||||
-rw-r--r-- | gold/output.cc | 10 | ||||
-rw-r--r-- | gold/output.h | 15 |
4 files changed, 248 insertions, 57 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 6dbbced..4f5833b 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,41 @@ +2010-07-13 Doug Kwan <dougkwan@google.com> + + * 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 <espindola@google.com> * fileread.cc (try_extra_search_path, find_file): Move to Input_file. diff --git a/gold/arm.cc b/gold/arm.cc index ddfe543..aadac32 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<unsigned int>* 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<big_endian>*, Symbol_table*); + fix_exidx_coverage(Layout*, const Input_objects*, + Arm_output_section<big_endian>*, Symbol_table*); // Functors for STL set. struct output_section_address_less_than @@ -5655,10 +5692,6 @@ void Arm_output_section<big_endian>::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<big_endian>::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<big_endian>::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<big_endian>* arm_relobj = Arm_relobj<big_endian>::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<big_endian>::fix_exidx_coverage( this->set_section_offsets_need_adjustment(); } +// Link EXIDX output sections to text output sections. + +template<bool big_endian> +void +Arm_output_section<big_endian>::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<big_endian>* arm_relobj = + Arm_relobj<big_endian>::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<big_endian>::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<big_endian>::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<big_endian>::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<big_endian>::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<big_endian>* os = + Arm_output_section<big_endian>::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<big_endian>::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<big_endian>* 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<big_endian>::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<big_endian>* exidx_output_section = - Arm_output_section<big_endian>::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<bool big_endian> void Target_arm<big_endian>::fix_exidx_coverage( Layout* layout, + const Input_objects* input_objects, Arm_output_section<big_endian>* exidx_section, Symbol_table* symtab) { @@ -11437,15 +11556,30 @@ Target_arm<big_endian>::fix_exidx_coverage( typedef std::set<Output_section*, output_section_address_less_than> 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<big_endian>* arm_relobj = + Arm_relobj<big_endian>::as_arm_relobj(*p); + std::vector<unsigned int> 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 3ac8a3d..a487eb8 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 7355718..894773d 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_; |