[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