[PATCH] D104905: [LLD][ELF][ARM] Fix case of patched unrelocated BLX

Peter Smith via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 25 03:10:05 PDT 2021


peter.smith created this revision.
peter.smith added reviewers: ikudrin, MaskRay, grimar.
Herald added subscribers: danielkiss, kristof.beyls, arichardson, emaste.
peter.smith requested review of this revision.

There are a couple of problems with the code to patch unrelocated BLX instructions:

- The calculation of the PC needs to take into account the alignment of the instruction. The Thumb BLX uses alignDown(PC, 4) for the source address.
- The calculation of the PC bias is hard-coded to 4 which works for Thumb, but when there is a BLX the branch will be in Arm state so it needs an 8 byte PC bias.

No asssembler generates an unrelocated BLX instruction so these problems do not affect real world programs. However we should still fix them.

Depends on D104701 <https://reviews.llvm.org/D104701> for objdump output of BLX


https://reviews.llvm.org/D104905

Files:
  lld/ELF/ARMErrataFix.cpp
  lld/test/ELF/arm-fix-cortex-a8-blx.s


Index: lld/test/ELF/arm-fix-cortex-a8-blx.s
===================================================================
--- lld/test/ELF/arm-fix-cortex-a8-blx.s
+++ lld/test/ELF/arm-fix-cortex-a8-blx.s
@@ -30,4 +30,4 @@
 // CHECK-PATCH:         21ffa:          nop.w
 // CHECK-PATCH-NEXT:    21ffe:          blx     0x22004 <__CortexA8657417_21FFE>
 // CHECK-PATCH:      00022004 <__CortexA8657417_21FFE>:
-// CHECK-PATCH-NEXT:    22004:          b       0x21004 <{{.+}}> @ imm = #-4104
+// CHECK-PATCH-NEXT:    22004:          b       0x21000 <_start>
Index: lld/ELF/ARMErrataFix.cpp
===================================================================
--- lld/ELF/ARMErrataFix.cpp
+++ lld/ELF/ARMErrataFix.cpp
@@ -164,6 +164,15 @@
     offset = target->getImplicitAddend(buf, R_ARM_THM_JUMP24);
   else
     offset = target->getImplicitAddend(buf, R_ARM_THM_CALL);
+  // A BLX instruction from Thumb to Arm may have an address that is
+  // not 4-byte aligned. As Arm instructions are always 4-byte aligned
+  // the instruction is calculated (from Arm ARM):
+  // targetAddress = Align(PC, 4) + imm32
+  // where
+  //   Align(x, y) = y * (x Div y)
+  // which corresponds to alignDown.
+  if (isBLX(instr))
+    sourceAddr = alignDown(sourceAddr, 4);
   return sourceAddr + offset + 4;
 }
 
@@ -185,7 +194,11 @@
   // We cannot use the instruction in the patchee section as this will have
   // been altered to point to us!
   uint64_t s = getThumbDestAddr(getBranchAddr(), instr);
-  uint64_t p = getVA(4);
+  // A BLX changes the state of the branch in the patch to Arm state, which
+  // has a PC Bias of 8, whereas in all other cases the branch is in Thumb
+  // state with a PC Bias of 4.
+  uint64_t pcBias = isBLX(instr) ? 8 : 4;
+  uint64_t p = getVA(pcBias);
   target->relocateNoSym(buf, isARM ? R_ARM_JUMP24 : R_ARM_THM_JUMP24, s - p);
 }
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D104905.354458.patch
Type: text/x-patch
Size: 1847 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210625/8325db41/attachment.bin>


More information about the llvm-commits mailing list