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.
This commit is contained in:
Doug Kwan 2010-09-08 23:54:51 +00:00
parent 5e1617b13f
commit aa98ff75dd
19 changed files with 1040 additions and 166 deletions

View File

@ -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

View File

@ -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

View File

@ -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]);
Symbol_value<size>* lv = &this->local_values_[i];
bool is_ordinary;
unsigned int shndx = lv.input_shndx(&is_ordinary);
// 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;
}

View File

@ -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;

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

65
gold/testsuite/arm_cortex_a8.sh Executable file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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"