[llvm] r213689 - [RuntimeDyld][MachO][AArch64] Add a helper function for encoding addends in instructions.
Juergen Ributzka
juergen at apple.com
Tue Jul 22 14:42:56 PDT 2014
Author: ributzka
Date: Tue Jul 22 16:42:55 2014
New Revision: 213689
URL: http://llvm.org/viewvc/llvm-project?rev=213689&view=rev
Log:
[RuntimeDyld][MachO][AArch64] Add a helper function for encoding addends in instructions.
Factor out the addend encoding into a helper function and simplify the
processRelocationRef.
Also add a few simple rtdyld tests. More tests to come once GOTs can be tested too.
Related to <rdar://problem/17768539>
Added:
llvm/trunk/test/ExecutionEngine/RuntimeDyld/AArch64/
llvm/trunk/test/ExecutionEngine/RuntimeDyld/AArch64/MachO_ARM64_relocations.s
llvm/trunk/test/ExecutionEngine/RuntimeDyld/AArch64/lit.local.cfg
Modified:
llvm/trunk/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h
Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h?rev=213689&r1=213688&r2=213689&view=diff
==============================================================================
--- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h (original)
+++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h Tue Jul 22 16:42:55 2014
@@ -118,6 +118,109 @@ public:
return Addend;
}
+ /// Extract the addend encoded in the instruction.
+ void encodeAddend(uint8_t *LocalAddress, uint32_t RelType,
+ int64_t Addend) const {
+ // Verify that the relocation has the correct alignment.
+ switch (RelType) {
+ default:
+ llvm_unreachable("Unsupported relocation type!");
+ case MachO::ARM64_RELOC_UNSIGNED:
+ llvm_unreachable("Invalid relocation type for instruction.");
+ case MachO::ARM64_RELOC_BRANCH26:
+ case MachO::ARM64_RELOC_PAGE21:
+ case MachO::ARM64_RELOC_PAGEOFF12:
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
+ assert((((uintptr_t)LocalAddress & 0x3) == 0) &&
+ "Instruction address is not aligned to 4 bytes.");
+ break;
+ }
+
+ switch (RelType) {
+ default:
+ llvm_unreachable("Unsupported relocation type!");
+ case MachO::ARM64_RELOC_BRANCH26: {
+ // Verify that the relocation points to the expected branch instruction.
+ uint32_t *p = (uint32_t *)LocalAddress;
+ assert((*p & 0xFC000000) == 0x14000000 && "Expected branch instruction.");
+
+ // Verify addend value.
+ assert((Addend & 0x3) == 0 && "Branch target is not aligned");
+ assert(isInt<28>(Addend) && "Branch target is out of range.");
+
+ // Encode the addend as 26 bit immediate in the branch instruction.
+ *p = (*p & 0xFC000000) | ((uint32_t)(Addend >> 2) & 0x03FFFFFF);
+ break;
+ }
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
+ case MachO::ARM64_RELOC_PAGE21: {
+ // Verify that the relocation points to the expected adrp instruction.
+ uint32_t *p = (uint32_t *)LocalAddress;
+ assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction.");
+
+ // Check that the addend fits into 21 bits (+ 12 lower bits).
+ assert((Addend & 0xFFF) == 0 && "ADRP target is not page aligned.");
+ assert(isInt<33>(Addend) && "Invalid page reloc value.");
+
+ // Encode the addend into the instruction.
+ uint32_t ImmLoValue = (uint32_t)(Addend << 17) & 0x60000000;
+ uint32_t ImmHiValue = (uint32_t)(Addend >> 9) & 0x00FFFFE0;
+ *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
+ break;
+ }
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: {
+ // Verify that the relocation points to one of the expected load / store
+ // instructions.
+ uint32_t *p = (uint32_t *)LocalAddress;
+ assert((*p & 0x3B000000) == 0x39000000 &&
+ "Only expected load / store instructions.");
+ } // fall-through
+ case MachO::ARM64_RELOC_PAGEOFF12: {
+ // Verify that the relocation points to one of the expected load / store
+ // or add / sub instructions.
+ uint32_t *p = (uint32_t *)LocalAddress;
+ assert((((*p & 0x3B000000) == 0x39000000) ||
+ ((*p & 0x11C00000) == 0x11000000) ) &&
+ "Expected load / store or add/sub instruction.");
+
+ // Check which instruction we are decoding to obtain the implicit shift
+ // factor of the instruction and verify alignment.
+ int ImplicitShift = 0;
+ if ((*p & 0x3B000000) == 0x39000000) { // << load / store
+ // For load / store instructions the size is encoded in bits 31:30.
+ ImplicitShift = ((*p >> 30) & 0x3);
+ switch (ImplicitShift) {
+ case 0:
+ // Check if this a vector op to get the correct shift value.
+ if ((*p & 0x04800000) == 0x04800000) {
+ ImplicitShift = 4;
+ assert(((Addend & 0xF) == 0) &&
+ "128-bit LDR/STR not 16-byte aligned.");
+ }
+ break;
+ case 1:
+ assert(((Addend & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
+ break;
+ case 2:
+ assert(((Addend & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
+ break;
+ case 3:
+ assert(((Addend & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
+ break;
+ }
+ }
+ // Compensate for implicit shift.
+ Addend >>= ImplicitShift;
+ assert(isUInt<12>(Addend) && "Addend cannot be encoded.");
+
+ // Encode the addend into the instruction.
+ *p = (*p & 0xFFC003FF) | ((uint32_t)(Addend << 10) & 0x003FFC00);
+ break;
+ }
+ }
+ }
+
relocation_iterator
processRelocationRef(unsigned SectionID, relocation_iterator RelI,
ObjectImage &ObjImg, ObjSectionToIDMap &ObjSectionToID,
@@ -196,105 +299,37 @@ public:
}
case MachO::ARM64_RELOC_BRANCH26: {
assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
- // Mask the value into the target address. We know instructions are
- // 32-bit aligned, so we can do it all at once.
- uint32_t *p = (uint32_t *)LocalAddress;
- // Check if the addend is encoded in the instruction.
- uint32_t EncodedAddend = *p & 0x03FFFFFF;
- if (EncodedAddend != 0) {
- if (RE.Addend == 0)
- llvm_unreachable("branch26 instruction has embedded addend.");
- else
- llvm_unreachable("branch26 instruction has embedded addend and"
- "ARM64_RELOC_ADDEND.");
- }
// Check if branch is in range.
uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
- uint64_t PCRelVal = Value - FinalAddress + RE.Addend;
- assert(isInt<26>(PCRelVal) && "Branch target out of range!");
- // Insert the value into the instruction.
- *p = (*p & 0xFC000000) | ((uint32_t)(PCRelVal >> 2) & 0x03FFFFFF);
+ int64_t PCRelVal = Value - FinalAddress + RE.Addend;
+ encodeAddend(LocalAddress, RE.RelType, PCRelVal);
break;
}
case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
case MachO::ARM64_RELOC_PAGE21: {
assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported");
- // Mask the value into the target address. We know instructions are
- // 32-bit aligned, so we can do it all at once.
- uint32_t *p = (uint32_t *)LocalAddress;
- // Check if the addend is encoded in the instruction.
- uint32_t EncodedAddend =
- ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3);
- if (EncodedAddend != 0) {
- if (RE.Addend == 0)
- llvm_unreachable("adrp instruction has embedded addend.");
- else
- llvm_unreachable("adrp instruction has embedded addend and"
- "ARM64_RELOC_ADDEND.");
- }
// Adjust for PC-relative relocation and offset.
uint64_t FinalAddress = Section.LoadAddress + RE.Offset;
- uint64_t PCRelVal =
- ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096));
- // Check that the value fits into 21 bits (+ 12 lower bits).
- assert(isInt<33>(PCRelVal) && "Invalid page reloc value!");
- // Insert the value into the instruction.
- uint32_t ImmLoValue = (uint32_t)(PCRelVal << 17) & 0x60000000;
- uint32_t ImmHiValue = (uint32_t)(PCRelVal >> 9) & 0x00FFFFE0;
- *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue;
+ int64_t PCRelVal =
+ ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096));
+ encodeAddend(LocalAddress, RE.RelType, PCRelVal);
break;
}
case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
case MachO::ARM64_RELOC_PAGEOFF12: {
assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported");
- // Mask the value into the target address. We know instructions are
- // 32-bit aligned, so we can do it all at once.
- uint32_t *p = (uint32_t *)LocalAddress;
- // Check if the addend is encoded in the instruction.
- uint32_t EncodedAddend = *p & 0x003FFC00;
- if (EncodedAddend != 0) {
- if (RE.Addend == 0)
- llvm_unreachable("adrp instruction has embedded addend.");
- else
- llvm_unreachable("adrp instruction has embedded addend and"
- "ARM64_RELOC_ADDEND.");
- }
// Add the offset from the symbol.
Value += RE.Addend;
// Mask out the page address and only use the lower 12 bits.
Value &= 0xFFF;
- // Check which instruction we are updating to obtain the implicit shift
- // factor from LDR/STR instructions.
- if (*p & 0x08000000) {
- uint32_t ImplicitShift = ((*p >> 30) & 0x3);
- switch (ImplicitShift) {
- case 0:
- // Check if this a vector op.
- if ((*p & 0x04800000) == 0x04800000) {
- ImplicitShift = 4;
- assert(((Value & 0xF) == 0) &&
- "128-bit LDR/STR not 16-byte aligned.");
- }
- break;
- case 1:
- assert(((Value & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned.");
- case 2:
- assert(((Value & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned.");
- case 3:
- assert(((Value & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned.");
- }
- // Compensate for implicit shift.
- Value >>= ImplicitShift;
- }
- // Insert the value into the instruction.
- *p = (*p & 0xFFC003FF) | ((uint32_t)(Value << 10) & 0x003FFC00);
+ encodeAddend(LocalAddress, RE.RelType, Value);
break;
}
case MachO::ARM64_RELOC_SUBTRACTOR:
case MachO::ARM64_RELOC_POINTER_TO_GOT:
case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
- llvm_unreachable("Relocation type not implemented yet!");
+ llvm_unreachable("Relocation type not yet implemented!");
case MachO::ARM64_RELOC_ADDEND:
llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by "
"processRelocationRef!");
Added: llvm/trunk/test/ExecutionEngine/RuntimeDyld/AArch64/MachO_ARM64_relocations.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/RuntimeDyld/AArch64/MachO_ARM64_relocations.s?rev=213689&view=auto
==============================================================================
--- llvm/trunk/test/ExecutionEngine/RuntimeDyld/AArch64/MachO_ARM64_relocations.s (added)
+++ llvm/trunk/test/ExecutionEngine/RuntimeDyld/AArch64/MachO_ARM64_relocations.s Tue Jul 22 16:42:55 2014
@@ -0,0 +1,54 @@
+# RUN: llvm-mc -triple=arm64-apple-ios7.0.0 -code-model=small -relocation-model=pic -filetype=obj -o %t.o %s
+# RUN: llvm-rtdyld -triple=arm64-apple-ios7.0.0 -verify -check=%s %t.o
+# RUN: rm %t.o
+
+# FIXME: Add GOT relocation tests once GOT testing is supported.
+
+ .section __TEXT,__text,regular,pure_instructions
+ .ios_version_min 7, 0
+ .globl foo
+ .align 2
+foo:
+ movz w0, #0
+ ret
+
+ .globl _test_branch_reloc
+ .align 2
+
+
+# Test ARM64_RELOC_BRANCH26 relocation. The branch instruction only encodes 26
+# bits of the 28-bit possible branch range. The lower two bits are always zero
+# and therefore ignored.
+# rtdyld-check: decode_operand(br1, 0)[25:0] = (foo-br1)[27:2]
+_test_branch_reloc:
+br1:
+ b foo
+ ret
+
+
+# Test ARM64_RELOC_UNSIGNED relocation. The absolute 64-bit address of the
+# function should be stored at the 8-byte memory location.
+# rtdyld-check: *{8}ptr = foo
+ .section __DATA,__data
+ .globl ptr
+ .align 3
+ .fill 8192, 1, 0
+ptr:
+ .quad foo
+
+
+# Test ARM64_RELOC_PAGE21 and ARM64_RELOC_PAGEOFF12 relocation. adrp encodes
+# the PC-relative page (4 KiB) difference between the adrp instruction and the
+# variable ptr. ldr encodes the offset of the variable within the page. The ldr
+# instruction perfroms an implicit shift on the encoded immediate (imm<<3).
+# rtdyld-check: decode_operand(adrp1, 1) = (ptr[32:12]-adrp1[32:12])
+# rtdyld-check: decode_operand(ldr1, 2) = (ptr[11:3])
+ .globl _test_adrp_ldr
+ .align 2
+_test_adrp_ldr:
+adrp1:
+ adrp x0, ptr at PAGE
+ldr1:
+ ldr x0, [x0, ptr at PAGEOFF]
+ ret
+ .fill 8192, 1, 0
Added: llvm/trunk/test/ExecutionEngine/RuntimeDyld/AArch64/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/RuntimeDyld/AArch64/lit.local.cfg?rev=213689&view=auto
==============================================================================
--- llvm/trunk/test/ExecutionEngine/RuntimeDyld/AArch64/lit.local.cfg (added)
+++ llvm/trunk/test/ExecutionEngine/RuntimeDyld/AArch64/lit.local.cfg Tue Jul 22 16:42:55 2014
@@ -0,0 +1,3 @@
+if not 'AArch64' in config.root.targets:
+ config.unsupported = True
+
More information about the llvm-commits
mailing list