From aa98ff75dd6197c120e5c962048a71d9c9626e08 Mon Sep 17 00:00:00 2001 From: Doug Kwan Date: Wed, 8 Sep 2010 23:54:51 +0000 Subject: [PATCH] 2010-09-08 Doug Kwan * 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. --- gold/ChangeLog | 39 +++ gold/arm.cc | 122 +++++-- gold/object.cc | 316 +++++++++++-------- gold/object.h | 59 ++++ gold/testsuite/Makefile.am | 80 ++++- gold/testsuite/Makefile.in | 92 +++++- gold/testsuite/arm_bl_out_of_range.s | 3 +- gold/testsuite/arm_branch_out_of_range.sh | 123 ++++++++ gold/testsuite/arm_cortex_a8.sh | 65 ++++ gold/testsuite/arm_cortex_a8_b.s | 30 ++ gold/testsuite/arm_cortex_a8_b_cond.s | 30 ++ gold/testsuite/arm_cortex_a8_b_local.s | 52 +++ gold/testsuite/arm_cortex_a8_bl.s | 30 ++ gold/testsuite/arm_cortex_a8_blx.s | 33 ++ gold/testsuite/arm_cortex_a8_local.s | 29 ++ gold/testsuite/arm_cortex_a8_local_reloc.s | 31 ++ gold/testsuite/thumb_bl_out_of_range.s | 6 + gold/testsuite/thumb_bl_out_of_range_local.s | 61 ++++ gold/testsuite/thumb_blx_out_of_range.s | 5 + 19 files changed, 1040 insertions(+), 166 deletions(-) create mode 100755 gold/testsuite/arm_branch_out_of_range.sh create mode 100755 gold/testsuite/arm_cortex_a8.sh create mode 100644 gold/testsuite/arm_cortex_a8_b.s create mode 100644 gold/testsuite/arm_cortex_a8_b_cond.s create mode 100644 gold/testsuite/arm_cortex_a8_b_local.s create mode 100644 gold/testsuite/arm_cortex_a8_bl.s create mode 100644 gold/testsuite/arm_cortex_a8_blx.s create mode 100644 gold/testsuite/arm_cortex_a8_local.s create mode 100644 gold/testsuite/arm_cortex_a8_local_reloc.s create mode 100644 gold/testsuite/thumb_bl_out_of_range_local.s diff --git a/gold/ChangeLog b/gold/ChangeLog index 503a653b90b..a8a11075e92 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,42 @@ +2010-09-08 Doug Kwan + + * 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. + 2010-09-08 Rafael Espindola * script-sections.cc (Script_sections::add_memory_region): Convert diff --git a/gold/arm.cc b/gold/arm.cc index 85f95429a4b..79a96633d48 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -1064,6 +1064,11 @@ class Arm_exidx_cantunwind : public Output_section_data this->do_fixed_endian_write(of); } + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** ARM cantunwind")); } + private: // Implement do_write for a given endianness. template @@ -1636,7 +1641,7 @@ class Arm_relobj : public Sized_relobj<32, big_endian> void do_relocate_sections(const Symbol_table* symtab, const Layout* layout, - const unsigned char* pshdrs, + const unsigned char* pshdrs, Output_file* of, typename Sized_relobj<32, big_endian>::Views* pivews); // Read the symbol information. @@ -6351,11 +6356,12 @@ Arm_relobj::do_relocate_sections( const Symbol_table* symtab, const Layout* layout, const unsigned char* pshdrs, + Output_file* of, typename Sized_relobj<32, big_endian>::Views* pviews) { // Call parent to relocate sections. Sized_relobj<32, big_endian>::do_relocate_sections(symtab, layout, pshdrs, - pviews); + of, pviews); // We do not generate stubs if doing a relocatable link. if (parameters->options().relocatable()) @@ -10944,6 +10950,8 @@ Target_arm::scan_reloc_section_for_stubs( Symbol_value<32> symval; const Symbol_value<32> *psymval; + bool is_defined_in_discarded_section; + unsigned int shndx; if (r_sym < local_count) { sym = NULL; @@ -10955,45 +10963,53 @@ Target_arm::scan_reloc_section_for_stubs( // counterpart in the kept section. The symbol must not // correspond to a section we are folding. bool is_ordinary; - unsigned int shndx = psymval->input_shndx(&is_ordinary); - if (is_ordinary - && shndx != elfcpp::SHN_UNDEF - && !arm_object->is_section_included(shndx) - && !(relinfo->symtab->is_section_folded(arm_object, shndx))) + shndx = psymval->input_shndx(&is_ordinary); + is_defined_in_discarded_section = + (is_ordinary + && shndx != elfcpp::SHN_UNDEF + && !arm_object->is_section_included(shndx) + && !relinfo->symtab->is_section_folded(arm_object, shndx)); + + // We need to compute the would-be final value of this local + // symbol. + if (!is_defined_in_discarded_section) { - if (comdat_behavior == CB_UNDETERMINED) - { - std::string name = - arm_object->section_name(relinfo->data_shndx); - comdat_behavior = get_comdat_behavior(name.c_str()); - } - if (comdat_behavior == CB_PRETEND) - { - bool found; - typename elfcpp::Elf_types<32>::Elf_Addr value = - arm_object->map_to_kept_section(shndx, &found); - if (found) - symval.set_output_value(value + psymval->input_value()); - else - symval.set_output_value(0); - } + typedef Sized_relobj<32, big_endian> ObjType; + typename ObjType::Compute_final_local_value_status status = + arm_object->compute_final_local_value(r_sym, psymval, &symval, + relinfo->symtab); + if (status == ObjType::CFLV_OK) + { + // Currently we cannot handle a branch to a target in + // a merged section. If this is the case, issue an error + // and also free the merge symbol value. + if (!symval.has_output_value()) + { + const std::string& section_name = + arm_object->section_name(shndx); + arm_object->error(_("cannot handle branch to local %u " + "in a merged section %s"), + r_sym, section_name.c_str()); + } + psymval = &symval; + } else - { - symval.set_output_value(0); - } - symval.set_no_output_symtab_entry(); - psymval = &symval; + { + // We cannot determine the final value. + continue; + } } } else { - const Symbol* gsym = arm_object->global_symbol(r_sym); + const Symbol* gsym; + gsym = arm_object->global_symbol(r_sym); gold_assert(gsym != NULL); if (gsym->is_forwarder()) gsym = relinfo->symtab->resolve_forwards(gsym); sym = static_cast*>(gsym); - if (sym->has_symtab_index()) + if (sym->has_symtab_index() && sym->symtab_index() != -1U) symval.set_output_symtab_index(sym->symtab_index()); else symval.set_no_output_symtab_entry(); @@ -11010,9 +11026,53 @@ Target_arm::scan_reloc_section_for_stubs( // Skip this if the symbol has not output section. if (status == Symbol_table::CFVS_NO_OUTPUT_SECTION) continue; - symval.set_output_value(value); + + if (gsym->type() == elfcpp::STT_TLS) + symval.set_is_tls_symbol(); + else if (gsym->type() == elfcpp::STT_GNU_IFUNC) + symval.set_is_ifunc_symbol(); psymval = &symval; + + is_defined_in_discarded_section = + (gsym->is_defined_in_discarded_section() + && gsym->is_undefined()); + shndx = 0; + } + + Symbol_value<32> symval2; + if (is_defined_in_discarded_section) + { + if (comdat_behavior == CB_UNDETERMINED) + { + std::string name = arm_object->section_name(relinfo->data_shndx); + comdat_behavior = get_comdat_behavior(name.c_str()); + } + if (comdat_behavior == CB_PRETEND) + { + // FIXME: This case does not work for global symbols. + // We have no place to store the original section index. + // Fortunately this does not matter for comdat sections, + // only for sections explicitly discarded by a linker + // script. + bool found; + typename elfcpp::Elf_types<32>::Elf_Addr value = + arm_object->map_to_kept_section(shndx, &found); + if (found) + symval2.set_output_value(value + psymval->input_value()); + else + symval2.set_output_value(0); + } + else + { + if (comdat_behavior == CB_WARNING) + gold_warning_at_location(relinfo, i, offset, + _("relocation refers to discarded " + "section")); + symval2.set_output_value(0); + } + symval2.set_no_output_symtab_entry(); + psymval = &symval2; } // If symbol is a section symbol, we don't know the actual type of diff --git a/gold/object.cc b/gold/object.cc index bdeb1414bd6..7bd35f3a587 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -1878,6 +1878,178 @@ Sized_relobj::do_count_local_symbols(Stringpool* pool, this->output_local_dynsym_count_ = dyncount; } +// Compute the final value of a local symbol. + +template +typename Sized_relobj::Compute_final_local_value_status +Sized_relobj::compute_final_local_value_internal( + unsigned int r_sym, + const Symbol_value* lv_in, + Symbol_value* lv_out, + bool relocatable, + const Output_sections& out_sections, + const std::vector
& 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* folded_obj = reinterpret_cast + *>(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* msv = + new Merged_symbol_value(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 +typename Sized_relobj::Compute_final_local_value_status +Sized_relobj::compute_final_local_value( + unsigned int r_sym, + const Symbol_value* lv_in, + Symbol_value* 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
& 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::do_finalize_local_symbols(unsigned int index, const bool relocatable = parameters->options().relocatable(); const Output_sections& out_sections(this->output_sections()); const std::vector
& out_offsets(this->section_offsets_); - unsigned int shnum = this->shnum(); for (unsigned int i = 1; i < loccount; ++i) { - Symbol_value& lv(this->local_values_[i]); - - bool is_ordinary; - unsigned int shndx = lv.input_shndx(&is_ordinary); + Symbol_value* 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* folded_obj = reinterpret_cast - *>(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* msv = - new Merged_symbol_value(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; } diff --git a/gold/object.h b/gold/object.h index 1f79e272322..6eca6e9d62c 100644 --- a/gold/object.h +++ b/gold/object.h @@ -1155,6 +1155,12 @@ class Symbol_value is_tls_symbol_(false), is_ifunc_symbol_(false), has_output_value_(true) { this->u_.value = 0; } + ~Symbol_value() + { + if (!this->has_output_value_) + delete this->u_.merged_symbol_value; + } + // Get the value of this symbol. OBJECT is the object in which this // symbol is defined, and ADDEND is an addend to add to the value. template @@ -1380,6 +1386,11 @@ class Symbol_value is_ifunc_symbol() const { return this->is_ifunc_symbol_; } + // Return true if this has output value. + bool + has_output_value() const + { return this->has_output_value_; } + private: // The index of this local symbol in the output symbol table. This // will be 0 if no value has been assigned yet, and the symbol may @@ -1558,6 +1569,16 @@ class Sized_relobj : public Relobj static const Address invalid_address = static_cast
(0) - 1; + enum Compute_final_local_value_status + { + // No error. + CFLV_OK, + // An error occurred. + CFLV_ERROR, + // The local symbol has no output section. + CFLV_DISCARDED + }; + Sized_relobj(const std::string& name, Input_file* input_file, off_t offset, const typename elfcpp::Ehdr&); @@ -1742,6 +1763,22 @@ class Sized_relobj : public Relobj Address map_to_kept_section(unsigned int shndx, bool* found) const; + // Compute final local symbol value. R_SYM is the local symbol index. + // LV_IN points to a local symbol value containing the input value. + // LV_OUT points to a local symbol value storing the final output value, + // which must not be a merged symbol value since before calling this + // method to avoid memory leak. SYMTAB points to a symbol table. + // + // The method returns a status code at return. If the return status is + // CFLV_OK, *LV_OUT contains the final value. If the return status is + // CFLV_ERROR, *LV_OUT is 0. If the return status is CFLV_DISCARDED, + // *LV_OUT is not modified. + Compute_final_local_value_status + compute_final_local_value(unsigned int r_sym, + const Symbol_value* lv_in, + Symbol_value* lv_out, + const Symbol_table* symtab); + protected: // Set up. virtual void @@ -2162,6 +2199,28 @@ class Sized_relobj : public Relobj return true; } + // Compute final local symbol value. R_SYM is the local symbol index. + // LV_IN points to a local symbol value containing the input value. + // LV_OUT points to a local symbol value storing the final output value, + // which must not be a merged symbol value since before calling this + // method to avoid memory leak. RELOCATABLE indicates whether we are + // linking a relocatable output. OUT_SECTIONS is an array of output + // sections. OUT_OFFSETS is an array of offsets of the sections. SYMTAB + // points to a symbol table. + // + // The method returns a status code at return. If the return status is + // CFLV_OK, *LV_OUT contains the final value. If the return status is + // CFLV_ERROR, *LV_OUT is 0. If the return status is CFLV_DISCARDED, + // *LV_OUT is not modified. + inline Compute_final_local_value_status + compute_final_local_value_internal(unsigned int r_sym, + const Symbol_value* lv_in, + Symbol_value* lv_out, + bool relocatable, + const Output_sections& out_sections, + const std::vector
& out_offsets, + const Symbol_table* symtab); + // The GOT offsets of local symbols. This map also stores GOT offsets // for tp-relative offsets for TLS symbols. typedef Unordered_map Local_got_offsets; diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index eab055755ea..c79c85640b6 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -1885,12 +1885,13 @@ arm_abs_global.stdout: arm_abs_global MOSTLYCLEANFILES += arm_abs_global -check_SCRIPTS += arm_branch_in_range.sh +check_SCRIPTS += arm_branch_in_range.sh arm_branch_out_of_range.sh check_DATA += arm_bl_in_range.stdout arm_bl_out_of_range.stdout \ thumb_bl_in_range.stdout thumb_bl_out_of_range.stdout \ thumb2_bl_in_range.stdout thumb2_bl_out_of_range.stdout \ thumb_blx_in_range.stdout thumb_blx_out_of_range.stdout \ - thumb2_blx_in_range.stdout thumb2_blx_out_of_range.stdout + thumb2_blx_in_range.stdout thumb2_blx_out_of_range.stdout \ + thumb_bl_out_of_range_local.stdout arm_bl_in_range.stdout: arm_bl_in_range $(TEST_OBJDUMP) -D $< > $@ @@ -1982,10 +1983,19 @@ thumb2_blx_out_of_range: thumb2_blx_out_of_range.o ../ld-new thumb2_blx_out_of_range.o: thumb_blx_out_of_range.s $(TEST_AS) -o $@ -march=armv7-a $< +thumb_bl_out_of_range_local.stdout: thumb_bl_out_of_range_local + $(TEST_OBJDUMP) -D $< > $@ + +thumb_bl_out_of_range_local: thumb_bl_out_of_range_local.o ../ld-new + ../ld-new -T $(srcdir)/thumb_branch_range.t -o $@ $< + +thumb_bl_out_of_range_local.o: thumb_bl_out_of_range_local.s + $(TEST_AS) -o $@ -march=armv5te $< + MOSTLYCLEANFILES += arm_bl_in_range arm_bl_out_of_range thumb_bl_in_range \ thumb_bl_out_of_range thumb2_bl_in_range thumb2_bl_out_of_range \ thumb_blx_in_range thumb_blx_out_of_range thumb2_blx_in_range \ - thumb2_blx_out_of_range + thumb2_blx_out_of_range thumb_bl_out_of_range_local check_SCRIPTS += arm_fix_v4bx.sh check_DATA += arm_fix_v4bx.stdout arm_fix_v4bx_interworking.stdout \ @@ -2050,4 +2060,68 @@ arm_attr_merge_7b.o: arm_attr_merge_7b.s MOSTLYCLEANFILES += arm_attr_merge_6 arm_attr_merge_6r arm_attr_merge_7 +# Cortex-A8 workaround test. + +check_SCRIPTS += arm_cortex_a8.sh +check_DATA += arm_cortex_a8_b_cond.stdout arm_cortex_a8_b.stdout \ + arm_cortex_a8_bl.stdout arm_cortex_a8_blx.stdout \ + arm_cortex_a8_local.stdout arm_cortex_a8_local_reloc.stdout + +arm_cortex_a8_b_cond.stdout: arm_cortex_a8_b_cond + $(TEST_OBJDUMP) -D -j.text $< > $@ + +arm_cortex_a8_b_cond: arm_cortex_a8_b_cond.o ../ld-new + ../ld-new -o $@ $< + +arm_cortex_a8_b_cond.o: arm_cortex_a8_b_cond.s + $(TEST_AS) -o $@ $< + +arm_cortex_a8_b.stdout: arm_cortex_a8_b + $(TEST_OBJDUMP) -D -j.text $< > $@ + +arm_cortex_a8_b: arm_cortex_a8_b.o ../ld-new + ../ld-new --fix-cortex-a8 -o $@ $< + +arm_cortex_a8_b.o: arm_cortex_a8_b.s + $(TEST_AS) -o $@ $< + +arm_cortex_a8_bl.stdout: arm_cortex_a8_bl + $(TEST_OBJDUMP) -D -j.text $< > $@ + +arm_cortex_a8_bl: arm_cortex_a8_bl.o ../ld-new + ../ld-new -o $@ $< + +arm_cortex_a8_bl.o: arm_cortex_a8_bl.s + $(TEST_AS) -o $@ $< + +arm_cortex_a8_blx.stdout: arm_cortex_a8_blx + $(TEST_OBJDUMP) -D -j.text $< > $@ + +arm_cortex_a8_blx: arm_cortex_a8_blx.o ../ld-new + ../ld-new -o $@ $< + +arm_cortex_a8_blx.o: arm_cortex_a8_blx.s + $(TEST_AS) -o $@ $< + +arm_cortex_a8_local.stdout: arm_cortex_a8_local + $(TEST_OBJDUMP) -D -j.text $< > $@ + +arm_cortex_a8_local: arm_cortex_a8_local.o ../ld-new + ../ld-new -o $@ $< + +arm_cortex_a8_local.o: arm_cortex_a8_local.s + $(TEST_AS) -o $@ $< + +arm_cortex_a8_local_reloc.stdout: arm_cortex_a8_local_reloc + $(TEST_OBJDUMP) -D -j.text $< > $@ + +arm_cortex_a8_local_reloc: arm_cortex_a8_local_reloc.o ../ld-new + ../ld-new -o $@ $< + +arm_cortex_a8_local_reloc.o: arm_cortex_a8_local_reloc.s + $(TEST_AS) -o $@ $< + +MOSTLYCLEANFILES += arm_cortex_a8_b_cond arm_cortex_a8_b arm_cortex_a8_bl \ + arm_cortex_a8_blx arm_cortex_a8_local arm_cortex_a8_local_reloc + endif DEFAULT_TARGET_ARM diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index e40caa66349..cc591ef3a0b 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -492,9 +492,13 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @DEFAULT_TARGET_X86_64_TRUE@am__append_39 = split_x86_64_1 split_x86_64_2 split_x86_64_3 \ @DEFAULT_TARGET_X86_64_TRUE@ split_x86_64_4 split_x86_64_r + +# Cortex-A8 workaround test. @DEFAULT_TARGET_ARM_TRUE@am__append_40 = arm_abs_global.sh \ @DEFAULT_TARGET_ARM_TRUE@ arm_branch_in_range.sh \ -@DEFAULT_TARGET_ARM_TRUE@ arm_fix_v4bx.sh arm_attr_merge.sh +@DEFAULT_TARGET_ARM_TRUE@ arm_branch_out_of_range.sh \ +@DEFAULT_TARGET_ARM_TRUE@ arm_fix_v4bx.sh arm_attr_merge.sh \ +@DEFAULT_TARGET_ARM_TRUE@ arm_cortex_a8.sh @DEFAULT_TARGET_ARM_TRUE@am__append_41 = arm_abs_global.stdout \ @DEFAULT_TARGET_ARM_TRUE@ arm_bl_in_range.stdout \ @DEFAULT_TARGET_ARM_TRUE@ arm_bl_out_of_range.stdout \ @@ -506,12 +510,19 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @DEFAULT_TARGET_ARM_TRUE@ thumb_blx_out_of_range.stdout \ @DEFAULT_TARGET_ARM_TRUE@ thumb2_blx_in_range.stdout \ @DEFAULT_TARGET_ARM_TRUE@ thumb2_blx_out_of_range.stdout \ +@DEFAULT_TARGET_ARM_TRUE@ thumb_bl_out_of_range_local.stdout \ @DEFAULT_TARGET_ARM_TRUE@ arm_fix_v4bx.stdout \ @DEFAULT_TARGET_ARM_TRUE@ arm_fix_v4bx_interworking.stdout \ @DEFAULT_TARGET_ARM_TRUE@ arm_no_fix_v4bx.stdout \ @DEFAULT_TARGET_ARM_TRUE@ arm_attr_merge_6.stdout \ @DEFAULT_TARGET_ARM_TRUE@ arm_attr_merge_6r.stdout \ -@DEFAULT_TARGET_ARM_TRUE@ arm_attr_merge_7.stdout +@DEFAULT_TARGET_ARM_TRUE@ arm_attr_merge_7.stdout \ +@DEFAULT_TARGET_ARM_TRUE@ arm_cortex_a8_b_cond.stdout \ +@DEFAULT_TARGET_ARM_TRUE@ arm_cortex_a8_b.stdout \ +@DEFAULT_TARGET_ARM_TRUE@ arm_cortex_a8_bl.stdout \ +@DEFAULT_TARGET_ARM_TRUE@ arm_cortex_a8_blx.stdout \ +@DEFAULT_TARGET_ARM_TRUE@ arm_cortex_a8_local.stdout \ +@DEFAULT_TARGET_ARM_TRUE@ arm_cortex_a8_local_reloc.stdout @DEFAULT_TARGET_ARM_TRUE@am__append_42 = arm_abs_global \ @DEFAULT_TARGET_ARM_TRUE@ arm_bl_in_range arm_bl_out_of_range \ @DEFAULT_TARGET_ARM_TRUE@ thumb_bl_in_range \ @@ -521,10 +532,16 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @DEFAULT_TARGET_ARM_TRUE@ thumb_blx_in_range \ @DEFAULT_TARGET_ARM_TRUE@ thumb_blx_out_of_range \ @DEFAULT_TARGET_ARM_TRUE@ thumb2_blx_in_range \ -@DEFAULT_TARGET_ARM_TRUE@ thumb2_blx_out_of_range arm_fix_v4bx \ +@DEFAULT_TARGET_ARM_TRUE@ thumb2_blx_out_of_range \ +@DEFAULT_TARGET_ARM_TRUE@ thumb_bl_out_of_range_local \ +@DEFAULT_TARGET_ARM_TRUE@ arm_fix_v4bx \ @DEFAULT_TARGET_ARM_TRUE@ arm_fix_v4bx_interworking \ @DEFAULT_TARGET_ARM_TRUE@ arm_no_fix_v4bx arm_attr_merge_6 \ -@DEFAULT_TARGET_ARM_TRUE@ arm_attr_merge_6r arm_attr_merge_7 +@DEFAULT_TARGET_ARM_TRUE@ arm_attr_merge_6r arm_attr_merge_7 \ +@DEFAULT_TARGET_ARM_TRUE@ arm_cortex_a8_b_cond arm_cortex_a8_b \ +@DEFAULT_TARGET_ARM_TRUE@ arm_cortex_a8_bl arm_cortex_a8_blx \ +@DEFAULT_TARGET_ARM_TRUE@ arm_cortex_a8_local \ +@DEFAULT_TARGET_ARM_TRUE@ arm_cortex_a8_local_reloc subdir = testsuite DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -3297,10 +3314,14 @@ arm_abs_global.sh.log: arm_abs_global.sh @p='arm_abs_global.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) arm_branch_in_range.sh.log: arm_branch_in_range.sh @p='arm_branch_in_range.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) +arm_branch_out_of_range.sh.log: arm_branch_out_of_range.sh + @p='arm_branch_out_of_range.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) arm_fix_v4bx.sh.log: arm_fix_v4bx.sh @p='arm_fix_v4bx.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) arm_attr_merge.sh.log: arm_attr_merge.sh @p='arm_attr_merge.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) +arm_cortex_a8.sh.log: arm_cortex_a8.sh + @p='arm_cortex_a8.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) object_unittest.log: object_unittest$(EXEEXT) @p='object_unittest$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) binary_unittest.log: binary_unittest$(EXEEXT) @@ -4641,6 +4662,15 @@ uninstall-am: @DEFAULT_TARGET_ARM_TRUE@thumb2_blx_out_of_range.o: thumb_blx_out_of_range.s @DEFAULT_TARGET_ARM_TRUE@ $(TEST_AS) -o $@ -march=armv7-a $< +@DEFAULT_TARGET_ARM_TRUE@thumb_bl_out_of_range_local.stdout: thumb_bl_out_of_range_local +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_OBJDUMP) -D $< > $@ + +@DEFAULT_TARGET_ARM_TRUE@thumb_bl_out_of_range_local: thumb_bl_out_of_range_local.o ../ld-new +@DEFAULT_TARGET_ARM_TRUE@ ../ld-new -T $(srcdir)/thumb_branch_range.t -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@thumb_bl_out_of_range_local.o: thumb_bl_out_of_range_local.s +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_AS) -o $@ -march=armv5te $< + @DEFAULT_TARGET_ARM_TRUE@arm_fix_v4bx.stdout: arm_fix_v4bx @DEFAULT_TARGET_ARM_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@ @@ -4692,6 +4722,60 @@ uninstall-am: @DEFAULT_TARGET_ARM_TRUE@arm_attr_merge_7b.o: arm_attr_merge_7b.s @DEFAULT_TARGET_ARM_TRUE@ $(TEST_AS) -o $@ $< +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b_cond.stdout: arm_cortex_a8_b_cond +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@ + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b_cond: arm_cortex_a8_b_cond.o ../ld-new +@DEFAULT_TARGET_ARM_TRUE@ ../ld-new -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b_cond.o: arm_cortex_a8_b_cond.s +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_AS) -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b.stdout: arm_cortex_a8_b +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@ + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b: arm_cortex_a8_b.o ../ld-new +@DEFAULT_TARGET_ARM_TRUE@ ../ld-new --fix-cortex-a8 -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_b.o: arm_cortex_a8_b.s +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_AS) -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_bl.stdout: arm_cortex_a8_bl +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@ + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_bl: arm_cortex_a8_bl.o ../ld-new +@DEFAULT_TARGET_ARM_TRUE@ ../ld-new -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_bl.o: arm_cortex_a8_bl.s +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_AS) -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_blx.stdout: arm_cortex_a8_blx +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@ + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_blx: arm_cortex_a8_blx.o ../ld-new +@DEFAULT_TARGET_ARM_TRUE@ ../ld-new -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_blx.o: arm_cortex_a8_blx.s +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_AS) -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local.stdout: arm_cortex_a8_local +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@ + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local: arm_cortex_a8_local.o ../ld-new +@DEFAULT_TARGET_ARM_TRUE@ ../ld-new -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local.o: arm_cortex_a8_local.s +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_AS) -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local_reloc.stdout: arm_cortex_a8_local_reloc +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_OBJDUMP) -D -j.text $< > $@ + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local_reloc: arm_cortex_a8_local_reloc.o ../ld-new +@DEFAULT_TARGET_ARM_TRUE@ ../ld-new -o $@ $< + +@DEFAULT_TARGET_ARM_TRUE@arm_cortex_a8_local_reloc.o: arm_cortex_a8_local_reloc.s +@DEFAULT_TARGET_ARM_TRUE@ $(TEST_AS) -o $@ $< + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/gold/testsuite/arm_bl_out_of_range.s b/gold/testsuite/arm_bl_out_of_range.s index 786d9aabf92..cb5ff53556b 100644 --- a/gold/testsuite/arm_bl_out_of_range.s +++ b/gold/testsuite/arm_bl_out_of_range.s @@ -15,7 +15,8 @@ _backward_target: .size _backward_target, .-_backward_target .text - .align 2 +# Use 256-byte alignment so that we know where the stubs start. + .align 8 # Define _start so that linker does not complain. .global _start diff --git a/gold/testsuite/arm_branch_out_of_range.sh b/gold/testsuite/arm_branch_out_of_range.sh new file mode 100755 index 00000000000..b59b442c8b0 --- /dev/null +++ b/gold/testsuite/arm_branch_out_of_range.sh @@ -0,0 +1,123 @@ +#!/bin/sh + +# arm_branch_out_of_range.sh -- test ARM/THUMB/THUMB branch instructions whose +# targets are just out of the branch range limits. + +# Copyright 2010 Free Software Foundation, Inc. +# Written by Doug Kwan + +# This file is part of gold. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. + +# This file goes with the assembler source files arm_bl_out_of_range.s, +# thumb_bl_out_of_range.s and thumb_bl_out_of_range_local.s that are assembled +# and linked to check that branches whose target are just out of the branch +# range limits are handle correctly. + +check() +{ + file=$1 + pattern=$2 + + found=`grep "$pattern" $file` + if test -z "$found"; then + echo "pattern \"$pattern\" not found in file $file." + exit 1 + fi +} + +# This is a bit crude. Also, there are tabs in the grep patterns. + +check arm_bl_out_of_range.stdout \ + " 4000004: eb00003d bl 4000100 <.*>" +check arm_bl_out_of_range.stdout \ + " 4000008: eb00003e bl 4000108 <.*>" +check arm_bl_out_of_range.stdout \ + " 4000100: e51ff004 ldr pc, \[pc, #-4\]" +check arm_bl_out_of_range.stdout \ + " 4000104: 02000008 " +check arm_bl_out_of_range.stdout \ + " 4000108: e51ff004 ldr pc, \[pc, #-4\]" +check arm_bl_out_of_range.stdout \ + " 400010c: 06000010 " + +check thumb_bl_out_of_range.stdout \ + " 800004: f000 e87c blx 800100 <.*>" +check thumb_bl_out_of_range.stdout \ + " 800008: f000 e87e blx 800108 <.*>" +check thumb_bl_out_of_range.stdout \ + " 800100: e51ff004 ldr pc, \[pc, #-4\]" +check thumb_bl_out_of_range.stdout \ + " 800104: 00400007 " +check thumb_bl_out_of_range.stdout \ + " 800108: e51ff004 ldr pc, \[pc, #-4\]" +check thumb_bl_out_of_range.stdout \ + " 80010c: 00c0000d " + +check thumb_blx_out_of_range.stdout \ + " 800004: f000 e87c blx 800100 <.*>" +check thumb_blx_out_of_range.stdout \ + " 80000a: f000 e87e blx 800108 <.*>" +check thumb_blx_out_of_range.stdout \ + " 800100: e51ff004 ldr pc, \[pc, #-4\]" +check thumb_blx_out_of_range.stdout \ + " 800104: 00400006 " +check thumb_blx_out_of_range.stdout \ + " 800108: e51ff004 ldr pc, \[pc, #-4\]" +check thumb_blx_out_of_range.stdout \ + " 80010c: 00c0000c " + +check thumb_bl_out_of_range_local.stdout \ + " 800004: f000 e87c blx 800100 <.*>" +check thumb_bl_out_of_range_local.stdout \ + " 800008: f000 e87e blx 800108 <.*>" +check thumb_bl_out_of_range_local.stdout \ + " 800100: e51ff004 ldr pc, \[pc, #-4\]" +check thumb_bl_out_of_range_local.stdout \ + " 800104: 00400007 " +check thumb_bl_out_of_range_local.stdout \ + " 800108: e51ff004 ldr pc, \[pc, #-4\]" +check thumb_bl_out_of_range_local.stdout \ + " 80010c: 00c0000d " + +check thumb2_bl_out_of_range.stdout \ + " 2000004: f000 e87c blx 2000100 <.*>" +check thumb2_bl_out_of_range.stdout \ + " 2000008: f000 e87e blx 2000108 <.*>" +check thumb2_bl_out_of_range.stdout \ + " 2000100: e51ff004 ldr pc, \[pc, #-4\]" +check thumb2_bl_out_of_range.stdout \ + " 2000104: 01000007 " +check thumb2_bl_out_of_range.stdout \ + " 2000108: e51ff004 ldr pc, \[pc, #-4\]" +check thumb2_bl_out_of_range.stdout \ + " 200010c: 0300000d " + +check thumb2_blx_out_of_range.stdout \ + " 2000004: f000 e87c blx 2000100 <.*>" +check thumb2_blx_out_of_range.stdout \ + " 200000a: f000 e87e blx 2000108 <.*>" +check thumb2_blx_out_of_range.stdout \ + " 2000100: e51ff004 ldr pc, \[pc, #-4\]" +check thumb2_blx_out_of_range.stdout \ + " 2000104: 01000006 " +check thumb2_blx_out_of_range.stdout \ + " 2000108: e51ff004 ldr pc, \[pc, #-4\]" +check thumb2_blx_out_of_range.stdout \ + " 200010c: 0300000c " + +exit 0 diff --git a/gold/testsuite/arm_cortex_a8.sh b/gold/testsuite/arm_cortex_a8.sh new file mode 100755 index 00000000000..5e25c251012 --- /dev/null +++ b/gold/testsuite/arm_cortex_a8.sh @@ -0,0 +1,65 @@ +#!/bin/sh + +# arm_cortex_a8.sh -- a test case for the Cortex-A8 workaround. + +# Copyright 2010 Free Software Foundation, Inc. +# Written by Doug Kwan . + +# This file is part of gold. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. + +# This file goes with arm_v4bx.s, an ARM assembly source file constructed to +# have test the handling of R_ARM_V4BX relocation. + +check() +{ + if ! grep -q "$2" "$1" + then + echo "Did not find expected instruction in $1:" + echo " $2" + echo "" + echo "Actual instructions below:" + cat "$1" + exit 1 + fi +} + +# Test branch. +check arm_cortex_a8_b.stdout ".*ffe: .* b.w .*000 <.*>" +check arm_cortex_a8_b.stdout ".000: .* b.w .*100 <_func>" + +# Test conditional branch. +check arm_cortex_a8_b_cond.stdout ".*ffe: .* b.w .*000 <.*>" +check arm_cortex_a8_b_cond.stdout ".000: .* beq.n .*006 <.*>" +check arm_cortex_a8_b_cond.stdout ".002: .* b.w .*002 <.*>" +check arm_cortex_a8_b_cond.stdout ".006: .* b.w .*100 <_func>" + +# Test branch and link. +check arm_cortex_a8_bl.stdout ".*ffe: .* bl .*000 <.*>" +check arm_cortex_a8_bl.stdout ".000: .* b.w .*100 <_func>" + +# Test blx +check arm_cortex_a8_blx.stdout ".*ffe: .* blx .*000 <.*>" +check arm_cortex_a8_blx.stdout ".000: .* b .*100 <_func>" + +# Test a local branch without relocation. +check arm_cortex_a8_local.stdout ".*ffe: .* b.w .*000 <.*>" +check arm_cortex_a8_local.stdout ".000: .* bpl.n .*006 <.*>" +check arm_cortex_a8_local.stdout ".002: .* b.w .*002 <.*>" +check arm_cortex_a8_local.stdout ".006: .* b.w .*100 <.*>" + +exit 0 diff --git a/gold/testsuite/arm_cortex_a8_b.s b/gold/testsuite/arm_cortex_a8_b.s new file mode 100644 index 00000000000..d2316a073e5 --- /dev/null +++ b/gold/testsuite/arm_cortex_a8_b.s @@ -0,0 +1,30 @@ + .syntax unified + .cpu cortex-a8 + + .text + .align 12 + +_start: + .type _start,%function + bx lr + .size _start,.-_start + + .align 8 + .thumb + .global _func + .type _func,%function +_func: + bx lr + .size _func,.-_func + + .align 11 + .space 2042 + + .align 1 + .thumb + .global _test + .type _test,%function +_test: + add.w r0, r0, 0 + b.w _func + .size _test,.-_test diff --git a/gold/testsuite/arm_cortex_a8_b_cond.s b/gold/testsuite/arm_cortex_a8_b_cond.s new file mode 100644 index 00000000000..a244aa70300 --- /dev/null +++ b/gold/testsuite/arm_cortex_a8_b_cond.s @@ -0,0 +1,30 @@ + .syntax unified + .cpu cortex-a8 + + .text + .align 12 + +_start: + .type _start,%function + bx lr + .size _start,.-_start + + .align 8 + .thumb + .global _func + .type _func,%function +_func: + bx lr + .size _func,.-_func + + .align 11 + .space 2042 + + .align 1 + .thumb + .global _test + .type _test,%function +_test: + add.w r0, r0, 0 + beq.w _func + .size _test,.-_test diff --git a/gold/testsuite/arm_cortex_a8_b_local.s b/gold/testsuite/arm_cortex_a8_b_local.s new file mode 100644 index 00000000000..2432d91cf0a --- /dev/null +++ b/gold/testsuite/arm_cortex_a8_b_local.s @@ -0,0 +1,52 @@ + .syntax unified + .cpu cortex-a8 + + .section .text.0, "x" + .align 12 + +_start: + .type _start,%function + bx lr + .size _start,.-_start + + .section .text.1, "x" + .align 11 + .thumb + .type .Lfunc1,%function +.Lfunc1: + bx lr + .size .Lfunc1,.-.Lfunc1 + + .section .text.2, "x" + .align 11 + .space 2042 + + .align 1 + .thumb + .global _test1 + .type _test1,%function +_test1: + add.w r0, r0, 0 + b.w .Lfunc1 + .size _test1,.-_test1 + + .align 8 + .thumb + .type .Lfunc2,%function +.Lfunc2: + bx lr + .size .Lfunc2,.-.Lfunc1 + + .align 11 + .space 2042 + + .align 1 + .thumb + .global _test2 + .type _test2,%function +_test2: + add.w r0, r0, 0 + b.w .Lfunc2 + .size _test2,.-_test2 + + diff --git a/gold/testsuite/arm_cortex_a8_bl.s b/gold/testsuite/arm_cortex_a8_bl.s new file mode 100644 index 00000000000..c78fa8d8481 --- /dev/null +++ b/gold/testsuite/arm_cortex_a8_bl.s @@ -0,0 +1,30 @@ + .syntax unified + .cpu cortex-a8 + + .text + .align 12 + +_start: + .type _start,%function + bx lr + .size _start,.-_start + + .align 8 + .thumb + .global _func + .type _func,%function +_func: + bx lr + .size _func,.-_func + + .align 11 + .space 2042 + + .align 1 + .thumb + .global _test + .type _test,%function +_test: + add.w r0, r0, 0 + bl _func + .size _test,.-_test diff --git a/gold/testsuite/arm_cortex_a8_blx.s b/gold/testsuite/arm_cortex_a8_blx.s new file mode 100644 index 00000000000..c323d25095e --- /dev/null +++ b/gold/testsuite/arm_cortex_a8_blx.s @@ -0,0 +1,33 @@ + .syntax unified + .cpu cortex-a8 + + .text + .align 12 + +_start: + .type _start,%function + bx lr + .size _start,.-_start + + .align 8 + .global _func + .type _func,%function +_func: + bx lr + .size _func,.-_func + + .align 11 + .space 2042 + + .align 1 + .thumb + .global _test + .type _test,%function +_test: + add.w r0, r0, 0 + blx _func + .size _test,.-_test + +# We have no mapping symbols for stubs. This make the disassembler +# list the stub correctly in ARM mode. + .arm diff --git a/gold/testsuite/arm_cortex_a8_local.s b/gold/testsuite/arm_cortex_a8_local.s new file mode 100644 index 00000000000..462aa18265b --- /dev/null +++ b/gold/testsuite/arm_cortex_a8_local.s @@ -0,0 +1,29 @@ + .syntax unified + .cpu cortex-a8 + + .text + .align 12 + +_start: + .type _start,%function + bx lr + .size _start,.-_start + + .align 8 + .thumb + .type .Lfunc,%function +.Lfunc: + bx lr + .size .Lfunc,.-.Lfunc + + .align 11 + .space 2042 + + .align 1 + .thumb + .global _test + .type _test,%function +_test: + add.w r0, r0, 0 + bpl.w .Lfunc + .size _test,.-_test diff --git a/gold/testsuite/arm_cortex_a8_local_reloc.s b/gold/testsuite/arm_cortex_a8_local_reloc.s new file mode 100644 index 00000000000..2b49184c778 --- /dev/null +++ b/gold/testsuite/arm_cortex_a8_local_reloc.s @@ -0,0 +1,31 @@ + .syntax unified + .cpu cortex-a8 + + .section .text.0, "x" + .align 12 + +_start: + .type _start,%function + bx lr + .size _start,.-_start + + .section .text.1, "x" + .align 11 + .thumb + .type .Lfunc,%function +.Lfunc: + bx lr + .size .Lfunc,.-.Lfunc + + .section .text.2, "x" + .align 11 + .space 2042 + + .align 1 + .thumb + .global _test + .type _test,%function +_test: + add.w r0, r0, 0 + b.w .Lfunc + .size _test,.-_test diff --git a/gold/testsuite/thumb_bl_out_of_range.s b/gold/testsuite/thumb_bl_out_of_range.s index 6629d74af0a..d0906d9d5ce 100644 --- a/gold/testsuite/thumb_bl_out_of_range.s +++ b/gold/testsuite/thumb_bl_out_of_range.s @@ -16,6 +16,8 @@ _backward_target: .size _backward_target, .-_backward_target .text +# Use 256-byte alignment so that we know where the stubs start. + .align 8 # Define _start so that linker does not complain. .global _start @@ -42,6 +44,10 @@ _forward_test: bl _forward_target .size _forward_test, .-_forward_test +# switch back to ARM mode so that stubs are disassembled correctly. + .code 32 + nop + .section .text.post,"x" # Add padding so that target is just out of branch range. diff --git a/gold/testsuite/thumb_bl_out_of_range_local.s b/gold/testsuite/thumb_bl_out_of_range_local.s new file mode 100644 index 00000000000..48de1e14206 --- /dev/null +++ b/gold/testsuite/thumb_bl_out_of_range_local.s @@ -0,0 +1,61 @@ +# thumb_bl_out_of_range_local.s +# Test THUMB/THUMB-2 bl instructions just out of the branch range limits +# and with local branch targets. + .syntax unified + + .section .text.pre,"x" + +# Add padding so that target is just output of branch range. + .space 6 + + .code 16 + .thumb_func + .type .Lbackward_target, %function +.Lbackward_target: + bx lr + .size .Lbackward_target, .-.Lbackward_target + + .text +# Use 256-byte alignment so that we know where the stubs start. + .align 8 + +# Define _start so that linker does not complain. + .global _start + .code 32 + .align 2 + .type _start, %function +_start: + bx lr + .size _start, .-_start + + .global _backward_test + .code 16 + .thumb_func + .type _backward_test, %function +_backward_test: + bl .Lbackward_target + .size _backward_test, .-_backward_test + + .global _forward_test + .code 16 + .thumb_func + .type _forward_test, %function +_forward_test: + bl .Lforward_target + .size _forward_test, .-_forward_test + +# Switch back to ARM mode so that we can see stubs + .code 32 + nop + + .section .text.post,"x" + +# Add padding so that target is just out of branch range. + .space 12 + + .code 16 + .thumb_func + .type .Lforward_target, %function +.Lforward_target: + bx lr + .size .Lforward_target, .-.Lforward_target diff --git a/gold/testsuite/thumb_blx_out_of_range.s b/gold/testsuite/thumb_blx_out_of_range.s index fc5beb58d1e..5689e272c90 100644 --- a/gold/testsuite/thumb_blx_out_of_range.s +++ b/gold/testsuite/thumb_blx_out_of_range.s @@ -15,6 +15,8 @@ _backward_target: .size _backward_target, .-_backward_target .text +# Use 256-byte alignment so that we know where the stubs start. + .align 8 # Define _start so that linker does not complain. .align 2 @@ -46,7 +48,10 @@ _forward_test: nop.n bl _forward_target .size _forward_test, .-_forward_test + +# switch back to ARM mode so that stubs are disassembled correctly. .code 32 + nop .section .text.post,"x" -- 2.30.2