diff options
author | Doug Kwan <dougkwan@google.com> | 2010-01-29 18:23:18 +0000 |
---|---|---|
committer | Doug Kwan <dougkwan@google.com> | 2010-01-29 18:23:18 +0000 |
commit | e7eca48cb283da81b3566df52c01ac510cc1013d (patch) | |
tree | e367aaa3dd15844bda87869721e7c50ecf124d40 /gold/arm.cc | |
parent | b0e28b39b7de5e36bb162657c3b62ba6349ba4b2 (diff) | |
download | gdb-e7eca48cb283da81b3566df52c01ac510cc1013d.zip gdb-e7eca48cb283da81b3566df52c01ac510cc1013d.tar.gz gdb-e7eca48cb283da81b3566df52c01ac510cc1013d.tar.bz2 |
2010-01-29 Doug Kwan <dougkwan@google.com>
* arm.cc (Arm_relobj::Arm_relobj): Initialize new data member
output_local_symbol_count_needs_update_.
(Arm_relobj::output_local_symbol_count_needs_update,
Arm_relobj::set_output_local_symbol_count_needs_update,
Arm_relobj::update_output_local_symbol_count): New methods.
(Arm_relobj::output_local_symbol_count_needs_update_): New data
member.
(Arm_exidx_cantunwind::do_fixed_endian_write): Write address
of pointed function as in a R_ARM_PREL31 relocation.
(Arm_output_section<big_endian>::fix_exidx_coverage): Mark objects
for output local symbol count updating.
(Target_arm::do_relax): Update output local symbol counts in objects
if necessary.
* object.h (Sized_relobj::set_output_local_symbol_count): New method.
Diffstat (limited to 'gold/arm.cc')
-rw-r--r-- | gold/arm.cc | 153 |
1 files changed, 147 insertions, 6 deletions
diff --git a/gold/arm.cc b/gold/arm.cc index 6c7a011..ba3e76c 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -1399,7 +1399,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian> : Sized_relobj<32, big_endian>(name, input_file, offset, ehdr), stub_tables_(), local_symbol_is_thumb_function_(), attributes_section_data_(NULL), mapping_symbols_info_(), - section_has_cortex_a8_workaround_(NULL), exidx_section_map_() + section_has_cortex_a8_workaround_(NULL), exidx_section_map_(), + output_local_symbol_count_needs_update_(false) { } ~Arm_relobj() @@ -1524,6 +1525,20 @@ class Arm_relobj : public Sized_relobj<32, big_endian> : NULL); } + // Whether output local symbol count needs updating. + bool + output_local_symbol_count_needs_update() const + { return this->output_local_symbol_count_needs_update_; } + + // Set output_local_symbol_count_needs_update flag to be true. + void + set_output_local_symbol_count_needs_update() + { this->output_local_symbol_count_needs_update_ = true; } + + // Update output local symbol count at the end of relaxation. + void + update_output_local_symbol_count(); + protected: // Post constructor setup. void @@ -1600,6 +1615,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian> std::vector<bool>* section_has_cortex_a8_workaround_; // Map a text section to its associated .ARM.exidx section, if there is one. Exidx_section_map exidx_section_map_; + // Whether output local symbol count needs updating. + bool output_local_symbol_count_needs_update_; }; // Arm_dynobj class. @@ -4866,7 +4883,10 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of) // Write out the entry. The first word either points to the beginning // or after the end of a text section. The second word is the special // EXIDX_CANTUNWIND value. - elfcpp::Swap<32, big_endian>::writeval(wv, output_address); + uint32_t prel31_offset = output_address - this->address(); + if (utils::has_overflow<31>(offset)) + gold_error(_("PREL31 overflow in EXIDX_CANTUNWIND entry")); + elfcpp::Swap<32, big_endian>::writeval(wv, prel31_offset & 0x7fffffffU); elfcpp::Swap<32, big_endian>::writeval(wv + 1, elfcpp::EXIDX_CANTUNWIND); of->write_output_view(this->offset(), oview_size, oview); @@ -5469,6 +5489,10 @@ Arm_output_section<big_endian>::fix_exidx_coverage( // The whole EXIDX section got merged. Remove it from output. gold_assert(section_offset_map == NULL); exidx_relobj->set_output_section(exidx_shndx, NULL); + + // All local symbols defined in this input section will be dropped. + // We need to adjust output local symbol count. + arm_relobj->set_output_local_symbol_count_needs_update(); } else if (deleted_bytes > 0) { @@ -5480,6 +5504,11 @@ Arm_output_section<big_endian>::fix_exidx_coverage( *section_offset_map, deleted_bytes); this->add_relaxed_input_section(merged_section); arm_relobj->convert_input_section_to_relaxed_section(exidx_shndx); + + // All local symbols defined in discarded portions of this input + // section will be dropped. We need to adjust output local symbol + // count. + arm_relobj->set_output_local_symbol_count_needs_update(); } else { @@ -6106,6 +6135,99 @@ Arm_relobj<big_endian>::do_gc_process_relocs(Symbol_table* symtab, } } +// Update output local symbol count. Owing to EXIDX entry merging, some local +// symbols will be removed in output. Adjust output local symbol count +// accordingly. We can only changed the static output local symbol count. It +// is too late to change the dynamic symbols. + +template<bool big_endian> +void +Arm_relobj<big_endian>::update_output_local_symbol_count() +{ + // Caller should check that this needs updating. We want caller checking + // because output_local_symbol_count_needs_update() is most likely inlined. + gold_assert(this->output_local_symbol_count_needs_update_); + + gold_assert(this->symtab_shndx() != -1U); + if (this->symtab_shndx() == 0) + { + // This object has no symbols. Weird but legal. + return; + } + + // 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); + + // Loop over the local symbols. + + typedef typename Sized_relobj<32, big_endian>::Output_sections + Output_sections; + const Output_sections& out_sections(this->output_sections()); + unsigned int shnum = this->shnum(); + unsigned int count = 0; + // Skip the first, dummy, symbol. + psyms += sym_size; + for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size) + { + elfcpp::Sym<32, big_endian> sym(psyms); + + Symbol_value<32>& lv((*this->local_values())[i]); + + // This local symbol was already discarded by do_count_local_symbols. + if (!lv.needs_output_symtab_entry()) + continue; + + bool is_ordinary; + unsigned int shndx = this->adjust_sym_shndx(i, sym.get_st_shndx(), + &is_ordinary); + + if (shndx < shnum) + { + Output_section* os = out_sections[shndx]; + + // This local symbol no longer has an output section. Discard it. + if (os == NULL) + { + lv.set_no_output_symtab_entry(); + continue; + } + + // Currently we only discard parts of EXIDX input sections. + // We explicitly check for a merged EXIDX input section to avoid + // calling Output_section_data::output_offset unless necessary. + if ((this->get_output_section_offset(shndx) == invalid_address) + && (this->exidx_input_section_by_shndx(shndx) != NULL)) + { + section_offset_type output_offset = + os->output_offset(this, shndx, lv.input_value()); + if (output_offset == -1) + { + // This symbol is defined in a part of an EXIDX input section + // that is discarded due to entry merging. + lv.set_no_output_symtab_entry(); + continue; + } + } + } + + ++count; + } + + this->set_output_local_symbol_count(count); + this->output_local_symbol_count_needs_update_ = false; +} + // Arm_dynobj methods. // Read the symbol information. @@ -6777,6 +6899,8 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, break; case elfcpp::R_ARM_REL32: + break; + case elfcpp::R_ARM_PREL31: { // Make a dynamic relocation if necessary. @@ -9569,10 +9693,27 @@ Target_arm<big_endian>::do_relax( // Finalize the stubs in the last relaxation pass. if (!continue_relaxation) - for (Stub_table_iterator sp = this->stub_tables_.begin(); - (sp != this->stub_tables_.end()) && !any_stub_table_changed; - ++sp) - (*sp)->finalize_stubs(); + { + for (Stub_table_iterator sp = this->stub_tables_.begin(); + (sp != this->stub_tables_.end()) && !any_stub_table_changed; + ++sp) + (*sp)->finalize_stubs(); + + // Update output local symbol counts of objects if necessary. + for (Input_objects::Relobj_iterator op = input_objects->relobj_begin(); + op != input_objects->relobj_end(); + ++op) + { + Arm_relobj<big_endian>* arm_relobj = + Arm_relobj<big_endian>::as_arm_relobj(*op); + + // Update output local symbol counts. We need to discard local + // symbols defined in parts of input sections that are discarded by + // relaxation. + if (arm_relobj->output_local_symbol_count_needs_update()) + arm_relobj->update_output_local_symbol_count(); + } + } return continue_relaxation; } |