aboutsummaryrefslogtreecommitdiff
path: root/gold/arm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/arm.cc')
-rw-r--r--gold/arm.cc137
1 files changed, 134 insertions, 3 deletions
diff --git a/gold/arm.cc b/gold/arm.cc
index 7736fa6..90deaa6 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -101,13 +101,10 @@ const int32_t THM2_MAX_BWD_BRANCH_OFFSET = (-(1 << 24) + 4);
// TODOs:
// - Support the following relocation types as needed:
// R_ARM_SBREL32
-// R_ARM_THM_PC8
// R_ARM_LDR_SBREL_11_0_NC
// R_ARM_ALU_SBREL_19_12_NC
// R_ARM_ALU_SBREL_27_20_CK
// R_ARM_SBREL31
-// R_ARM_THM_ALU_PREL_11_0
-// R_ARM_THM_PC12
// R_ARM_REL32_NOI
// R_ARM_PLT32_ABS
// R_ARM_GOT_ABS
@@ -3179,6 +3176,115 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian>
return This::STATUS_OKAY;
}
+ // R_ARM_THM_ALU_PREL_11_0: ((S + A) | T) - Pa (Thumb32)
+ static inline typename This::Status
+ thm_alu11(unsigned char* view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval,
+ Arm_address address,
+ Arm_address 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 insn = (elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+ | elfcpp::Swap<16, big_endian>::readval(wv + 1);
+
+ // 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
+ // -----------------------------------------------------------------------
+ // ADD{S} 1 1 1 1 0|i|0|1 0 0 0|S|1 1 0 1||0|imm3 |Rd |imm8
+ // ADDW 1 1 1 1 0|i|1|0 0 0 0|0|1 1 0 1||0|imm3 |Rd |imm8
+ // ADR[+] 1 1 1 1 0|i|1|0 0 0 0|0|1 1 1 1||0|imm3 |Rd |imm8
+ // SUB{S} 1 1 1 1 0|i|0|1 1 0 1|S|1 1 0 1||0|imm3 |Rd |imm8
+ // SUBW 1 1 1 1 0|i|1|0 1 0 1|0|1 1 0 1||0|imm3 |Rd |imm8
+ // ADR[-] 1 1 1 1 0|i|1|0 1 0 1|0|1 1 1 1||0|imm3 |Rd |imm8
+
+ // Determine a sign for the addend.
+ const int sign = ((insn & 0xf8ef0000) == 0xf0ad0000
+ || (insn & 0xf8ef0000) == 0xf0af0000) ? -1 : 1;
+ // Thumb2 addend encoding:
+ // imm12 := i | imm3 | imm8
+ int32_t addend = (insn & 0xff)
+ | ((insn & 0x00007000) >> 4)
+ | ((insn & 0x04000000) >> 15);
+ // Apply a sign to the added.
+ addend *= sign;
+
+ int32_t x = (psymval->value(object, addend) | thumb_bit)
+ - (address & 0xfffffffc);
+ Reltype val = abs(x);
+ // Mask out the value and a distinct part of the ADD/SUB opcode
+ // (bits 7:5 of opword).
+ insn = (insn & 0xfb0f8f00)
+ | (val & 0xff)
+ | ((val & 0x700) << 4)
+ | ((val & 0x800) << 15);
+ // Set the opcode according to whether the value to go in the
+ // place is negative.
+ if (x < 0)
+ insn |= 0x00a00000;
+
+ elfcpp::Swap<16, big_endian>::writeval(wv, insn >> 16);
+ elfcpp::Swap<16, big_endian>::writeval(wv + 1, insn & 0xffff);
+ return ((val > 0xfff) ?
+ This::STATUS_OVERFLOW : This::STATUS_OKAY);
+ }
+
+ // R_ARM_THM_PC8: S + A - Pa (Thumb)
+ static inline typename This::Status
+ thm_pc8(unsigned char* view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval,
+ Arm_address address)
+ {
+ 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 insn = elfcpp::Swap<16, big_endian>::readval(wv);
+ Reltype addend = ((insn & 0x00ff) << 2);
+ int32_t x = (psymval->value(object, addend) - (address & 0xfffffffc));
+ Reltype val = abs(x);
+ insn = (insn & 0xff00) | ((val & 0x03fc) >> 2);
+
+ elfcpp::Swap<16, big_endian>::writeval(wv, insn);
+ return ((val > 0x03fc)
+ ? This::STATUS_OVERFLOW
+ : This::STATUS_OKAY);
+ }
+
+ // R_ARM_THM_PC12: S + A - Pa (Thumb32)
+ static inline typename This::Status
+ thm_pc12(unsigned char* view,
+ const Sized_relobj<32, big_endian>* object,
+ const Symbol_value<32>* psymval,
+ Arm_address address)
+ {
+ 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 insn = (elfcpp::Swap<16, big_endian>::readval(wv) << 16)
+ | elfcpp::Swap<16, big_endian>::readval(wv + 1);
+ // Determine a sign for the addend (positive if the U bit is 1).
+ const int sign = (insn & 0x00800000) ? 1 : -1;
+ int32_t addend = (insn & 0xfff);
+ // Apply a sign to the added.
+ addend *= sign;
+
+ int32_t x = (psymval->value(object, addend) - (address & 0xfffffffc));
+ Reltype val = abs(x);
+ // Mask out and apply the value and the U bit.
+ insn = (insn & 0xff7ff000) | (val & 0xfff);
+ // Set the U bit according to whether the value to go in the
+ // place is positive.
+ if (x >= 0)
+ insn |= 0x00800000;
+
+ elfcpp::Swap<16, big_endian>::writeval(wv, insn >> 16);
+ elfcpp::Swap<16, big_endian>::writeval(wv + 1, insn & 0xffff);
+ return ((val > 0xfff) ?
+ This::STATUS_OVERFLOW : This::STATUS_OKAY);
+ }
+
// R_ARM_V4BX
static inline typename This::Status
v4bx(const Relocate_info<32, big_endian>* relinfo,
@@ -6578,6 +6684,9 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab,
case elfcpp::R_ARM_THM_JUMP8:
case elfcpp::R_ARM_THM_JUMP11:
case elfcpp::R_ARM_V4BX:
+ case elfcpp::R_ARM_THM_PC8:
+ case elfcpp::R_ARM_THM_PC12:
+ case elfcpp::R_ARM_THM_ALU_PREL_11_0:
case elfcpp::R_ARM_ALU_PC_G0_NC:
case elfcpp::R_ARM_ALU_PC_G0:
case elfcpp::R_ARM_ALU_PC_G1_NC:
@@ -6744,6 +6853,9 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
case elfcpp::R_ARM_THM_JUMP8:
case elfcpp::R_ARM_THM_JUMP11:
case elfcpp::R_ARM_V4BX:
+ case elfcpp::R_ARM_THM_PC8:
+ case elfcpp::R_ARM_THM_PC12:
+ case elfcpp::R_ARM_THM_ALU_PREL_11_0:
case elfcpp::R_ARM_ALU_PC_G0_NC:
case elfcpp::R_ARM_ALU_PC_G0:
case elfcpp::R_ARM_ALU_PC_G1_NC:
@@ -7523,6 +7635,22 @@ Target_arm<big_endian>::Relocate::relocate(
}
break;
+ case elfcpp::R_ARM_THM_PC8:
+ reloc_status =
+ Arm_relocate_functions::thm_pc8(view, object, psymval, address);
+ break;
+
+ case elfcpp::R_ARM_THM_PC12:
+ reloc_status =
+ Arm_relocate_functions::thm_pc12(view, object, psymval, address);
+ break;
+
+ case elfcpp::R_ARM_THM_ALU_PREL_11_0:
+ reloc_status =
+ Arm_relocate_functions::thm_alu11(view, object, psymval, address,
+ thumb_bit);
+ break;
+
case elfcpp::R_ARM_ALU_PC_G0_NC:
reloc_status =
Arm_relocate_functions::arm_grp_alu(view, object, psymval, 0,
@@ -7815,6 +7943,7 @@ Target_arm<big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
case elfcpp::R_ARM_THM_JUMP6:
case elfcpp::R_ARM_THM_JUMP8:
case elfcpp::R_ARM_THM_JUMP11:
+ case elfcpp::R_ARM_THM_PC8:
return 2;
case elfcpp::R_ARM_ABS32:
@@ -7846,6 +7975,8 @@ Target_arm<big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
case elfcpp::R_ARM_THM_MOVT_BREL:
case elfcpp::R_ARM_THM_MOVW_BREL:
case elfcpp::R_ARM_V4BX:
+ case elfcpp::R_ARM_THM_PC12:
+ case elfcpp::R_ARM_THM_ALU_PREL_11_0:
case elfcpp::R_ARM_ALU_PC_G0_NC:
case elfcpp::R_ARM_ALU_PC_G0:
case elfcpp::R_ARM_ALU_PC_G1_NC: