diff options
-rw-r--r-- | gold/ChangeLog | 19 | ||||
-rw-r--r-- | gold/arm.cc | 205 |
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: |