[lld] dd4d3f7 - [LLD][ELF][ARM] Fix case of patched unrelocated BLX

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 30 06:08:06 PDT 2021


Author: Peter Smith
Date: 2021-06-30T14:07:35+01:00
New Revision: dd4d3f74062c64d57a5881dceac028ec6c231b73

URL: https://github.com/llvm/llvm-project/commit/dd4d3f74062c64d57a5881dceac028ec6c231b73
DIFF: https://github.com/llvm/llvm-project/commit/dd4d3f74062c64d57a5881dceac028ec6c231b73.diff

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

There are a couple of problems with the code to patch
unrelocated BLX instructions:
1. 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.
2. 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.

Differential Revision: https://reviews.llvm.org/D104905

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/lld/ELF/ARMErrataFix.cpp b/lld/ELF/ARMErrataFix.cpp
index 86b822f02fd55..77623780ffa5a 100644
--- a/lld/ELF/ARMErrataFix.cpp
+++ b/lld/ELF/ARMErrataFix.cpp
@@ -164,6 +164,15 @@ static uint64_t getThumbDestAddr(uint64_t sourceAddr, uint32_t instr) {
     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 @@ void Patch657417Section::writeTo(uint8_t *buf) {
   // 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);
 }
 

diff  --git a/lld/test/ELF/arm-fix-cortex-a8-blx.s b/lld/test/ELF/arm-fix-cortex-a8-blx.s
index 6000f0f3dfcbf..10c9d2aeb4685 100644
--- a/lld/test/ELF/arm-fix-cortex-a8-blx.s
+++ b/lld/test/ELF/arm-fix-cortex-a8-blx.s
@@ -30,4 +30,4 @@ _start:
 // 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>


        


More information about the llvm-commits mailing list