2009-06-03 Doug Kwan <dougkwan@google.com>
* gold/arm.cc (namespace utils): New. (Target_arm::reloc_is_non_pic): Define new method. (class Arm_relocate_functions): New. (Target_arm::Relocate::relocate): Handle relocation types used by Android.
This commit is contained in:
parent
07b82ea5f9
commit
c121c67179
@ -1,7 +1,31 @@
|
||||
2009-06-03 Doug Kwan <dougkwan@google.com>
|
||||
|
||||
* gold/arm.cc (namespace utils): New.
|
||||
(Target_arm::reloc_is_non_pic): Define new method.
|
||||
(class Arm_relocate_functions): New.
|
||||
(Target_arm::Relocate::relocate): Handle relocation types used by
|
||||
Android.
|
||||
|
||||
2009-06-03 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* arm.cc (Target_arm::scan::global): Use || instead of |.
|
||||
|
||||
2009-06-02 Doug Kwan <dougkwan@google.com>
|
||||
|
||||
* gold/arm.cc (Target_arm::Scan::Scan): Initialize
|
||||
issued_non_pic_error_.
|
||||
(class Target_arm::Scan): Declare new method check_non_pic.
|
||||
Define new method symbol_needs_plt_entry.
|
||||
Declare new data member issued_non_pic_error_.
|
||||
(class Target_arm::Relocate): Declare new method
|
||||
should_apply_static_reloc.
|
||||
(Target_arm::may_need_copy_reloc): Handle STT_ARM_TFUNC.
|
||||
(Target_arm::Scan::check_non_pic): Define new method.
|
||||
(Target_arm::Scan::local): Handle a small subset of reloc types used
|
||||
by Android.
|
||||
(Target_arm::Scan::local): Same.
|
||||
(Target_arm::Relocate::should_apply_statci_reloc): Define new method.
|
||||
|
||||
2009-05-31 Mikolaj Zalewski <mikolajz@google.com>
|
||||
|
||||
* incremental.cc (Incremental_inputs::report_command_line): Filter
|
||||
|
496
gold/arm.cc
496
gold/arm.cc
@ -75,7 +75,6 @@ class Output_data_plt_arm;
|
||||
// R_ARM_PREL31
|
||||
//
|
||||
// Coming soon (pending patches):
|
||||
// - Relocation
|
||||
// - Defining section symbols __exidx_start and __exidx_stop.
|
||||
// - Support interworking.
|
||||
// - Mergeing all .ARM.xxx.yyy sections into .ARM.xxx. Currently, they
|
||||
@ -88,6 +87,48 @@ class Output_data_plt_arm;
|
||||
// - Make PLTs more flexible for different architecture features like
|
||||
// Thumb-2 and BE8.
|
||||
|
||||
// Utilities for manipulating integers of up to 32-bits
|
||||
|
||||
namespace utils
|
||||
{
|
||||
// Sign extend an n-bit unsigned integer stored in an uint32_t into
|
||||
// an int32_t. NO_BITS must be between 1 to 32.
|
||||
template<int no_bits>
|
||||
static inline int32_t
|
||||
sign_extend(uint32_t bits)
|
||||
{
|
||||
gold_assert(no_bits < 1 || no_bits > 32);
|
||||
if (no_bits == 32)
|
||||
return static_cast<int32_t>(bits);
|
||||
uint32_t mask = (~((uint32_t) 0)) >> (32 - no_bits);
|
||||
bits &= mask;
|
||||
uint32_t top_bit = 1U << (no_bits - 1);
|
||||
int32_t as_signed = static_cast<int32_t>(bits);
|
||||
return (bits & top_bit) ? as_signed + (-top_bit * 2) : as_signed;
|
||||
}
|
||||
|
||||
// Detects overflow of an NO_BITS integer stored in a uint32_t.
|
||||
template<int no_bits>
|
||||
static inline bool
|
||||
has_overflow(uint32_t bits)
|
||||
{
|
||||
gold_assert(no_bits < 1 || no_bits > 32);
|
||||
if (no_bits == 32)
|
||||
return false;
|
||||
int32_t max = (1 << (no_bits - 1)) - 1;
|
||||
int32_t min = -(1 << (no_bits - 1));
|
||||
int32_t as_signed = static_cast<int32_t>(bits);
|
||||
return as_signed > max || as_signed < min;
|
||||
}
|
||||
|
||||
// Select bits from A and B using bits in MASK. For each n in [0..31],
|
||||
// the n-th bit in the result is chosen from the n-th bits of A and B.
|
||||
// A zero selects A and a one selects B.
|
||||
static inline uint32_t
|
||||
bit_select(uint32_t a, uint32_t b, uint32_t mask)
|
||||
{ return (a & ~mask) | (b & mask); }
|
||||
};
|
||||
|
||||
template<bool big_endian>
|
||||
class Target_arm : public Sized_target<32, big_endian>
|
||||
{
|
||||
@ -288,6 +329,24 @@ class Target_arm : public Sized_target<32, big_endian>
|
||||
const Symbol_value<32>*,
|
||||
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
|
||||
section_size_type);
|
||||
|
||||
// Return whether we want to pass flag NON_PIC_REF for this
|
||||
// reloc.
|
||||
static inline bool
|
||||
reloc_is_non_pic (unsigned int r_type)
|
||||
{
|
||||
switch (r_type)
|
||||
{
|
||||
case elfcpp::R_ARM_REL32:
|
||||
case elfcpp::R_ARM_THM_CALL:
|
||||
case elfcpp::R_ARM_CALL:
|
||||
case elfcpp::R_ARM_JUMP24:
|
||||
case elfcpp::R_ARM_PREL31:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// A class which returns the size required for a relocation type,
|
||||
@ -393,6 +452,254 @@ const Target::Target_info Target_arm<big_endian>::arm_info =
|
||||
0x1000 // common_pagesize (overridable by -z common-page-size)
|
||||
};
|
||||
|
||||
// Arm relocate functions class
|
||||
//
|
||||
|
||||
template<bool big_endian>
|
||||
class Arm_relocate_functions : public Relocate_functions<32, big_endian>
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
STATUS_OKAY, // No error during relocation.
|
||||
STATUS_OVERFLOW, // Relocation oveflow.
|
||||
STATUS_BAD_RELOC // Relocation cannot be applied.
|
||||
} Status;
|
||||
|
||||
private:
|
||||
typedef Relocate_functions<32, big_endian> Base;
|
||||
typedef Arm_relocate_functions<big_endian> This;
|
||||
|
||||
// Get an symbol value of *PSYMVAL with an ADDEND. This is a wrapper
|
||||
// to Symbol_value::value(). If HAS_THUMB_BIT is true, that LSB is used
|
||||
// to distinguish ARM and THUMB functions and it is treated specially.
|
||||
static inline Symbol_value<32>::Value
|
||||
arm_symbol_value (const Sized_relobj<32, big_endian> *object,
|
||||
const Symbol_value<32>* psymval,
|
||||
Symbol_value<32>::Value addend,
|
||||
bool has_thumb_bit)
|
||||
{
|
||||
typedef Symbol_value<32>::Value Valtype;
|
||||
|
||||
if (has_thumb_bit)
|
||||
{
|
||||
Valtype raw = psymval->value(object, 0);
|
||||
Valtype thumb_bit = raw & 1;
|
||||
return ((raw & ~((Valtype) 1)) + addend) | thumb_bit;
|
||||
}
|
||||
else
|
||||
return psymval->value(object, addend);
|
||||
}
|
||||
|
||||
// FIXME: This probably only works for Android on ARM v5te. We should
|
||||
// following GNU ld for the general case.
|
||||
template<unsigned r_type>
|
||||
static inline typename This::Status
|
||||
arm_branch_common(unsigned char *view,
|
||||
const Sized_relobj<32, big_endian>* object,
|
||||
const Symbol_value<32>* psymval,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
bool has_thumb_bit)
|
||||
{
|
||||
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
|
||||
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
||||
Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
|
||||
|
||||
bool insn_is_b = (((val >> 28) & 0xf) <= 0xe)
|
||||
&& ((val & 0x0f000000UL) == 0x0a000000UL);
|
||||
bool insn_is_uncond_bl = (val & 0xff000000UL) == 0xeb000000UL;
|
||||
bool insn_is_cond_bl = (((val >> 28) & 0xf) < 0xe)
|
||||
&& ((val & 0x0f000000UL) == 0x0b000000UL);
|
||||
bool insn_is_blx = (val & 0xfe000000UL) == 0xfa000000UL;
|
||||
bool insn_is_any_branch = (val & 0x0e000000UL) == 0x0a000000UL;
|
||||
|
||||
if (r_type == elfcpp::R_ARM_CALL)
|
||||
{
|
||||
if (!insn_is_uncond_bl && !insn_is_blx)
|
||||
return This::STATUS_BAD_RELOC;
|
||||
}
|
||||
else if (r_type == elfcpp::R_ARM_JUMP24)
|
||||
{
|
||||
if (!insn_is_b && !insn_is_cond_bl)
|
||||
return This::STATUS_BAD_RELOC;
|
||||
}
|
||||
else if (r_type == elfcpp::R_ARM_PLT32)
|
||||
{
|
||||
if (!insn_is_any_branch)
|
||||
return This::STATUS_BAD_RELOC;
|
||||
}
|
||||
else
|
||||
gold_unreachable();
|
||||
|
||||
Valtype addend = utils::sign_extend<26>(val << 2);
|
||||
Valtype x = (This::arm_symbol_value(object, psymval, addend, has_thumb_bit)
|
||||
- address);
|
||||
|
||||
// If target has thumb bit set, we need to either turn the BL
|
||||
// into a BLX (for ARMv5 or above) or generate a stub.
|
||||
if (x & 1)
|
||||
{
|
||||
// Turn BL to BLX.
|
||||
if (insn_is_uncond_bl)
|
||||
val = (val & 0xffffff) | 0xfa000000 | ((x & 2) << 23);
|
||||
else
|
||||
return This::STATUS_BAD_RELOC;
|
||||
}
|
||||
else
|
||||
gold_assert(!insn_is_blx);
|
||||
|
||||
val = utils::bit_select(val, (x >> 2), 0xffffffUL);
|
||||
elfcpp::Swap<32, big_endian>::writeval(wv, val);
|
||||
return (utils::has_overflow<26>(x)
|
||||
? This::STATUS_OVERFLOW : This::STATUS_OKAY);
|
||||
}
|
||||
|
||||
public:
|
||||
// R_ARM_ABS32: (S + A) | T
|
||||
static inline typename This::Status
|
||||
abs32(unsigned char *view,
|
||||
const Sized_relobj<32, big_endian>* object,
|
||||
const Symbol_value<32>* psymval,
|
||||
bool has_thumb_bit)
|
||||
{
|
||||
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
|
||||
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
||||
Valtype addend = elfcpp::Swap<32, big_endian>::readval(wv);
|
||||
Valtype x = This::arm_symbol_value(object, psymval, addend, has_thumb_bit);
|
||||
elfcpp::Swap<32, big_endian>::writeval(wv, x);
|
||||
return This::STATUS_OKAY;
|
||||
}
|
||||
|
||||
// R_ARM_REL32: (S + A) | T - P
|
||||
static inline typename This::Status
|
||||
rel32(unsigned char *view,
|
||||
const Sized_relobj<32, big_endian>* object,
|
||||
const Symbol_value<32>* psymval,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
bool has_thumb_bit)
|
||||
{
|
||||
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
|
||||
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
||||
Valtype addend = elfcpp::Swap<32, big_endian>::readval(wv);
|
||||
Valtype x = (This::arm_symbol_value(object, psymval, addend, has_thumb_bit)
|
||||
- address);
|
||||
elfcpp::Swap<32, big_endian>::writeval(wv, x);
|
||||
return This::STATUS_OKAY;
|
||||
}
|
||||
|
||||
// R_ARM_THM_CALL: (S + A) | T - P
|
||||
static inline typename This::Status
|
||||
thm_call(unsigned char *view,
|
||||
const Sized_relobj<32, big_endian>* object,
|
||||
const Symbol_value<32>* psymval,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
bool has_thumb_bit)
|
||||
{
|
||||
// A thumb call consists of two instructions.
|
||||
typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
|
||||
typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
|
||||
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
||||
Valtype hi = elfcpp::Swap<16, big_endian>::readval(wv);
|
||||
Valtype lo = elfcpp::Swap<16, big_endian>::readval(wv + 1);
|
||||
// Must be a BL instruction. lo == 11111xxxxxxxxxxx.
|
||||
gold_assert((lo & 0xf800) == 0xf800);
|
||||
Reltype addend = utils::sign_extend<23>(((hi & 0x7ff) << 12)
|
||||
| ((lo & 0x7ff) << 1));
|
||||
Reltype x = (This::arm_symbol_value(object, psymval, addend, has_thumb_bit)
|
||||
- address);
|
||||
|
||||
// If target has no thumb bit set, we need to either turn the BL
|
||||
// into a BLX (for ARMv5 or above) or generate a stub.
|
||||
if ((x & 1) == 0)
|
||||
{
|
||||
// This only works for ARMv5 and above with interworking enabled.
|
||||
lo &= 0xefff;
|
||||
}
|
||||
hi = utils::bit_select(hi, (x >> 12), 0x7ffU);
|
||||
lo = utils::bit_select(lo, (x >> 1), 0x7ffU);
|
||||
elfcpp::Swap<16, big_endian>::writeval(wv, hi);
|
||||
elfcpp::Swap<16, big_endian>::writeval(wv + 1, lo);
|
||||
return (utils::has_overflow<23>(x)
|
||||
? This::STATUS_OVERFLOW
|
||||
: This::STATUS_OKAY);
|
||||
}
|
||||
|
||||
// R_ARM_BASE_PREL: B(S) + A - P
|
||||
static inline typename This::Status
|
||||
base_prel(unsigned char* view,
|
||||
elfcpp::Elf_types<32>::Elf_Addr origin,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address)
|
||||
{
|
||||
Base::rel32(view, origin - address);
|
||||
return STATUS_OKAY;
|
||||
}
|
||||
|
||||
// R_ARM_GOT_BREL: GOT(S) + A - GOT_ORG
|
||||
static inline typename This::Status
|
||||
got_brel(unsigned char* view,
|
||||
typename elfcpp::Swap<32, big_endian>::Valtype got_offset)
|
||||
{
|
||||
Base::rel32(view, got_offset);
|
||||
return This::STATUS_OKAY;
|
||||
}
|
||||
|
||||
// R_ARM_PLT32: (S + A) | T - P
|
||||
static inline typename This::Status
|
||||
plt32(unsigned char *view,
|
||||
const Sized_relobj<32, big_endian>* object,
|
||||
const Symbol_value<32>* psymval,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
bool has_thumb_bit)
|
||||
{
|
||||
return arm_branch_common<elfcpp::R_ARM_PLT32>(view, object, psymval,
|
||||
address, has_thumb_bit);
|
||||
}
|
||||
|
||||
// R_ARM_CALL: (S + A) | T - P
|
||||
static inline typename This::Status
|
||||
call(unsigned char *view,
|
||||
const Sized_relobj<32, big_endian>* object,
|
||||
const Symbol_value<32>* psymval,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
bool has_thumb_bit)
|
||||
{
|
||||
return arm_branch_common<elfcpp::R_ARM_CALL>(view, object, psymval,
|
||||
address, has_thumb_bit);
|
||||
}
|
||||
|
||||
// R_ARM_JUMP24: (S + A) | T - P
|
||||
static inline typename This::Status
|
||||
jump24(unsigned char *view,
|
||||
const Sized_relobj<32, big_endian>* object,
|
||||
const Symbol_value<32>* psymval,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
bool has_thumb_bit)
|
||||
{
|
||||
return arm_branch_common<elfcpp::R_ARM_JUMP24>(view, object, psymval,
|
||||
address, has_thumb_bit);
|
||||
}
|
||||
|
||||
// R_ARM_PREL: (S + A) | T - P
|
||||
static inline typename This::Status
|
||||
prel31(unsigned char *view,
|
||||
const Sized_relobj<32, big_endian>* object,
|
||||
const Symbol_value<32>* psymval,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
bool has_thumb_bit)
|
||||
{
|
||||
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
|
||||
Valtype* wv = reinterpret_cast<Valtype*>(view);
|
||||
Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
|
||||
Valtype addend = utils::sign_extend<31>(val);
|
||||
Valtype x = (This::arm_symbol_value(object, psymval, addend, has_thumb_bit)
|
||||
- address);
|
||||
val = utils::bit_select(val, x, 0x7fffffffU);
|
||||
elfcpp::Swap<32, big_endian>::writeval(wv, val);
|
||||
return (utils::has_overflow<31>(x) ?
|
||||
This::STATUS_OVERFLOW : This::STATUS_OKAY);
|
||||
}
|
||||
};
|
||||
|
||||
// Get the GOT section, creating it if necessary.
|
||||
|
||||
template<bool big_endian>
|
||||
@ -1199,23 +1506,192 @@ Target_arm<big_endian>::Relocate::should_apply_static_reloc(
|
||||
template<bool big_endian>
|
||||
inline bool
|
||||
Target_arm<big_endian>::Relocate::relocate(
|
||||
const Relocate_info<32, big_endian>* /* relinfo */,
|
||||
Target_arm* /* target */,
|
||||
Output_section* /* output_section */,
|
||||
size_t /* relnum */,
|
||||
const elfcpp::Rel<32, big_endian>& /* rel */,
|
||||
const Relocate_info<32, big_endian>* relinfo,
|
||||
Target_arm* target,
|
||||
Output_section *output_section,
|
||||
size_t relnum,
|
||||
const elfcpp::Rel<32, big_endian>& rel,
|
||||
unsigned int r_type,
|
||||
const Sized_symbol<32>* /* gsym */,
|
||||
const Symbol_value<32>* /* psymval */,
|
||||
unsigned char* /* view */,
|
||||
elfcpp::Elf_types<32>::Elf_Addr /* address */,
|
||||
const Sized_symbol<32>* gsym,
|
||||
const Symbol_value<32>* psymval,
|
||||
unsigned char* view,
|
||||
elfcpp::Elf_types<32>::Elf_Addr address,
|
||||
section_size_type /* view_size */ )
|
||||
{
|
||||
typedef Arm_relocate_functions<big_endian> Arm_relocate_functions;
|
||||
|
||||
r_type = get_real_reloc_type(r_type);
|
||||
|
||||
// If this the symbol may be a Thumb function, set thumb bit to 1.
|
||||
bool has_thumb_bit = ((gsym != NULL)
|
||||
&& (gsym->type() == elfcpp::STT_FUNC
|
||||
|| gsym->type() == elfcpp::STT_ARM_TFUNC));
|
||||
|
||||
// Pick the value to use for symbols defined in shared objects.
|
||||
Symbol_value<32> symval;
|
||||
if (gsym != NULL
|
||||
&& gsym->use_plt_offset(reloc_is_non_pic(r_type)))
|
||||
{
|
||||
symval.set_output_value(target->plt_section()->address()
|
||||
+ gsym->plt_offset());
|
||||
psymval = &symval;
|
||||
has_thumb_bit = 0;
|
||||
}
|
||||
|
||||
const Sized_relobj<32, big_endian>* object = relinfo->object;
|
||||
|
||||
// Get the GOT offset if needed.
|
||||
// The GOT pointer points to the end of the GOT section.
|
||||
// We need to subtract the size of the GOT section to get
|
||||
// the actual offset to use in the relocation.
|
||||
bool have_got_offset = false;
|
||||
unsigned int got_offset = 0;
|
||||
switch (r_type)
|
||||
{
|
||||
case elfcpp::R_ARM_GOT_BREL:
|
||||
if (gsym != NULL)
|
||||
{
|
||||
gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
|
||||
got_offset = (gsym->got_offset(GOT_TYPE_STANDARD)
|
||||
- target->got_size());
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
|
||||
gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
|
||||
got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
|
||||
- target->got_size());
|
||||
}
|
||||
have_got_offset = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
typename Arm_relocate_functions::Status reloc_status =
|
||||
Arm_relocate_functions::STATUS_OKAY;
|
||||
switch (r_type)
|
||||
{
|
||||
case elfcpp::R_ARM_NONE:
|
||||
break;
|
||||
|
||||
case elfcpp::R_ARM_ABS32:
|
||||
if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
|
||||
output_section))
|
||||
reloc_status = Arm_relocate_functions::abs32(view, object, psymval,
|
||||
has_thumb_bit);
|
||||
break;
|
||||
|
||||
case elfcpp::R_ARM_REL32:
|
||||
reloc_status = Arm_relocate_functions::rel32(view, object, psymval,
|
||||
address, has_thumb_bit);
|
||||
break;
|
||||
|
||||
case elfcpp::R_ARM_THM_CALL:
|
||||
reloc_status = Arm_relocate_functions::thm_call(view, object, psymval,
|
||||
address, has_thumb_bit);
|
||||
break;
|
||||
|
||||
case elfcpp::R_ARM_GOTOFF32:
|
||||
{
|
||||
elfcpp::Elf_types<32>::Elf_Addr got_origin;
|
||||
got_origin = target->got_plt_section()->address();
|
||||
reloc_status = Arm_relocate_functions::rel32(view, object, psymval,
|
||||
got_origin, has_thumb_bit);
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_ARM_BASE_PREL:
|
||||
{
|
||||
uint32_t origin;
|
||||
// Get the addressing origin of the output segment defining the
|
||||
// symbol gsym (AAELF 4.6.1.2 Relocation types)
|
||||
gold_assert(gsym != NULL);
|
||||
if (gsym->source() == Symbol::IN_OUTPUT_SEGMENT)
|
||||
origin = gsym->output_segment()->vaddr();
|
||||
else if (gsym->source () == Symbol::IN_OUTPUT_DATA)
|
||||
origin = gsym->output_data()->address();
|
||||
else
|
||||
{
|
||||
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
|
||||
_("cannot find origin of R_ARM_BASE_PREL"));
|
||||
return true;
|
||||
}
|
||||
reloc_status = Arm_relocate_functions::base_prel(view, origin, address);
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_ARM_GOT_BREL:
|
||||
gold_assert(have_got_offset);
|
||||
reloc_status = Arm_relocate_functions::got_brel(view, got_offset);
|
||||
break;
|
||||
|
||||
case elfcpp::R_ARM_PLT32:
|
||||
gold_assert(gsym == NULL
|
||||
|| gsym->has_plt_offset()
|
||||
|| gsym->final_value_is_known()
|
||||
|| (gsym->is_defined()
|
||||
&& !gsym->is_from_dynobj()
|
||||
&& !gsym->is_preemptible()));
|
||||
reloc_status = Arm_relocate_functions::plt32(view, object, psymval,
|
||||
address, has_thumb_bit);
|
||||
break;
|
||||
|
||||
case elfcpp::R_ARM_CALL:
|
||||
reloc_status = Arm_relocate_functions::call(view, object, psymval,
|
||||
address, has_thumb_bit);
|
||||
break;
|
||||
|
||||
case elfcpp::R_ARM_JUMP24:
|
||||
reloc_status = Arm_relocate_functions::jump24(view, object, psymval,
|
||||
address, has_thumb_bit);
|
||||
break;
|
||||
|
||||
case elfcpp::R_ARM_PREL31:
|
||||
reloc_status = Arm_relocate_functions::prel31(view, object, psymval,
|
||||
address, has_thumb_bit);
|
||||
break;
|
||||
|
||||
case elfcpp::R_ARM_TARGET1:
|
||||
// This should have been mapped to another type already.
|
||||
// Fall through.
|
||||
case elfcpp::R_ARM_COPY:
|
||||
case elfcpp::R_ARM_GLOB_DAT:
|
||||
case elfcpp::R_ARM_JUMP_SLOT:
|
||||
case elfcpp::R_ARM_RELATIVE:
|
||||
// These are relocations which should only be seen by the
|
||||
// dynamic linker, and should never be seen here.
|
||||
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
|
||||
_("unexpected reloc %u in object file"),
|
||||
r_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
|
||||
_("unsupported reloc %u"),
|
||||
r_type);
|
||||
break;
|
||||
}
|
||||
|
||||
// Report any errors.
|
||||
switch (reloc_status)
|
||||
{
|
||||
case Arm_relocate_functions::STATUS_OKAY:
|
||||
break;
|
||||
case Arm_relocate_functions::STATUS_OVERFLOW:
|
||||
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
|
||||
_("relocation overflow in relocation %u"),
|
||||
r_type);
|
||||
break;
|
||||
case Arm_relocate_functions::STATUS_BAD_RELOC:
|
||||
gold_error_at_location(
|
||||
relinfo,
|
||||
relnum,
|
||||
rel.get_r_offset(),
|
||||
_("unexpected opcode while processing relocation %u"),
|
||||
r_type);
|
||||
break;
|
||||
default:
|
||||
gold_unreachable();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user