diff options
author | Doug Kwan <dougkwan@google.com> | 2010-02-19 02:16:41 +0000 |
---|---|---|
committer | Doug Kwan <dougkwan@google.com> | 2010-02-19 02:16:41 +0000 |
commit | c8761b9af499c6c3405107924478a6d2d476f74e (patch) | |
tree | 54fb0f74806d7659e5f861247675f7d14a342450 /gold | |
parent | d0bf826b37bdeb1ad98dc2d601b450bd5b9043e5 (diff) | |
download | gdb-c8761b9af499c6c3405107924478a6d2d476f74e.zip gdb-c8761b9af499c6c3405107924478a6d2d476f74e.tar.gz gdb-c8761b9af499c6c3405107924478a6d2d476f74e.tar.bz2 |
2010-02-18 Doug Kwan <dougkwan@google.com>
* arm.cc (Arm_relobj::find_linked_text_section): New method.
(Arm_relobj::make_exidx_input_section): Pass section index of linked
text section as a parameter becuase some broken tools may not set
the link in section header.
(Target_arm::has_got_section): New method.
(Target_arm::scan_section_for_cortex_a8_stubs): Treat an input section
without any mapping symbol as data only. Remove warning.
(Arm_relobj::do_read_synbols): If an EXIDX input section has no
link in its section header, try to discover the link by inspecting the
REL31 relocation at the beginning of the section.
(Target_arm::Scan::check_non_pic): Report name of offending relocation
in error message.
(Target_arm::Scan::global): Treat any reference to the symbol
_GLOBAL_OFFSET_TABLE_ as a GOT access.
Diffstat (limited to 'gold')
-rw-r--r-- | gold/ChangeLog | 17 | ||||
-rw-r--r-- | gold/arm.cc | 253 |
2 files changed, 227 insertions, 43 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index eb98592..8796c6d 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,20 @@ +2010-02-18 Doug Kwan <dougkwan@google.com> + + * arm.cc (Arm_relobj::find_linked_text_section): New method. + (Arm_relobj::make_exidx_input_section): Pass section index of linked + text section as a parameter becuase some broken tools may not set + the link in section header. + (Target_arm::has_got_section): New method. + (Target_arm::scan_section_for_cortex_a8_stubs): Treat an input section + without any mapping symbol as data only. Remove warning. + (Arm_relobj::do_read_synbols): If an EXIDX input section has no + link in its section header, try to discover the link by inspecting the + REL31 relocation at the beginning of the section. + (Target_arm::Scan::check_non_pic): Report name of offending relocation + in error message. + (Target_arm::Scan::global): Treat any reference to the symbol + _GLOBAL_OFFSET_TABLE_ as a GOT access. + 2010-02-12 Sriraman Tallam <tmsriram@google.com> * arm.cc (Scan::local_reloc_may_be_function_pointer): New function. diff --git a/gold/arm.cc b/gold/arm.cc index bdbdbd1..d974b1b 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -1597,11 +1597,23 @@ class Arm_relobj : public Sized_relobj<32, big_endian> unsigned int, Output_section*, Target_arm<big_endian>*); + // Find the linked text section of an EXIDX section by looking at the + // first reloction of the EXIDX section. PSHDR points to the section + // headers of a relocation section and PSYMS points to the local symbols. + // PSHNDX points to a location storing the text section index if found. + // Return whether we can find the linked section. + bool + find_linked_text_section(const unsigned char* pshdr, + const unsigned char* psyms, unsigned int* pshndx); + + // // Make a new Arm_exidx_input_section object for EXIDX section with - // index SHNDX and section header SHDR. + // index SHNDX and section header SHDR. TEXT_SHNDX is the section + // index of the linked text section. void make_exidx_input_section(unsigned int shndx, - const elfcpp::Shdr<32, big_endian>& shdr); + const elfcpp::Shdr<32, big_endian>& shdr, + unsigned int text_shndx); // Return the output address of either a plain input section or a // relaxed input section. SHNDX is the section index. @@ -1996,6 +2008,11 @@ class Target_arm : public Sized_target<32, big_endian> do_is_defined_by_abi(Symbol* sym) const { return strcmp(sym->name(), "__tls_get_addr") == 0; } + // Return whether there is a GOT section. + bool + has_got_section() const + { return this->got_ != NULL; } + // Return the size of the GOT section. section_size_type got_size() @@ -5618,6 +5635,17 @@ Arm_relobj<big_endian>::scan_section_for_cortex_a8_erratum( Output_section* os, Target_arm<big_endian>* arm_target) { + // Look for the first mapping symbol in this section. It should be + // at (shndx, 0). + Mapping_symbol_position section_start(shndx, 0); + typename Mapping_symbols_info::const_iterator p = + this->mapping_symbols_info_.lower_bound(section_start); + + // There are no mapping symbols for this section. Treat it as a data-only + // section. + if (p == this->mapping_symbols_info_.end() || p->first.first != shndx) + return; + Arm_address output_address = this->simple_input_section_output_address(shndx, os); @@ -5631,21 +5659,6 @@ Arm_relobj<big_endian>::scan_section_for_cortex_a8_erratum( // THUMB code only. Second, we only want to look at the 4K-page boundary // to speed up the scanning. - // Look for the first mapping symbol in this section. It should be - // at (shndx, 0). - Mapping_symbol_position section_start(shndx, 0); - typename Mapping_symbols_info::const_iterator p = - this->mapping_symbols_info_.lower_bound(section_start); - - if (p == this->mapping_symbols_info_.end() - || p->first != section_start) - { - gold_warning(_("Cortex-A8 erratum scanning failed because there " - "is no mapping symbols for section %u of %s"), - shndx, this->name().c_str()); - return; - } - while (p != this->mapping_symbols_info_.end() && p->first.first == shndx) { @@ -5979,27 +5992,95 @@ Arm_relobj<big_endian>::do_relocate_sections( } } -// Create a new EXIDX input section object for EXIDX section SHNDX with -// header SHDR. +// Find the linked text section of an EXIDX section by looking the the first +// relocation. 4.4.1 of the EHABI specifications says that an EXIDX section +// must be linked to to its associated code section via the sh_link field of +// its section header. However, some tools are broken and the link is not +// always set. LD just drops such an EXIDX section silently, causing the +// associated code not unwindabled. Here we try a little bit harder to +// discover the linked code section. +// +// PSHDR points to the section header of a relocation section of an EXIDX +// section. If we can find a linked text section, return true and +// store the text section index in the location PSHNDX. Otherwise +// return false. template<bool big_endian> -void -Arm_relobj<big_endian>::make_exidx_input_section( - unsigned int shndx, - const elfcpp::Shdr<32, big_endian>& shdr) +bool +Arm_relobj<big_endian>::find_linked_text_section( + const unsigned char* pshdr, + const unsigned char* psyms, + unsigned int* pshndx) { - // Link .text section to its .ARM.exidx section in the same object. - unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_link()); + elfcpp::Shdr<32, big_endian> shdr(pshdr); + + // If there is no relocation, we cannot find the linked text section. + size_t reloc_size; + if (shdr.get_sh_type() == elfcpp::SHT_REL) + reloc_size = elfcpp::Elf_sizes<32>::rel_size; + else + reloc_size = elfcpp::Elf_sizes<32>::rela_size; + size_t reloc_count = shdr.get_sh_size() / reloc_size; + + // Get the relocations. + const unsigned char* prelocs = + this->get_view(shdr.get_sh_offset(), shdr.get_sh_size(), true, false); - // Issue an error and ignore this EXIDX section if it does not point - // to any text section. - if (text_shndx == elfcpp::SHN_UNDEF) + // Find the REL31 relocation for the first word of the first EXIDX entry. + for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size) { - gold_error(_("EXIDX section %u in %s has no linked text section"), - shndx, this->name().c_str()); - return; + Arm_address r_offset; + typename elfcpp::Elf_types<32>::Elf_WXword r_info; + if (shdr.get_sh_type() == elfcpp::SHT_REL) + { + typename elfcpp::Rel<32, big_endian> reloc(prelocs); + r_info = reloc.get_r_info(); + r_offset = reloc.get_r_offset(); + } + else + { + typename elfcpp::Rela<32, big_endian> reloc(prelocs); + r_info = reloc.get_r_info(); + r_offset = reloc.get_r_offset(); + } + + unsigned int r_type = elfcpp::elf_r_type<32>(r_info); + if (r_type != elfcpp::R_ARM_PREL31 && r_type != elfcpp::R_ARM_SBREL31) + continue; + + unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info); + if (r_sym == 0 + || r_sym >= this->local_symbol_count() + || r_offset != 0) + continue; + + // This is the relocation for the first word of the first EXIDX entry. + // We expect to see a local section symbol. + const int sym_size = elfcpp::Elf_sizes<32>::sym_size; + elfcpp::Sym<32, big_endian> sym(psyms + r_sym * sym_size); + if (sym.get_st_type() == elfcpp::STT_SECTION) + { + *pshndx = this->adjust_shndx(sym.get_st_shndx()); + return true; + } + else + return false; } - + + return false; +} + +// Make an EXIDX input section object for an EXIDX section whose index is +// SHNDX. SHDR is the section header of the EXIDX section and TEXT_SHNDX +// is the section index of the linked text section. + +template<bool big_endian> +void +Arm_relobj<big_endian>::make_exidx_input_section( + unsigned int shndx, + const elfcpp::Shdr<32, big_endian>& shdr, + unsigned int text_shndx) +{ // 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) @@ -6040,9 +6121,10 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd) // Go over the section headers and look for .ARM.attributes and .ARM.exidx // sections. + std::vector<unsigned int> deferred_exidx_sections; const size_t shdr_size = elfcpp::Elf_sizes<32>::shdr_size; - const unsigned char *ps = - sd->section_headers->data() + shdr_size; + const unsigned char* pshdrs = sd->section_headers->data(); + const unsigned char *ps = pshdrs + shdr_size; for (unsigned int i = 1; i < this->shnum(); ++i, ps += shdr_size) { elfcpp::Shdr<32, big_endian> shdr(ps); @@ -6058,7 +6140,79 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd) new Attributes_section_data(view->data(), section_size); } else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX) - this->make_exidx_input_section(i, shdr); + { + 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) + deferred_exidx_sections.push_back(i); + else + this->make_exidx_input_section(i, shdr, text_shndx); + } + } + + // Some tools are broken and they do not set the link of EXIDX sections. + // We look at the first relocation to figure out the linked sections. + if (!deferred_exidx_sections.empty()) + { + // We need to go over the section headers again to find the mapping + // from sections being relocated to their relocation sections. This is + // a bit inefficient as we could do that in the loop above. However, + // we do not expect any deferred EXIDX sections normally. So we do not + // want to slow down the most common path. + typedef Unordered_map<unsigned int, unsigned int> Reloc_map; + Reloc_map reloc_map; + ps = pshdrs + shdr_size; + for (unsigned int i = 1; i < this->shnum(); ++i, ps += shdr_size) + { + elfcpp::Shdr<32, big_endian> shdr(ps); + elfcpp::Elf_Word sh_type = shdr.get_sh_type(); + if (sh_type == elfcpp::SHT_REL || sh_type == elfcpp::SHT_RELA) + { + unsigned int info_shndx = this->adjust_shndx(shdr.get_sh_info()); + if (info_shndx >= this->shnum()) + gold_error(_("relocation section %u has invalid info %u"), + i, info_shndx); + Reloc_map::value_type value(info_shndx, i); + std::pair<Reloc_map::iterator, bool> result = + reloc_map.insert(value); + if (!result.second) + gold_error(_("section %u has multiple relocation sections " + "%u and %u"), + info_shndx, i, reloc_map[info_shndx]); + } + } + + // Read the symbol table section header. + const unsigned int symtab_shndx = this->symtab_shndx(); + elfcpp::Shdr<32, big_endian> + symtabshdr(this, this->elf_file()->section_header(symtab_shndx)); + gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB); + + // Read the local symbols. + const int sym_size =elfcpp::Elf_sizes<32>::sym_size; + const unsigned int loccount = this->local_symbol_count(); + gold_assert(loccount == symtabshdr.get_sh_info()); + off_t locsize = loccount * sym_size; + const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(), + locsize, true, true); + + // Process the deferred EXIDX sections. + for(unsigned int i = 0; i < deferred_exidx_sections.size(); ++i) + { + unsigned int shndx = deferred_exidx_sections[i]; + elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size); + unsigned int text_shndx; + 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); + } } } @@ -6562,15 +6716,21 @@ Target_arm<big_endian>::Scan::check_non_pic(Relobj* object, return; default: - // This prevents us from issuing more than one error per reloc - // section. But we can still wind up issuing more than one - // error per object file. - if (this->issued_non_pic_error_) + { + // This prevents us from issuing more than one error per reloc + // section. But we can still wind up issuing more than one + // error per object file. + if (this->issued_non_pic_error_) + return; + const Arm_reloc_property* reloc_property = + arm_reloc_property_table->get_reloc_property(r_type); + gold_assert(reloc_property != NULL); + object->error(_("requires unsupported dynamic reloc %s; " + "recompile with -fPIC"), + reloc_property->name().c_str()); + this->issued_non_pic_error_ = true; return; - object->error(_("requires unsupported dynamic reloc; " - "recompile with -fPIC")); - this->issued_non_pic_error_ = true; - return; + } case elfcpp::R_ARM_NONE: gold_unreachable(); @@ -6802,6 +6962,13 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, unsigned int r_type, Symbol* gsym) { + // A reference to _GLOBAL_OFFSET_TABLE_ implies that we need a got + // section. We check here to avoid creating a dynamic reloc against + // _GLOBAL_OFFSET_TABLE_. + if (!target->has_got_section() + && strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0) + target->got_section(symtab, layout); + r_type = get_real_reloc_type(r_type); switch (r_type) { |