diff options
Diffstat (limited to 'binutils-2.19/gold/arm.cc')
-rw-r--r-- | binutils-2.19/gold/arm.cc | 376 |
1 files changed, 304 insertions, 72 deletions
diff --git a/binutils-2.19/gold/arm.cc b/binutils-2.19/gold/arm.cc index 76f28be..566e326 100644 --- a/binutils-2.19/gold/arm.cc +++ b/binutils-2.19/gold/arm.cc @@ -1320,7 +1320,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() { } @@ -1347,6 +1350,10 @@ class Arm_output_section : public Output_section const Text_section_list& sorted_text_section, Symbol_table* symtab); + // Link an EXIDX section into its corresponding text section. + void + set_exidx_section_link(); + private: // For convenience. typedef Output_section::Input_section Input_section; @@ -1371,7 +1378,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() @@ -1404,6 +1411,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_; @@ -1415,6 +1432,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. @@ -1576,6 +1595,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 @@ -1648,7 +1683,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. @@ -2104,6 +2140,23 @@ class Target_arm : public Sized_target<32, big_endian> fix_cortex_a8_(false), cortex_a8_relocs_info_() { } + // Virtual function which is set to return true by a target if + // it can use relocation types to determine if a function's + // pointer is taken. + virtual bool + can_check_for_function_pointers() const + { return true; } + + // Whether a section called SECTION_NAME may have function pointers to + // sections not eligible for safe ICF folding. + virtual bool + section_may_have_icf_unsafe_pointers(const char* section_name) const + { + return (!is_prefix_of(".ARM.exidx", section_name) + && !is_prefix_of(".ARM.extab", section_name) + && Target::section_may_have_icf_unsafe_pointers(section_name)); + } + // Whether we can use BLX. bool may_use_blx() const @@ -2460,8 +2513,7 @@ class Target_arm : public Sized_target<32, big_endian> Output_section* , const elfcpp::Rel<32, big_endian>& , unsigned int , - const elfcpp::Sym<32, big_endian>&) - { return false; } + const elfcpp::Sym<32, big_endian>&); inline bool global_reloc_may_be_function_pointer(Symbol_table* , Layout* , Target_arm* , @@ -2469,8 +2521,7 @@ class Target_arm : public Sized_target<32, big_endian> unsigned int , Output_section* , const elfcpp::Rel<32, big_endian>& , - unsigned int , Symbol*) - { return false; } + unsigned int , Symbol*); private: static void @@ -2501,6 +2552,9 @@ class Target_arm : public Sized_target<32, big_endian> || sym->is_preemptible())); } + inline bool + possible_function_pointer_reloc(unsigned int r_type); + // Whether we have issued an error about a non-PIC compilation. bool issued_non_pic_error_; }; @@ -2732,7 +2786,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 @@ -5624,10 +5679,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(); @@ -5699,9 +5750,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; @@ -5785,15 +5837,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. @@ -5812,6 +5869,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 @@ -6413,28 +6492,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. @@ -6504,19 +6612,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; } @@ -6572,15 +6682,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); } } } @@ -7672,6 +7781,72 @@ Target_arm<big_endian>::Scan::unsupported_reloc_global( object->name().c_str(), r_type, gsym->demangled_name().c_str()); } +template<bool big_endian> +inline bool +Target_arm<big_endian>::Scan::possible_function_pointer_reloc( + unsigned int r_type) +{ + switch (r_type) + { + case elfcpp::R_ARM_PC24: + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_PLT32: + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_THM_JUMP24: + case elfcpp::R_ARM_SBREL31: + case elfcpp::R_ARM_PREL31: + case elfcpp::R_ARM_THM_JUMP19: + case elfcpp::R_ARM_THM_JUMP6: + case elfcpp::R_ARM_THM_JUMP11: + case elfcpp::R_ARM_THM_JUMP8: + // All the relocations above are branches except SBREL31 and PREL31. + return false; + + default: + // Be conservative and assume this is a function pointer. + return true; + } +} + +template<bool big_endian> +inline bool +Target_arm<big_endian>::Scan::local_reloc_may_be_function_pointer( + Symbol_table*, + Layout*, + Target_arm<big_endian>* target, + Sized_relobj<32, big_endian>*, + unsigned int, + Output_section*, + const elfcpp::Rel<32, big_endian>&, + unsigned int r_type, + const elfcpp::Sym<32, big_endian>&) +{ + r_type = target->get_real_reloc_type(r_type); + return possible_function_pointer_reloc(r_type); +} + +template<bool big_endian> +inline bool +Target_arm<big_endian>::Scan::global_reloc_may_be_function_pointer( + Symbol_table*, + Layout*, + Target_arm<big_endian>* target, + Sized_relobj<32, big_endian>*, + unsigned int, + Output_section*, + const elfcpp::Rel<32, big_endian>&, + unsigned int r_type, + Symbol* gsym) +{ + // GOT is not a function. + if (strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0) + return false; + + r_type = target->get_real_reloc_type(r_type); + return possible_function_pointer_reloc(r_type); +} + // Scan a relocation for a global symbol. template<bool big_endian> @@ -8090,6 +8265,7 @@ Target_arm<big_endian>::do_finalize_sections( if (this->attributes_section_data_ == NULL) this->attributes_section_data_ = new Attributes_section_data(NULL, 0); + bool merged_any_attributes = false; // Merge processor-specific flags. for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); p != input_objects->relobj_end(); @@ -8104,6 +8280,7 @@ Target_arm<big_endian>::do_finalize_sections( arm_relobj->processor_specific_flags()); this->merge_object_attributes(arm_relobj->name().c_str(), arm_relobj->attributes_section_data()); + merged_any_attributes = true; } } @@ -8118,6 +8295,7 @@ Target_arm<big_endian>::do_finalize_sections( arm_dynobj->processor_specific_flags()); this->merge_object_attributes(arm_dynobj->name().c_str(), arm_dynobj->attributes_section_data()); + merged_any_attributes = true; } // Check BLX use. @@ -8193,9 +8371,9 @@ Target_arm<big_endian>::do_finalize_sections( } } - // Create an .ARM.attributes section unless we have no regular input - // object. In that case the output will be empty. - if (input_objects->number_of_relobjs() != 0) + // Create an .ARM.attributes section if we have merged any attributes + // from inputs. + if (merged_any_attributes) { Output_attributes_section_data* attributes_section = new Output_attributes_section_data(*this->attributes_section_data_); @@ -8204,6 +8382,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. @@ -8306,6 +8495,13 @@ Target_arm<big_endian>::Relocate::relocate( // be converted into an NOP. is_weakly_undefined_without_plt = true; } + else if (gsym->is_undefined() && reloc_property->uses_symbol()) + { + // This relocation uses the symbol value but the symbol is + // undefined. Exit early and have the caller reporting an + // error. + return true; + } else { // Set thumb bit if symbol: @@ -10760,12 +10956,6 @@ Target_arm<big_endian>::do_relax( bool stubs_always_after_branch = stub_group_size_param < 0; section_size_type stub_group_size = abs(stub_group_size_param); - // The Cortex-A8 erratum fix depends on stubs not being in the same 4K - // page as the first half of a 32-bit branch straddling two 4K pages. - // This is a crude way of enforcing that. - if (this->fix_cortex_a8_) - stubs_always_after_branch = true; - if (stub_group_size == 1) { // Default value. @@ -10775,25 +10965,51 @@ Target_arm<big_endian>::do_relax( // fixing cortex-a8 errata, the branch range has to be even smaller, // since wide conditional branch has a range of +-1MB only. // - // This value is 24K less than that, which allows for 2025 + // This value is 48K less than that, which allows for 4096 // 12-byte stubs. If we exceed that, then we will fail to link. // The user will have to relink with an explicit group size // option. - if (this->fix_cortex_a8_) - stub_group_size = 1024276; - else - stub_group_size = 4170000; + stub_group_size = 4145152; + } + + // The Cortex-A8 erratum fix depends on stubs not being in the same 4K + // page as the first half of a 32-bit branch straddling two 4K pages. + // This is a crude way of enforcing that. In addition, long conditional + // branches of THUMB-2 have a range of +-1M. If we are fixing cortex-A8 + // erratum, limit the group size to (1M - 12k) to avoid unreachable + // cortex-A8 stubs from long conditional branches. + if (this->fix_cortex_a8_) + { + stubs_always_after_branch = true; + const section_size_type cortex_a8_group_size = 1024 * (1024 - 12); + stub_group_size = std::max(stub_group_size, cortex_a8_group_size); } 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; } } @@ -11244,6 +11460,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) { @@ -11256,15 +11473,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. |