[lld] 3bc7980 - [ELF] Fix branch range computation when picking ThunkSection

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Tue May 3 08:46:21 PDT 2022


Author: Fangrui Song
Date: 2022-05-03T08:46:15-07:00
New Revision: 3bc79808d06343f712728e1491f31a45383d9803

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

LOG: [ELF] Fix branch range computation when picking ThunkSection

Similar to D117734. Take AArch64 as an example when the branch range is +-0x8000000.

getISDThunkSec returns `ts` when `src-0x8000000-r_addend <= tsBase < src-0x8000000`
and the new thunk will be placed in `ts` (`ts->addThunk(t)`). However, the new
thunk (at the end of ts) may be unreachable from src. In the next pass,
`normalizeExistingThunk` reverts the relocation back to the original target.
Then a new thunk is created and the same `ts` is picked as before. The `ts` is
still unreachable.

I have observed it in one test with a sufficiently large r_addend (47664): there
are initially 245 Thunk's, then in each pass 14 new Thunk's are created and get
appended to the unreachable ThunkSection. After 15 passes lld fails with
`thunk creation not converged`.

The new test aarch64-thunk-reuse2.s checks the case.

Without `- pcBias`, arm-thumb-thunk-empty-pass.s and arm-thunk-multipass-plt.s
will fail.

Reviewed By: peter.smith

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

Added: 
    lld/test/ELF/aarch64-thunk-reuse2.s

Modified: 
    lld/ELF/Relocations.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index ed1f2168170d8..0ba761728442d 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1862,6 +1862,19 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> outputSections) {
       });
 }
 
+static int64_t getPCBias(RelType type) {
+  if (config->emachine != EM_ARM)
+    return 0;
+  switch (type) {
+  case R_ARM_THM_JUMP19:
+  case R_ARM_THM_JUMP24:
+  case R_ARM_THM_CALL:
+    return 4;
+  default:
+    return 8;
+  }
+}
+
 // Find or create a ThunkSection within the InputSectionDescription (ISD) that
 // is in range of Src. An ISD maps to a range of InputSections described by a
 // linker script section pattern such as { .text .text.* }.
@@ -1870,10 +1883,12 @@ ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *os,
                                            InputSectionDescription *isd,
                                            const Relocation &rel,
                                            uint64_t src) {
+  // See the comment in getThunk for -pcBias below.
+  const int64_t pcBias = getPCBias(rel.type);
   for (std::pair<ThunkSection *, uint32_t> tp : isd->thunkSections) {
     ThunkSection *ts = tp.first;
-    uint64_t tsBase = os->addr + ts->outSecOff + rel.addend;
-    uint64_t tsLimit = tsBase + ts->getSize() + rel.addend;
+    uint64_t tsBase = os->addr + ts->outSecOff - pcBias;
+    uint64_t tsLimit = tsBase + ts->getSize();
     if (target->inBranchRange(rel.type, src,
                               (src > tsLimit) ? tsBase : tsLimit))
       return ts;
@@ -2024,19 +2039,6 @@ static bool isThunkSectionCompatible(InputSection *source,
   return true;
 }
 
-static int64_t getPCBias(RelType type) {
-  if (config->emachine != EM_ARM)
-    return 0;
-  switch (type) {
-  case R_ARM_THM_JUMP19:
-  case R_ARM_THM_JUMP24:
-  case R_ARM_THM_CALL:
-    return 4;
-  default:
-    return 8;
-  }
-}
-
 std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
                                                 Relocation &rel, uint64_t src) {
   std::vector<Thunk *> *thunkVec = nullptr;

diff  --git a/lld/test/ELF/aarch64-thunk-reuse2.s b/lld/test/ELF/aarch64-thunk-reuse2.s
new file mode 100644
index 0000000000000..6495f8a5284b5
--- /dev/null
+++ b/lld/test/ELF/aarch64-thunk-reuse2.s
@@ -0,0 +1,38 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o
+# RUN: ld.lld -pie -Ttext=0x10300 %t.o -o %t
+# RUN: llvm-objdump -d --no-show-raw-insn --disassemble-symbols=dest,__AArch64ADRPThunk_,high %t | FileCheck %s
+
+## We create initial ThunkSection before the gap. Because the ThunkSection
+## selection code isn't so precise, we may create an unused thunk there (0x10704).
+## In the next pass we will create a ThunkSection after the gap. There used to be
+## a bug reusing the first ThunkSection (unreachable) due to the large r_addend.
+# CHECK:       <dest>:
+# CHECK-NEXT:     10700:       ret
+# CHECK:       <__AArch64ADRPThunk_>:
+# CHECK-NEXT:     10704:       adrp    x16, 0x10000
+# CHECK-NEXT:                  add     x16, x16, #1792
+# CHECK-NEXT:                  br      x16
+# CHECK-EMPTY:
+# CHECK:       <__AArch64ADRPThunk_>:
+# CHECK-NEXT:   8010710:       adrp    x16, 0x10000
+# CHECK-NEXT:                  add     x16, x16, #1792
+# CHECK-NEXT:                  br      x16
+# CHECK-LABEL: <high>:
+# CHECK-NEXT:   801071c:       bl      0x8010710 <__AArch64ADRPThunk_>
+# CHECK-NEXT:                  b       0x8010710 <__AArch64ADRPThunk_>
+
+.section .text._start, "ax", %progbits
+.globl _start
+_start:
+.space 0x400
+dest:
+  ret
+
+.section .text.gap, "ax", %progbits
+.space 0x8000000
+
+.section .text.high, "ax", %progbits
+high:
+  bl dest
+  b dest


        


More information about the llvm-commits mailing list