[lld] c03fdd3 - [ELF] Fix the branch range computation when reusing a thunk

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 24 09:03:26 PST 2022


Author: Fangrui Song
Date: 2022-01-24T09:03:21-08:00
New Revision: c03fdd340356c9a29242975f39786529eb99f194

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

LOG: [ELF] Fix the branch range computation when reusing a thunk

Notation: dst is `t->getThunkTargetSym()->getVA()`

On AArch64, when `src-0x8000000-r_addend <= dst < src-0x8000000`, the condition
`target->inBranchRange(rel.type, src, rel.sym->getVA(rel.addend))` may
incorrectly consider a thunk reusable.
`rel.addend = -getPCBias(rel.type)` resets the addend to 0 for AArch64/PPC
and the zero addend is used by `rel.sym->getVA(rel.addend)` to check
out-of-range relocations.

See the test for a case this computation is wrong:
`error: a.o:(.text_high+0x4): relocation R_AARCH64_JUMP26 out of range: -134217732 is not in [-134217728, 134217727]`
I have seen a real world case with r_addend=19960.

Reviewed By: peter.smith

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

Added: 
    lld/test/ELF/aarch64-thunk-reuse.s
    lld/test/ELF/arm-thunk-reuse.s

Modified: 
    lld/ELF/Relocations.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 3a4cbde6ab698..074bc71509916 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -2042,7 +2042,8 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
   // out in the relocation addend. We compensate for the PC bias so that
   // an Arm and Thumb relocation to the same destination get the same keyAddend,
   // which is usually 0.
-  int64_t keyAddend = rel.addend + getPCBias(rel.type);
+  const int64_t pcBias = getPCBias(rel.type);
+  const int64_t keyAddend = rel.addend + pcBias;
 
   // We use a ((section, offset), addend) pair to find the thunk position if
   // possible so that we create only one thunk for aliased symbols or ICFed
@@ -2061,7 +2062,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
     if (isThunkSectionCompatible(isec, t->getThunkTargetSym()->section) &&
         t->isCompatibleWith(*isec, rel) &&
         target->inBranchRange(rel.type, src,
-                              t->getThunkTargetSym()->getVA(rel.addend)))
+                              t->getThunkTargetSym()->getVA(-pcBias)))
       return std::make_pair(t, false);
 
   // No existing compatible Thunk in range, create a new one

diff  --git a/lld/test/ELF/aarch64-thunk-reuse.s b/lld/test/ELF/aarch64-thunk-reuse.s
new file mode 100644
index 0000000000000..bdbd08ab5f282
--- /dev/null
+++ b/lld/test/ELF/aarch64-thunk-reuse.s
@@ -0,0 +1,49 @@
+# REQUIRES: aarch64
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %t/a.s -o %t/a.o
+# RUN: ld.lld -pie -T %t/lds %t/a.o -o %t/a
+# RUN: llvm-objdump -d --no-show-raw-insn %t/a | FileCheck %s
+
+## We create a thunk for dest.
+# CHECK-LABEL: <mid>:
+# CHECK-NEXT:   8010008:       b       0x801000c <__AArch64ADRPThunk_>
+# CHECK-EMPTY:
+# CHECK-NEXT:  <__AArch64ADRPThunk_>:
+# CHECK-NEXT:   801000c:       adrp    x16, 0x10000
+# CHECK-NEXT:                  add     x16, x16, #4
+# CHECK-NEXT:                  br      x16
+
+## The first instruction can reuse the thunk but the second can't.
+## If we reuse the thunk for b, we will get an "out of range" error.
+# CHECK-LABEL: <high>:
+# CHECK-NEXT:  1001000c:       bl      0x801000c <__AArch64ADRPThunk_>
+# CHECK-NEXT:                  b       0x10010014 <__AArch64ADRPThunk_>
+# CHECK-EMPTY:
+# CHECK-NEXT:  <__AArch64ADRPThunk_>:
+# CHECK-NEXT:  10010014:       adrp    x16, 0x10000
+# CHECK-NEXT:                  add     x16, x16, #4
+# CHECK-NEXT:                  br      x16
+
+#--- a.s
+.section .text_low, "ax", %progbits
+.globl _start
+_start:
+  nop
+dest:
+  ret
+
+.section .text_mid, "ax", %progbits
+mid:
+  b dest
+
+.section .text_high, "ax", %progbits
+high:
+  bl dest
+  b dest
+
+#--- lds
+SECTIONS {
+  .text_low 0x10000: { *(.text_low) }
+  .text_mid 0x8010008 : { *(.text_mid) }
+  .text_high 0x1001000c : { *(.text_high) }
+}

diff  --git a/lld/test/ELF/arm-thunk-reuse.s b/lld/test/ELF/arm-thunk-reuse.s
new file mode 100644
index 0000000000000..3959c3cd695f4
--- /dev/null
+++ b/lld/test/ELF/arm-thunk-reuse.s
@@ -0,0 +1,52 @@
+# REQUIRES: arm
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=armv7-a-none-eabi --arm-add-build-attributes %t/a.s -o %t/a.o
+# RUN: ld.lld -pie -T %t/lds %t/a.o -o %t/a
+# RUN: llvm-objdump -d --no-show-raw-insn %t/a | FileCheck %s
+
+## We create a thunk for dest.
+# CHECK-LABEL: <mid>:
+# CHECK-NEXT:   2010004:     b       0x2010008 <__ARMV7PILongThunk_dest>
+# CHECK-EMPTY:
+# CHECK-NEXT:  <__ARMV7PILongThunk_dest>:
+# CHECK-NEXT:   2010008:     movw    r12, #65516
+# CHECK-NEXT:                movt    r12, #65023
+# CHECK-NEXT:                add     r12, r12, pc
+# CHECK-NEXT:                bx      r12
+
+## The first instruction can reuse the thunk but the second can't.
+## If we reuse the thunk for b, we will get an "out of range" error.
+# CHECK-LABEL: <high>:
+# CHECK-NEXT:   4010000:      bl      0x2010008 <__ARMV7PILongThunk_dest>
+# CHECK-NEXT:                 b       0x4010008 <__ARMV7PILongThunk_dest>
+# CHECK-EMPTY:
+# CHECK-NEXT:  <__ARMV7PILongThunk_dest>:
+# CHECK-NEXT:   4010008:      movw    r12, #65516
+# CHECK-NEXT:                 movt    r12, #64511
+# CHECK-NEXT:                 add     r12, r12, pc
+# CHECK-NEXT:                 bx      r12
+
+#--- a.s
+.section .text_low, "ax", %progbits
+
+.globl _start
+_start:
+  nop
+dest:
+  bx lr
+
+.section .text_mid, "ax", %progbits
+mid:
+  b dest
+
+.section .text_high, "ax", %progbits
+high:
+  bl dest
+  b dest
+
+#--- lds
+SECTIONS {
+  .text_low 0x10000: { *(.text_low) }
+  .text_mid 0x2010004 : { *(.text_mid) }
+  .text_high 0x4010000 : { *(.text_high) }
+}


        


More information about the llvm-commits mailing list