summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog19
-rw-r--r--gold/arm.cc205
2 files changed, 224 insertions, 0 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 28f76fb50f..4a2e831a26 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,5 +1,24 @@
2009-10-07 Viktor Kutuzov <vkutuzov@accesssoftek.com>
+ * arm.cc (Arm_relocate_functions::extract_arm_movw_movt_addend):
+ New function.
+ (Arm_relocate_functions::insert_val_arm_movw_movt): New function.
+ (Arm_relocate_functions::extract_thumb_movw_movt_addend): New
+ function.
+ (Arm_relocate_functions::insert_val_thumb_movw_movt): New
+ function.
+ (Arm_relocate_functions::movw_abs_nc): New function.
+ (Arm_relocate_functions::movt_abs): New function.
+ (Arm_relocate_functions::thm_movw_abs_nc): New function.
+ (Arm_relocate_functions::thm_movt_abs): New function.
+ (Scan::local): Handle R_ARM_MOVW_ABS_NC, R_ARM_MOVT_ABS,
+ R_ARM_THM_MOVW_ABS_NC, R_ARM_THM_MOVT_ABS.
+ (Scan::global): Likewise.
+ (Relocate::relocate): Likewise.
+ (Relocatable_size_for_reloc::get_size_for_reloc): Likewise.
+
+2009-10-07 Viktor Kutuzov <vkutuzov@accesssoftek.com>
+
* arm.cc (Arm_relocate_functions::got_prel) New function.
(Scan::local, Scan::global): Handle R_ARM_GOT_PREL.
(Relocate::relocate): Likewise.
diff --git a/gold/arm.cc b/gold/arm.cc
index f70964c5e8..d855092bc4 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -75,6 +75,10 @@ class Output_data_plt_arm;
// R_ARM_TARGET1
// R_ARM_PREL31
// R_ARM_ABS8
+// R_ARM_MOVW_ABS_NC
+// R_ARM_MOVT_ABS
+// R_ARM_THM_MOVW_ABS_NC
+// R_ARM_THM_MOVT_ABS
//
// TODOs:
// - Generate various branch stubs.
@@ -509,6 +513,79 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian>
return psymval->value(object, addend);
}
+ // Encoding of imm16 argument for movt and movw ARM instructions
+ // from ARM ARM:
+ //
+ // imm16 := imm4 | imm12
+ //
+ // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
+ // +-------+---------------+-------+-------+-----------------------+
+ // | | |imm4 | |imm12 |
+ // +-------+---------------+-------+-------+-----------------------+
+
+ // Extract the relocation addend from VAL based on the ARM
+ // instruction encoding described above.
+ static inline typename elfcpp::Swap<32, big_endian>::Valtype
+ extract_arm_movw_movt_addend(
+ typename elfcpp::Swap<32, big_endian>::Valtype val)
+ {
+ // According to the Elf ABI for ARM Architecture the immediate
+ // field is sign-extended to form the addend.
+ return utils::sign_extend<16>(((val >> 4) & 0xf000) | (val & 0xfff));
+ }
+
+ // Insert X into VAL based on the ARM instruction encoding described
+ // above.
+ static inline typename elfcpp::Swap<32, big_endian>::Valtype
+ insert_val_arm_movw_movt(
+ typename elfcpp::Swap<32, big_endian>::Valtype val,
+ typename elfcpp::Swap<32, big_endian>::Valtype x)
+ {
+ val &= 0xfff0f000;
+ val |= x & 0x0fff;
+ val |= (x & 0xf000) << 4;
+ return val;
+ }
+
+ // Encoding of imm16 argument for movt and movw Thumb2 instructions
+ // from ARM ARM:
+ //
+ // imm16 := imm4 | i | imm3 | imm8
+ //
+ // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
+ // +---------+-+-----------+-------++-+-----+-------+---------------+
+ // | |i| |imm4 || |imm3 | |imm8 |
+ // +---------+-+-----------+-------++-+-----+-------+---------------+
+
+ // Extract the relocation addend from VAL based on the Thumb2
+ // instruction encoding described above.
+ static inline typename elfcpp::Swap<32, big_endian>::Valtype
+ extract_thumb_movw_movt_addend(
+ typename elfcpp::Swap<32, big_endian>::Valtype val)
+ {
+ // According to the Elf ABI for ARM Architecture the immediate
+ // field is sign-extended to form the addend.
+ return utils::sign_extend<16>(((val >> 4) & 0xf000)
+ | ((val >> 15) & 0x0800)
+ | ((val >> 4) & 0x0700)
+ | (val & 0x00ff));
+ }
+
+ // Insert X into VAL based on the Thumb2 instruction encoding
+ // described above.
+ static inline typename elfcpp::Swap<32, big_endian>::Valtype
+ insert_val_thumb_movw_movt(
+ typename elfcpp::Swap<32, big_endian>::Valtype val,
+ typename elfcpp::Swap<32, big_endian>::Valtype x)
+ {
+ val &= 0xfbf08f00;
+ val |= (x & 0xf000) << 4;
+ val |= (x & 0x0800) << 15;
+ val |= (x & 0x0700) << 4;
+ val |= (x & 0x00ff);
+ return val;
+ }
+
// FIXME: This probably only works for Android on ARM v5te. We should
// following GNU ld for the general case.
template<unsigned r_type>
@@ -746,6 +823,79 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian>
return (utils::has_overflow<31>(x) ?
This::STATUS_OVERFLOW : This::STATUS_OKAY);
}
+
+ // R_ARM_MOVW_ABS_NC: (S + A) | T
+ static inline typename This::Status
+ movw_abs_nc(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 val = elfcpp::Swap<32, big_endian>::readval(wv);
+ Valtype addend = This::extract_arm_movw_movt_addend(val);
+ Valtype x = This::arm_symbol_value(object, psymval, addend, has_thumb_bit);
+ val = This::insert_val_arm_movw_movt(val, x);
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+ return This::STATUS_OKAY;
+ }
+
+ // R_ARM_MOVT_ABS: S + A
+ static inline typename This::Status
+ movt_abs(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval)
+ {
+ 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 = This::extract_arm_movw_movt_addend(val);
+ Valtype x = This::arm_symbol_value(object, psymval, addend, 0) >> 16;
+ val = This::insert_val_arm_movw_movt(val, x);
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+ return This::STATUS_OKAY;
+ }
+
+ // R_ARM_THM_MOVW_ABS_NC: S + A | T
+ static inline typename This::Status
+ thm_movw_abs_nc(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval,
+ bool has_thumb_bit)
+ {
+ typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Reltype val = ((elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+ | elfcpp::Swap<16, big_endian>::readval(wv + 1));
+ Reltype addend = extract_thumb_movw_movt_addend(val);
+ Reltype x = This::arm_symbol_value(object, psymval, addend, has_thumb_bit);
+ val = This::insert_val_thumb_movw_movt(val, x);
+ elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
+ elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
+ return This::STATUS_OKAY;
+ }
+
+ // R_ARM_THM_MOVT_ABS: S + A
+ static inline typename This::Status
+ thm_movt_abs(unsigned char *view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval)
+ {
+ typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
+ typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
+ Valtype* wv = reinterpret_cast<Valtype*>(view);
+ Reltype val = ((elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+ | elfcpp::Swap<16, big_endian>::readval(wv + 1));
+ Reltype addend = This::extract_thumb_movw_movt_addend(val);
+ Reltype x = This::arm_symbol_value(object, psymval, addend, 0) >> 16;
+ val = This::insert_val_thumb_movw_movt(val, x);
+ elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
+ elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
+ return This::STATUS_OKAY;
+ }
+
};
// Get the GOT section, creating it if necessary.
@@ -1156,6 +1306,10 @@ Target_arm<big_endian>::Scan::local(const General_options&,
case elfcpp::R_ARM_PREL31:
case elfcpp::R_ARM_JUMP24:
case elfcpp::R_ARM_PLT32:
+ case elfcpp::R_ARM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_MOVT_ABS:
+ case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_THM_MOVT_ABS:
break;
case elfcpp::R_ARM_GOTOFF32:
@@ -1286,6 +1440,12 @@ Target_arm<big_endian>::Scan::global(const General_options&,
}
break;
+ case elfcpp::R_ARM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_MOVT_ABS:
+ case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_THM_MOVT_ABS:
+ break;
+
case elfcpp::R_ARM_REL32:
case elfcpp::R_ARM_PREL31:
{
@@ -1679,6 +1839,47 @@ Target_arm<big_endian>::Relocate::relocate(
has_thumb_bit);
break;
+ case elfcpp::R_ARM_MOVW_ABS_NC:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+ output_section))
+ reloc_status = Arm_relocate_functions::movw_abs_nc(view, object,
+ psymval,
+ has_thumb_bit);
+ else
+ gold_error(_("relocation R_ARM_MOVW_ABS_NC cannot be used when making"
+ "a shared object; recompile with -fPIC"));
+ break;
+
+ case elfcpp::R_ARM_MOVT_ABS:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+ output_section))
+ reloc_status = Arm_relocate_functions::movt_abs(view, object, psymval);
+ else
+ gold_error(_("relocation R_ARM_MOVT_ABS cannot be used when making"
+ "a shared object; recompile with -fPIC"));
+ break;
+
+ case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+ output_section))
+ reloc_status = Arm_relocate_functions::thm_movw_abs_nc(view, object,
+ psymval,
+ has_thumb_bit);
+ else
+ gold_error(_("relocation R_ARM_THM_MOVW_ABS_NC cannot be used when"
+ "making a shared object; recompile with -fPIC"));
+ break;
+
+ case elfcpp::R_ARM_THM_MOVT_ABS:
+ if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true,
+ output_section))
+ reloc_status = Arm_relocate_functions::thm_movt_abs(view, object,
+ psymval);
+ else
+ gold_error(_("relocation R_ARM_THM_MOVT_ABS cannot be used when"
+ "making a shared object; recompile with -fPIC"));
+ break;
+
case elfcpp::R_ARM_REL32:
reloc_status = Arm_relocate_functions::rel32(view, object, psymval,
address, has_thumb_bit);
@@ -1869,6 +2070,10 @@ Target_arm<big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
case elfcpp::R_ARM_CALL:
case elfcpp::R_ARM_JUMP24:
case elfcpp::R_ARM_PREL31:
+ case elfcpp::R_ARM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_MOVT_ABS:
+ case elfcpp::R_ARM_THM_MOVW_ABS_NC:
+ case elfcpp::R_ARM_THM_MOVT_ABS:
return 4;
case elfcpp::R_ARM_TARGET1: