[lld] 651afa8 - [LLD][ELF] Do not reuse thunks in OVERLAYs (#200415)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 10 03:03:32 PDT 2026


Author: Peter Smith
Date: 2026-06-10T11:03:28+01:00
New Revision: 651afa86119fd138488490862d1418eb40a43473

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

LOG: [LLD][ELF] Do not reuse thunks in OVERLAYs (#200415)

We cannot guarantee that a thunk in an OVERLAY will be in memory at the
same time as the caller if the caller is not in the same output section.
It is safe for a caller in an OVERLAY to reuse a thunk in a non-OVERLAY
section as we know that will be in memory. Thunks that are placed
before their target, are alternative entry points and can also be reused.

Resurrect the isThunkSectionCompatible function that was recently
removed as it served a similar purpose for thunks in different
partitions.

Potentially fixes #199966 which mentions a similar problem for sections
assigned to TCM (Tightly Coupled Memory). It should be possible to model
a TCM as an OVERLAY. If not then there may need to be a command-line
option to inhibit thunk sharing across output sections.

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

Modified: 
    lld/ELF/Relocations.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index ac7752a423440..0338754c9c32f 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1788,6 +1788,23 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *os,
   return ts;
 }
 
+static bool isThunkSectionCompatible(InputSection *source, Thunk &thunk) {
+  // Thunks that precede their target section are logically an alternative entry
+  // point and can always compatible.
+  if (thunk.getTargetInputSection())
+    return true;
+
+  SectionBase *target = thunk.getThunkTargetSym()->section;
+  OutputSection *sourceOS = source->getOutputSection();
+  OutputSection *targetOS = target->getOutputSection();
+  assert(sourceOS && targetOS);
+
+  // Thunks in a 
diff erent Overlay Output Section can't be reused
+  // as we can't guarantee that the Overlay will be in memory.
+  return (source->getOutputSection() == targetOS->getOutputSection() ||
+          !targetOS->inOverlay);
+}
+
 std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
                                                 Relocation &rel, uint64_t src) {
   SmallVector<std::unique_ptr<Thunk>, 0> *thunkVec = nullptr;
@@ -1812,7 +1829,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
 
   // Check existing Thunks for Sym to see if they can be reused
   for (auto &t : *thunkVec)
-    if (t->isCompatibleWith(*isec, rel) &&
+    if (isThunkSectionCompatible(isec, *t) && t->isCompatibleWith(*isec, rel) &&
         ctx.target->inBranchRange(rel.type, src,
                                   t->getThunkTargetSym()->getVA(ctx, -pcBias)))
       return std::make_pair(t.get(), false);

diff  --git a/lld/test/ELF/aarch64-thunk-bti-overlay-reuse.s b/lld/test/ELF/aarch64-thunk-bti-overlay-reuse.s
new file mode 100644
index 0000000000000..9340586ce5d82
--- /dev/null
+++ b/lld/test/ELF/aarch64-thunk-bti-overlay-reuse.s
@@ -0,0 +1,70 @@
+// REQUIRES: aarch64
+// RUN: rm -rf %t && split-file %s %t && cd %t
+// RUN: llvm-mc -filetype=obj -triple=aarch64 a.s -o a.o
+// RUN: ld.lld --script=overlay.ld a.o -o overlay --pic-veneer --print-map
+// RUN: llvm-objdump -d --no-show-raw-insn overlay | FileCheck %s
+
+/// A range extension thunk in a 
diff erent overlay should not be shared as we
+/// cannot guarantee it is in memory. However some thunks, like the BTI
+/// landing pads are logically alterative entry points for functions so will
+/// be in memory if the target is in memory.
+
+/// Expect 3 range extension thunks, one per overlay and 1 for the .text
+/// section following. However we only want 1 BTI landing pad thunk at
+/// the destination.
+
+CHECK-LABEL: 0000000000001000 <.text.over.01>:
+CHECK-NEXT: 1000: bl 0x1004
+CHECK-LABEL: 0000000000001004 <__AArch64ADRPThunk_>:
+
+CHECK-LABEL: 0000000000001000 <.text.over.02>:
+CHECK-NEXT: 1000: bl 0x1008
+CHECK-LABEL: 0000000000001008 <__AArch64ADRPThunk_>:
+
+CHECK-LABEL: 0000000080000000 <__AArch64BTIThunk_>:
+CHECk-NEXT: 80000000: bti     c
+CHECK-LABEL: 0000000080000004 <far>:
+
+//--- a.s
+ .section ".note.gnu.property", "a"
+ .p2align 3
+ .long 4
+ .long 0x10
+ .long 0x5
+ .asciz "GNU"
+
+/// Enable BTI.
+ .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND.
+ .long 4
+ .long 1          // GNU_PROPERTY_AARCH64_FEATURE_1_BTI.
+ .long 0
+
+ .section .text.over.01, "ax", %progbits
+ bl far
+
+ .section .text.over.02, "ax", %progbits
+ bl far
+ // So thunk in overlay can be distinguished by address.
+ nop
+
+ .global _start
+ .section .text
+_start:
+ bl far
+
+ .section .text.far, "ax", %progbits
+far:
+ ret
+
+//--- overlay.ld
+
+SECTIONS {
+  OVERLAY 0x1000 : {
+    .text.over.01   { *(.text.over.01) }
+    .text.over.02   { *(.text.over.02) }
+  }
+	.text 0x2000 : { *(.text) }
+  OVERLAY 0x80000000 : {
+    .text.far { *(.text.far) }
+  }
+}

diff  --git a/lld/test/ELF/arm-thunk-overlay-reuse.s b/lld/test/ELF/arm-thunk-overlay-reuse.s
new file mode 100644
index 0000000000000..b904f9bd1b6b4
--- /dev/null
+++ b/lld/test/ELF/arm-thunk-overlay-reuse.s
@@ -0,0 +1,89 @@
+// REQUIRES: arm
+// RUN: rm -rf %t && split-file %s %t && cd %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv4t-none-eabi a.s -o a.o
+// RUN: ld.lld a.o -T overlay.ld -o overlay
+// RUN: llvm-objdump -d --no-show-raw-insn overlay | FileCheck %s
+
+/// A thunk in a 
diff erent overlay should not be shared as we cannot guarantee it
+/// is in memory. It is OK for an overlay to share a thunk in a non-overlay as
+/// that will be in memory.
+
+// CHECK-LABEL: <_start>:
+// CHECK-NEXT: 1000: bl 0x1004
+// CHECK-LABEL: <__Thumbv4ABSLongThunk_far>:
+
+// CHECK-LABEL: <over1>:
+// CHECK-NEXT: 2000: bl 0x1004
+// CHECK-NEXT:       bl 0x200c
+// CHECK-NEXT:       bl 0x200c
+// CHECK-LABEL: <__Thumbv4ABSLongThunk_far2>:
+
+// CHECK-LABEL: <over2>:
+// CHECK-NEXT: 2000: bl 0x1004
+// CHECK-NEXT:       bl 0x2010
+// CHECK-NEXT:       bl 0x2010
+// CHECK-LABEL: <__Thumbv4ABSLongThunk_far2>:
+
+// CHECK-LABEL: <nonover>:
+// CHECK-NEXT: 3000: bl 0x3004
+// CHECK-LABEL: <__Thumbv4ABSLongThunk_far2>:
+
+//--- a.s
+ .thumb
+ .global _start
+ .type _start, %function
+ .section .text.00, "ax", %progbits
+
+_start:
+ bl far
+
+ .section .text.over.01, "ax", %progbits
+ .global over1
+ .type over1, %function
+over1:
+/// Expect reuse of non-overlay .text.00 thunk.
+ bl far
+/// Expect generation of one thunk for Overlay.
+ bl far2
+ bl far2
+
+ .section .text.over.02, "ax", %progbits
+ .global over2
+ .type over2, %function
+over2:
+/// Expect reuse of non-overlay .text.00 thunk.
+ bl far
+/// Expect generation of one thunk for Overlay.
+ bl far2
+ bl far2
+/// Add gap so we can distinguish the thunk by address.
+ nop
+ nop
+
+ .section .text.02, "ax", %progbits
+ .global nonover
+ .type nonover, %function
+/// Expect another thunk for far2 as we cannot reuse one in an overlay.
+nonover:
+ bl far2
+
+
+ .section .text.far, "ax", %progbits
+ .global far
+ .type far, %function
+ .global far2
+ .type far2 %function
+far:	bx lr
+far2:	bx lr
+
+//--- overlay.ld
+
+SECTIONS {
+  .text.01 0x1000 : { *(.text.00) }
+  OVERLAY 0x2000 : {
+    .text.over.01   { *(.text.over.01) }
+    .text.over.02   { *(.text.over.02) }
+  }
+  .text.02 0x3000 : { *(.text.02) }
+  .text.03 0x80000000 : { *(.text.far) }
+}


        


More information about the llvm-commits mailing list