diff options
Diffstat (limited to 'gold/arm.cc')
-rw-r--r-- | gold/arm.cc | 242 |
1 files changed, 188 insertions, 54 deletions
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<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. |