Line 1... |
Line 1... |
// arm.cc -- arm target support for gold.
|
// arm.cc -- arm target support for gold.
|
|
|
// Copyright 2009, 2010 Free Software Foundation, Inc.
|
// Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
|
// Written by Doug Kwan <dougkwan@google.com> based on the i386 code
|
// Written by Doug Kwan <dougkwan@google.com> based on the i386 code
|
// by Ian Lance Taylor <iant@google.com>.
|
// by Ian Lance Taylor <iant@google.com>.
|
// This file also contains borrowed and adapted code from
|
// This file also contains borrowed and adapted code from
|
// bfd/elf32-arm.c.
|
// bfd/elf32-arm.c.
|
|
|
Line 2180... |
Line 2180... |
may_use_blx_(false), should_force_pic_veneer_(false),
|
may_use_blx_(false), should_force_pic_veneer_(false),
|
arm_input_section_map_(), attributes_section_data_(NULL),
|
arm_input_section_map_(), attributes_section_data_(NULL),
|
fix_cortex_a8_(false), cortex_a8_relocs_info_()
|
fix_cortex_a8_(false), cortex_a8_relocs_info_()
|
{ }
|
{ }
|
|
|
// Virtual function which is set to return true by a target if
|
|
// it can use relocation types to determine if a function's
|
|
// pointer is taken.
|
|
virtual bool
|
|
can_check_for_function_pointers() const
|
|
{ return true; }
|
|
|
|
// Whether a section called SECTION_NAME may have function pointers to
|
|
// sections not eligible for safe ICF folding.
|
|
virtual bool
|
|
section_may_have_icf_unsafe_pointers(const char* section_name) const
|
|
{
|
|
return (!is_prefix_of(".ARM.exidx", section_name)
|
|
&& !is_prefix_of(".ARM.extab", section_name)
|
|
&& Target::section_may_have_icf_unsafe_pointers(section_name));
|
|
}
|
|
|
|
// Whether we can use BLX.
|
// Whether we can use BLX.
|
bool
|
bool
|
may_use_blx() const
|
may_use_blx() const
|
{ return this->may_use_blx_; }
|
{ return this->may_use_blx_; }
|
|
|
Line 2551... |
Line 2534... |
// as the default.
|
// as the default.
|
gold_assert(arm_reloc_property_table == NULL);
|
gold_assert(arm_reloc_property_table == NULL);
|
arm_reloc_property_table = new Arm_reloc_property_table();
|
arm_reloc_property_table = new Arm_reloc_property_table();
|
}
|
}
|
|
|
|
// Virtual function which is set to return true by a target if
|
|
// it can use relocation types to determine if a function's
|
|
// pointer is taken.
|
|
virtual bool
|
|
do_can_check_for_function_pointers() const
|
|
{ return true; }
|
|
|
|
// Whether a section called SECTION_NAME may have function pointers to
|
|
// sections not eligible for safe ICF folding.
|
|
virtual bool
|
|
do_section_may_have_icf_unsafe_pointers(const char* section_name) const
|
|
{
|
|
return (!is_prefix_of(".ARM.exidx", section_name)
|
|
&& !is_prefix_of(".ARM.extab", section_name)
|
|
&& Target::do_section_may_have_icf_unsafe_pointers(section_name));
|
|
}
|
|
|
private:
|
private:
|
// The class which scans relocations.
|
// The class which scans relocations.
|
class Scan
|
class Scan
|
{
|
{
|
public:
|
public:
|
Line 2944... |
Line 2944... |
elfcpp::EM_ARM, // machine_code
|
elfcpp::EM_ARM, // machine_code
|
false, // has_make_symbol
|
false, // has_make_symbol
|
false, // has_resolve
|
false, // has_resolve
|
false, // has_code_fill
|
false, // has_code_fill
|
true, // is_default_stack_executable
|
true, // is_default_stack_executable
|
|
false, // can_icf_inline_merge_sections
|
'\0', // wrap_char
|
'\0', // wrap_char
|
"/usr/lib/libc.so.1", // dynamic_linker
|
"/usr/lib/libc.so.1", // dynamic_linker
|
0x8000, // default_text_segment_address
|
0x8000, // default_text_segment_address
|
0x1000, // abi_pagesize (overridable by -z max-page-size)
|
0x1000, // abi_pagesize (overridable by -z max-page-size)
|
0x1000, // common_pagesize (overridable by -z common-page-size)
|
0x1000, // common_pagesize (overridable by -z common-page-size)
|
Line 3212... |
Line 3213... |
abs8(unsigned char* view,
|
abs8(unsigned char* view,
|
const Sized_relobj_file<32, big_endian>* object,
|
const Sized_relobj_file<32, big_endian>* object,
|
const Symbol_value<32>* psymval)
|
const Symbol_value<32>* psymval)
|
{
|
{
|
typedef typename elfcpp::Swap<8, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap<8, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
|
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
Valtype val = elfcpp::Swap<8, big_endian>::readval(wv);
|
Valtype val = elfcpp::Swap<8, big_endian>::readval(wv);
|
Reltype addend = utils::sign_extend<8>(val);
|
int32_t addend = utils::sign_extend<8>(val);
|
Reltype x = psymval->value(object, addend);
|
Arm_address x = psymval->value(object, addend);
|
val = utils::bit_select(val, x, 0xffU);
|
val = utils::bit_select(val, x, 0xffU);
|
elfcpp::Swap<8, big_endian>::writeval(wv, val);
|
elfcpp::Swap<8, big_endian>::writeval(wv, val);
|
|
|
// R_ARM_ABS8 permits signed or unsigned results.
|
// R_ARM_ABS8 permits signed or unsigned results.
|
int signed_x = static_cast<int32_t>(x);
|
int signed_x = static_cast<int32_t>(x);
|
Line 3274... |
Line 3274... |
static inline typename This::Status
|
static inline typename This::Status
|
abs16(unsigned char* view,
|
abs16(unsigned char* view,
|
const Sized_relobj_file<32, big_endian>* object,
|
const Sized_relobj_file<32, big_endian>* object,
|
const Symbol_value<32>* psymval)
|
const Symbol_value<32>* psymval)
|
{
|
{
|
typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap_unaligned<16, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
|
typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
Valtype val = elfcpp::Swap_unaligned<16, big_endian>::readval(view);
|
Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
|
int32_t addend = utils::sign_extend<16>(val);
|
Reltype addend = utils::sign_extend<16>(val);
|
Arm_address x = psymval->value(object, addend);
|
Reltype x = psymval->value(object, addend);
|
|
val = utils::bit_select(val, x, 0xffffU);
|
val = utils::bit_select(val, x, 0xffffU);
|
elfcpp::Swap<16, big_endian>::writeval(wv, val);
|
elfcpp::Swap_unaligned<16, big_endian>::writeval(view, val);
|
return (utils::has_signed_unsigned_overflow<16>(x)
|
|
|
// R_ARM_ABS16 permits signed or unsigned results.
|
|
int signed_x = static_cast<int32_t>(x);
|
|
return ((signed_x < -32768 || signed_x > 65536)
|
? This::STATUS_OVERFLOW
|
? This::STATUS_OVERFLOW
|
: This::STATUS_OKAY);
|
: This::STATUS_OKAY);
|
}
|
}
|
|
|
// R_ARM_ABS32: (S + A) | T
|
// R_ARM_ABS32: (S + A) | T
|
Line 3294... |
Line 3296... |
abs32(unsigned char* view,
|
abs32(unsigned char* view,
|
const Sized_relobj_file<32, big_endian>* object,
|
const Sized_relobj_file<32, big_endian>* object,
|
const Symbol_value<32>* psymval,
|
const Symbol_value<32>* psymval,
|
Arm_address thumb_bit)
|
Arm_address thumb_bit)
|
{
|
{
|
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype;
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
Valtype addend = elfcpp::Swap_unaligned<32, big_endian>::readval(view);
|
Valtype addend = elfcpp::Swap<32, big_endian>::readval(wv);
|
|
Valtype x = psymval->value(object, addend) | thumb_bit;
|
Valtype x = psymval->value(object, addend) | thumb_bit;
|
elfcpp::Swap<32, big_endian>::writeval(wv, x);
|
elfcpp::Swap_unaligned<32, big_endian>::writeval(view, x);
|
return This::STATUS_OKAY;
|
return This::STATUS_OKAY;
|
}
|
}
|
|
|
// R_ARM_REL32: (S + A) | T - P
|
// R_ARM_REL32: (S + A) | T - P
|
static inline typename This::Status
|
static inline typename This::Status
|
Line 3310... |
Line 3311... |
const Sized_relobj_file<32, big_endian>* object,
|
const Sized_relobj_file<32, big_endian>* object,
|
const Symbol_value<32>* psymval,
|
const Symbol_value<32>* psymval,
|
Arm_address address,
|
Arm_address address,
|
Arm_address thumb_bit)
|
Arm_address thumb_bit)
|
{
|
{
|
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype;
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
Valtype addend = elfcpp::Swap_unaligned<32, big_endian>::readval(view);
|
Valtype addend = elfcpp::Swap<32, big_endian>::readval(wv);
|
|
Valtype x = (psymval->value(object, addend) | thumb_bit) - address;
|
Valtype x = (psymval->value(object, addend) | thumb_bit) - address;
|
elfcpp::Swap<32, big_endian>::writeval(wv, x);
|
elfcpp::Swap_unaligned<32, big_endian>::writeval(view, x);
|
return This::STATUS_OKAY;
|
return This::STATUS_OKAY;
|
}
|
}
|
|
|
// R_ARM_THM_JUMP24: (S + A) | T - P
|
// R_ARM_THM_JUMP24: (S + A) | T - P
|
static typename This::Status
|
static typename This::Status
|
Line 3354... |
Line 3354... |
const Sized_relobj_file<32, big_endian>* object,
|
const Sized_relobj_file<32, big_endian>* object,
|
const Symbol_value<32>* psymval,
|
const Symbol_value<32>* psymval,
|
Arm_address address)
|
Arm_address address)
|
{
|
{
|
typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap<16, big_endian>::Valtype Reltype;
|
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
|
Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
|
Reltype addend = utils::sign_extend<8>((val & 0x00ff) << 1);
|
int32_t addend = utils::sign_extend<8>((val & 0x00ff) << 1);
|
Reltype x = (psymval->value(object, addend) - address);
|
int32_t x = (psymval->value(object, addend) - address);
|
elfcpp::Swap<16, big_endian>::writeval(wv, (val & 0xff00) | ((x & 0x01fe) >> 1));
|
elfcpp::Swap<16, big_endian>::writeval(wv, ((val & 0xff00)
|
return (utils::has_overflow<8>(x)
|
| ((x & 0x01fe) >> 1)));
|
|
// We do a 9-bit overflow check because x is right-shifted by 1 bit.
|
|
return (utils::has_overflow<9>(x)
|
? This::STATUS_OVERFLOW
|
? This::STATUS_OVERFLOW
|
: This::STATUS_OKAY);
|
: This::STATUS_OKAY);
|
}
|
}
|
|
|
// R_ARM_THM_JUMP11: S + A – P
|
// R_ARM_THM_JUMP11: S + A – P
|
Line 3373... |
Line 3374... |
const Sized_relobj_file<32, big_endian>* object,
|
const Sized_relobj_file<32, big_endian>* object,
|
const Symbol_value<32>* psymval,
|
const Symbol_value<32>* psymval,
|
Arm_address address)
|
Arm_address address)
|
{
|
{
|
typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap<16, big_endian>::Valtype Reltype;
|
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
|
Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
|
Reltype addend = utils::sign_extend<11>((val & 0x07ff) << 1);
|
int32_t addend = utils::sign_extend<11>((val & 0x07ff) << 1);
|
Reltype x = (psymval->value(object, addend) - address);
|
int32_t x = (psymval->value(object, addend) - address);
|
elfcpp::Swap<16, big_endian>::writeval(wv, (val & 0xf800) | ((x & 0x0ffe) >> 1));
|
elfcpp::Swap<16, big_endian>::writeval(wv, ((val & 0xf800)
|
return (utils::has_overflow<11>(x)
|
| ((x & 0x0ffe) >> 1)));
|
|
// We do a 12-bit overflow check because x is right-shifted by 1 bit.
|
|
return (utils::has_overflow<12>(x)
|
? This::STATUS_OVERFLOW
|
? This::STATUS_OVERFLOW
|
: This::STATUS_OKAY);
|
: This::STATUS_OKAY);
|
}
|
}
|
|
|
// R_ARM_BASE_PREL: B(S) + A - P
|
// R_ARM_BASE_PREL: B(S) + A - P
|
Line 3430... |
Line 3432... |
const Sized_relobj_file<32, big_endian>* object,
|
const Sized_relobj_file<32, big_endian>* object,
|
const Symbol_value<32>* psymval,
|
const Symbol_value<32>* psymval,
|
Arm_address address,
|
Arm_address address,
|
Arm_address thumb_bit)
|
Arm_address thumb_bit)
|
{
|
{
|
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype;
|
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
Valtype val = elfcpp::Swap_unaligned<32, big_endian>::readval(view);
|
Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
|
|
Valtype addend = utils::sign_extend<31>(val);
|
Valtype addend = utils::sign_extend<31>(val);
|
Valtype x = (psymval->value(object, addend) | thumb_bit) - address;
|
Valtype x = (psymval->value(object, addend) | thumb_bit) - address;
|
val = utils::bit_select(val, x, 0x7fffffffU);
|
val = utils::bit_select(val, x, 0x7fffffffU);
|
elfcpp::Swap<32, big_endian>::writeval(wv, val);
|
elfcpp::Swap_unaligned<32, big_endian>::writeval(view, val);
|
return (utils::has_overflow<31>(x) ?
|
return (utils::has_overflow<31>(x) ?
|
This::STATUS_OVERFLOW : This::STATUS_OKAY);
|
This::STATUS_OVERFLOW : This::STATUS_OKAY);
|
}
|
}
|
|
|
// R_ARM_MOVW_ABS_NC: (S + A) | T (relative address base is )
|
// R_ARM_MOVW_ABS_NC: (S + A) | T (relative address base is )
|
Line 5216... |
Line 5217... |
{
|
{
|
off_t offset = this->offset();
|
off_t offset = this->offset();
|
const section_size_type oview_size = 8;
|
const section_size_type oview_size = 8;
|
unsigned char* const oview = of->get_output_view(offset, oview_size);
|
unsigned char* const oview = of->get_output_view(offset, oview_size);
|
|
|
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
|
typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype;
|
Valtype* wv = reinterpret_cast<Valtype*>(oview);
|
|
|
|
Output_section* os = this->relobj_->output_section(this->shndx_);
|
Output_section* os = this->relobj_->output_section(this->shndx_);
|
gold_assert(os != NULL);
|
gold_assert(os != NULL);
|
|
|
Arm_relobj<big_endian>* arm_relobj =
|
Arm_relobj<big_endian>* arm_relobj =
|
Line 5258... |
Line 5258... |
// or after the end of a text section. The second word is the special
|
// or after the end of a text section. The second word is the special
|
// EXIDX_CANTUNWIND value.
|
// EXIDX_CANTUNWIND value.
|
uint32_t prel31_offset = output_address - this->address();
|
uint32_t prel31_offset = output_address - this->address();
|
if (utils::has_overflow<31>(offset))
|
if (utils::has_overflow<31>(offset))
|
gold_error(_("PREL31 overflow in EXIDX_CANTUNWIND entry"));
|
gold_error(_("PREL31 overflow in EXIDX_CANTUNWIND entry"));
|
elfcpp::Swap<32, big_endian>::writeval(wv, prel31_offset & 0x7fffffffU);
|
elfcpp::Swap_unaligned<32, big_endian>::writeval(oview,
|
elfcpp::Swap<32, big_endian>::writeval(wv + 1, elfcpp::EXIDX_CANTUNWIND);
|
prel31_offset & 0x7fffffffU);
|
|
elfcpp::Swap_unaligned<32, big_endian>::writeval(oview + 4,
|
|
elfcpp::EXIDX_CANTUNWIND);
|
|
|
of->write_output_view(this->offset(), oview_size, oview);
|
of->write_output_view(this->offset(), oview_size, oview);
|
}
|
}
|
|
|
// Arm_exidx_merged_section methods.
|
// Arm_exidx_merged_section methods.
|
Line 5801... |
Line 5803... |
p != this->input_sections().end();
|
p != this->input_sections().end();
|
++p)
|
++p)
|
{
|
{
|
// We only care about plain or relaxed input sections. We also
|
// We only care about plain or relaxed input sections. We also
|
// ignore any merged sections.
|
// ignore any merged sections.
|
if ((p->is_input_section() || p->is_relaxed_input_section())
|
if (p->is_input_section() || p->is_relaxed_input_section())
|
&& p->data_size() != 0)
|
|
list->push_back(Text_section_list::value_type(p->relobj(),
|
list->push_back(Text_section_list::value_type(p->relobj(),
|
p->shndx()));
|
p->shndx()));
|
}
|
}
|
}
|
}
|
|
|
Line 11900... |
Line 11901... |
class Target_selector_arm : public Target_selector
|
class Target_selector_arm : public Target_selector
|
{
|
{
|
public:
|
public:
|
Target_selector_arm()
|
Target_selector_arm()
|
: Target_selector(elfcpp::EM_ARM, 32, big_endian,
|
: Target_selector(elfcpp::EM_ARM, 32, big_endian,
|
(big_endian ? "elf32-bigarm" : "elf32-littlearm"))
|
(big_endian ? "elf32-bigarm" : "elf32-littlearm"),
|
|
(big_endian ? "armelfb" : "armelf"))
|
{ }
|
{ }
|
|
|
Target*
|
Target*
|
do_instantiate_target()
|
do_instantiate_target()
|
{ return new Target_arm<big_endian>(); }
|
{ return new Target_arm<big_endian>(); }
|