aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog39
-rw-r--r--gold/arm.cc122
-rw-r--r--gold/object.cc316
-rw-r--r--gold/object.h59
-rw-r--r--gold/testsuite/Makefile.am80
-rw-r--r--gold/testsuite/Makefile.in92
-rw-r--r--gold/testsuite/arm_bl_out_of_range.s3
-rwxr-xr-xgold/testsuite/arm_branch_out_of_range.sh123
-rwxr-xr-xgold/testsuite/arm_cortex_a8.sh65
-rw-r--r--gold/testsuite/arm_cortex_a8_b.s30
-rw-r--r--gold/testsuite/arm_cortex_a8_b_cond.s30
-rw-r--r--gold/testsuite/arm_cortex_a8_b_local.s52
-rw-r--r--gold/testsuite/arm_cortex_a8_bl.s30
-rw-r--r--gold/testsuite/arm_cortex_a8_blx.s33
-rw-r--r--gold/testsuite/arm_cortex_a8_local.s29
-rw-r--r--gold/testsuite/arm_cortex_a8_local_reloc.s31
-rw-r--r--gold/testsuite/thumb_bl_out_of_range.s6
-rw-r--r--gold/testsuite/thumb_bl_out_of_range_local.s61
-rw-r--r--gold/testsuite/thumb_blx_out_of_range.s5
19 files changed, 1040 insertions, 166 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 503a653..a8a1107 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,42 @@
+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.
+
2010-09-08 Rafael Espindola <espindola@google.com>
* script-sections.cc (Script_sections::add_memory_region): Convert
diff --git a/gold/arm.cc b/gold/arm.cc
index 85f9542..79a9663 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<false>(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<bool big_endian>
@@ -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<big_endian>::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<big_endian>::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<big_endian>::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<const Sized_symbol<32>*>(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<big_endian>::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 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;
}
diff --git a/gold/object.h b/gold/object.h
index 1f79e27..6eca6e9 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<bool big_endian>
@@ -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<Address>(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<size, big_endian>&);
@@ -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<size>* lv_in,
+ Symbol_value<size>* 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<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);
+
// The GOT offsets of local symbols. This map also stores GOT offsets
// for tp-relative offsets for TLS symbols.
typedef Unordered_map<unsigned int, Got_offset_list*> Local_got_offsets;
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index eab0557..c79c856 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 e40caa6..cc591ef 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 786d9aa..cb5ff53 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 0000000..b59b442
--- /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 <dougkwan@google.com>
+
+# 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 0000000..5e25c25
--- /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 <dougkwan@google.com>.
+
+# 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 0000000..d2316a0
--- /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 0000000..a244aa7
--- /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 0000000..2432d91
--- /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 0000000..c78fa8d
--- /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 0000000..c323d25
--- /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 0000000..462aa18
--- /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 0000000..2b49184
--- /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 6629d74..d0906d9 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 0000000..48de1e1
--- /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 fc5beb5..5689e27 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"