diff options
author | Doug Kwan <dougkwan@google.com> | 2010-09-08 23:54:51 +0000 |
---|---|---|
committer | Doug Kwan <dougkwan@google.com> | 2010-09-08 23:54:51 +0000 |
commit | aa98ff75dd6197c120e5c962048a71d9c9626e08 (patch) | |
tree | 2aad2bdf3900143fcfe75bd413a0d0462a9dd76d /gold/object.cc | |
parent | 5e1617b13f13c2de52e23a947ef85bcdb99a5b05 (diff) | |
download | gdb-aa98ff75dd6197c120e5c962048a71d9c9626e08.zip gdb-aa98ff75dd6197c120e5c962048a71d9c9626e08.tar.gz gdb-aa98ff75dd6197c120e5c962048a71d9c9626e08.tar.bz2 |
2010-09-08 Doug Kwan <dougkwan@google.com>
* arm.cc (Arm_exidx_cantunwind::do_print_to_mapfile): New method.
(Arm_relobj::do_relocate_sections): Add new parameter for output
file to match the parent.
(Target_arm::scan_reloc_section_for_stubs): Use would-be final values
of local symbols instead of input values. Update code to track
changes in gold::relocate_section.
* object.cc (Sized_relobj::compute_final_local_value): New methods.
(Sized_relobj::compute_final_local_value_internal): New methods.
(Sized_relobj::do_finalize_local_symbols): Move code from loop
body into private version of Sized_relobj::compute_final_local_value.
Call the inline method.
* object.h (Symbol_value::Symbol_value): Define destructor. Free
merged symbol value if there is one.
(Symbol_value::has_output_value): New method defintiion.
(Sized_relobj::Compute_final_local_value_status): New enum type.
(Sized_relobj::compute_final_local_value): New methods.
(Sized_relobj::compute_final_local_value_internal): New methods.
* Makefile.am (check_SCRIPTS): Add arm_branch_out_of_range.sh
and arm_cortex_a8.sh.
(thumb_bl_out_of_range_local, arm_cortex_a8_b_cond, arm_cortex_a8_bl,
arm_cortex_a8_blx, arm_cortex_a8_local, arm_corte_a8_local_reloc):
New tests.
* Makefile.in: Regenerate.
* testsuite/arm_bl_out_of_range.s: Update test.
* testsuite/thumb_bl_out_of_range.s: Ditto.
* testsuite/thumb_blx_out_of_range.s: Ditto.
* testsuite/arm_branch_out_of_range.sh: New file.
* testsuite/arm_cortex_a8.sh: Ditto.
* testsuite/arm_cortex_a8_b.s: Ditto.
* testsuite/arm_cortex_a8_b_cond.s: Ditto.
* testsuite/arm_cortex_a8_b_local.s: Ditto.
* testsuite/arm_cortex_a8_bl.s: Ditto.
* testsuite/arm_cortex_a8_blx.s: Ditto.
* testsuite/arm_cortex_a8_local.s: Ditto.
* testsuite/arm_cortex_a8_local_reloc.s: Ditto.
* testsuite/thumb_bl_out_of_range_local.s: Ditto.
Diffstat (limited to 'gold/object.cc')
-rw-r--r-- | gold/object.cc | 316 |
1 files changed, 189 insertions, 127 deletions
diff --git a/gold/object.cc b/gold/object.cc index bdeb141..7bd35f3 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -1878,6 +1878,178 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool, this->output_local_dynsym_count_ = dyncount; } +// Compute the final value of a local symbol. + +template<int size, bool big_endian> +typename Sized_relobj<size, big_endian>::Compute_final_local_value_status +Sized_relobj<size, big_endian>::compute_final_local_value_internal( + unsigned int r_sym, + const Symbol_value<size>* lv_in, + Symbol_value<size>* lv_out, + bool relocatable, + const Output_sections& out_sections, + const std::vector<Address>& out_offsets, + const Symbol_table* symtab) +{ + // We are going to overwrite *LV_OUT, if it has a merged symbol value, + // we may have a memory leak. + gold_assert(lv_out->has_output_value()); + + bool is_ordinary; + unsigned int shndx = lv_in->input_shndx(&is_ordinary); + + // Set the output symbol value. + + if (!is_ordinary) + { + if (shndx == elfcpp::SHN_ABS || Symbol::is_common_shndx(shndx)) + lv_out->set_output_value(lv_in->input_value()); + else + { + this->error(_("unknown section index %u for local symbol %u"), + shndx, r_sym); + lv_out->set_output_value(0); + return This::CFLV_ERROR; + } + } + else + { + if (shndx >= this->shnum()) + { + this->error(_("local symbol %u section index %u out of range"), + r_sym, shndx); + lv_out->set_output_value(0); + return This::CFLV_ERROR; + } + + Output_section* os = out_sections[shndx]; + Address secoffset = out_offsets[shndx]; + if (symtab->is_section_folded(this, shndx)) + { + gold_assert(os == NULL && secoffset == invalid_address); + // Get the os of the section it is folded onto. + Section_id folded = symtab->icf()->get_folded_section(this, + shndx); + gold_assert(folded.first != NULL); + Sized_relobj<size, big_endian>* folded_obj = reinterpret_cast + <Sized_relobj<size, big_endian>*>(folded.first); + os = folded_obj->output_section(folded.second); + gold_assert(os != NULL); + secoffset = folded_obj->get_output_section_offset(folded.second); + + // This could be a relaxed input section. + if (secoffset == invalid_address) + { + const Output_relaxed_input_section* relaxed_section = + os->find_relaxed_input_section(folded_obj, folded.second); + gold_assert(relaxed_section != NULL); + secoffset = relaxed_section->address() - os->address(); + } + } + + if (os == NULL) + { + // This local symbol belongs to a section we are discarding. + // In some cases when applying relocations later, we will + // attempt to match it to the corresponding kept section, + // so we leave the input value unchanged here. + return This::CFLV_DISCARDED; + } + else if (secoffset == invalid_address) + { + uint64_t start; + + // This is a SHF_MERGE section or one which otherwise + // requires special handling. + if (shndx == this->discarded_eh_frame_shndx_) + { + // This local symbol belongs to a discarded .eh_frame + // section. Just treat it like the case in which + // os == NULL above. + gold_assert(this->has_eh_frame_); + return This::CFLV_DISCARDED; + } + else if (!lv_in->is_section_symbol()) + { + // This is not a section symbol. We can determine + // the final value now. + lv_out->set_output_value( + os->output_address(this, shndx, lv_in->input_value())); + } + else if (!os->find_starting_output_address(this, shndx, &start)) + { + // This is a section symbol, but apparently not one in a + // merged section. First check to see if this is a relaxed + // input section. If so, use its address. Otherwise just + // use the start of the output section. This happens with + // relocatable links when the input object has section + // symbols for arbitrary non-merge sections. + const Output_section_data* posd = + os->find_relaxed_input_section(this, shndx); + if (posd != NULL) + { + Address relocatable_link_adjustment = + relocatable ? os->address() : 0; + lv_out->set_output_value(posd->address() + - relocatable_link_adjustment); + } + else + lv_out->set_output_value(os->address()); + } + else + { + // We have to consider the addend to determine the + // value to use in a relocation. START is the start + // of this input section. If we are doing a relocatable + // link, use offset from start output section instead of + // address. + Address adjusted_start = + relocatable ? start - os->address() : start; + Merged_symbol_value<size>* msv = + new Merged_symbol_value<size>(lv_in->input_value(), + adjusted_start); + lv_out->set_merged_symbol_value(msv); + } + } + else if (lv_in->is_tls_symbol()) + lv_out->set_output_value(os->tls_offset() + + secoffset + + lv_in->input_value()); + else + lv_out->set_output_value((relocatable ? 0 : os->address()) + + secoffset + + lv_in->input_value()); + } + return This::CFLV_OK; +} + +// Compute final local symbol value. R_SYM is the index of a local +// symbol in symbol table. LV points to a symbol value, which is +// expected to hold the input value and to be over-written by the +// final value. SYMTAB points to a symbol table. Some targets may want +// to know would-be-finalized local symbol values in relaxation. +// Hence we provide this method. Since this method updates *LV, a +// callee should make a copy of the original local symbol value and +// use the copy instead of modifying an object's local symbols before +// everything is finalized. The caller should also free up any allocated +// memory in the return value in *LV. +template<int size, bool big_endian> +typename Sized_relobj<size, big_endian>::Compute_final_local_value_status +Sized_relobj<size, big_endian>::compute_final_local_value( + unsigned int r_sym, + const Symbol_value<size>* lv_in, + Symbol_value<size>* lv_out, + const Symbol_table* symtab) +{ + // This is just a wrapper of compute_final_local_value_internal. + const bool relocatable = parameters->options().relocatable(); + const Output_sections& out_sections(this->output_sections()); + const std::vector<Address>& out_offsets(this->section_offsets_); + return this->compute_final_local_value_internal(r_sym, lv_in, lv_out, + relocatable, out_sections, + out_offsets, symtab); +} + // Finalize the local symbols. Here we set the final value in // THIS->LOCAL_VALUES_ and set their output symbol table indexes. // This function is always called from a singleton thread. The actual @@ -1897,141 +2069,31 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index, const bool relocatable = parameters->options().relocatable(); const Output_sections& out_sections(this->output_sections()); const std::vector<Address>& out_offsets(this->section_offsets_); - unsigned int shnum = this->shnum(); for (unsigned int i = 1; i < loccount; ++i) { - Symbol_value<size>& lv(this->local_values_[i]); - - bool is_ordinary; - unsigned int shndx = lv.input_shndx(&is_ordinary); + Symbol_value<size>* lv = &this->local_values_[i]; - // Set the output symbol value. - - if (!is_ordinary) + This::Compute_final_local_value_status cflv_status = + this->compute_final_local_value_internal(i, lv, lv, relocatable, + out_sections, out_offsets, + symtab); + switch (cflv_status) { - if (shndx == elfcpp::SHN_ABS || Symbol::is_common_shndx(shndx)) - lv.set_output_value(lv.input_value()); - else + case CFLV_OK: + if (!lv->is_output_symtab_index_set()) { - this->error(_("unknown section index %u for local symbol %u"), - shndx, i); - lv.set_output_value(0); + lv->set_output_symtab_index(index); + ++index; } + break; + case CFLV_DISCARDED: + case CFLV_ERROR: + // Do nothing. + break; + default: + gold_unreachable(); } - else - { - if (shndx >= shnum) - { - this->error(_("local symbol %u section index %u out of range"), - i, shndx); - shndx = 0; - } - - Output_section* os = out_sections[shndx]; - Address secoffset = out_offsets[shndx]; - if (symtab->is_section_folded(this, shndx)) - { - gold_assert(os == NULL && secoffset == invalid_address); - // Get the os of the section it is folded onto. - Section_id folded = symtab->icf()->get_folded_section(this, - shndx); - gold_assert(folded.first != NULL); - Sized_relobj<size, big_endian>* folded_obj = reinterpret_cast - <Sized_relobj<size, big_endian>*>(folded.first); - os = folded_obj->output_section(folded.second); - gold_assert(os != NULL); - secoffset = folded_obj->get_output_section_offset(folded.second); - - // This could be a relaxed input section. - if (secoffset == invalid_address) - { - const Output_relaxed_input_section* relaxed_section = - os->find_relaxed_input_section(folded_obj, folded.second); - gold_assert(relaxed_section != NULL); - secoffset = relaxed_section->address() - os->address(); - } - } - - if (os == NULL) - { - // This local symbol belongs to a section we are discarding. - // In some cases when applying relocations later, we will - // attempt to match it to the corresponding kept section, - // so we leave the input value unchanged here. - continue; - } - else if (secoffset == invalid_address) - { - uint64_t start; - - // This is a SHF_MERGE section or one which otherwise - // requires special handling. - if (shndx == this->discarded_eh_frame_shndx_) - { - // This local symbol belongs to a discarded .eh_frame - // section. Just treat it like the case in which - // os == NULL above. - gold_assert(this->has_eh_frame_); - continue; - } - else if (!lv.is_section_symbol()) - { - // This is not a section symbol. We can determine - // the final value now. - lv.set_output_value(os->output_address(this, shndx, - lv.input_value())); - } - else if (!os->find_starting_output_address(this, shndx, &start)) - { - // This is a section symbol, but apparently not one in a - // merged section. First check to see if this is a relaxed - // input section. If so, use its address. Otherwise just - // use the start of the output section. This happens with - // relocatable links when the input object has section - // symbols for arbitrary non-merge sections. - const Output_section_data* posd = - os->find_relaxed_input_section(this, shndx); - if (posd != NULL) - { - Address relocatable_link_adjustment = - relocatable ? os->address() : 0; - lv.set_output_value(posd->address() - - relocatable_link_adjustment); - } - else - lv.set_output_value(os->address()); - } - else - { - // We have to consider the addend to determine the - // value to use in a relocation. START is the start - // of this input section. If we are doing a relocatable - // link, use offset from start output section instead of - // address. - Address adjusted_start = - relocatable ? start - os->address() : start; - Merged_symbol_value<size>* msv = - new Merged_symbol_value<size>(lv.input_value(), - adjusted_start); - lv.set_merged_symbol_value(msv); - } - } - else if (lv.is_tls_symbol()) - lv.set_output_value(os->tls_offset() - + secoffset - + lv.input_value()); - else - lv.set_output_value((relocatable ? 0 : os->address()) - + secoffset - + lv.input_value()); - } - - if (!lv.is_output_symtab_index_set()) - { - lv.set_output_symtab_index(index); - ++index; - } } return index; } |