[lld] [LLD][ELF] Do not reuse thunks in OVERLAYs (PR #200415)

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 1 07:02:43 PDT 2026


https://github.com/smithp35 updated https://github.com/llvm/llvm-project/pull/200415

>From 90efedb1997b0205a39d0f4d0f7668b57eab6d93 Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.smith at arm.com>
Date: Fri, 29 May 2026 15:06:08 +0100
Subject: [PATCH 1/2] [LLD][ELF] Do not reuse thunks in OVERLAYs

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.

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.
---
 lld/ELF/Relocations.cpp                | 16 ++++-
 lld/test/ELF/arm-thunk-overlay-reuse.s | 89 ++++++++++++++++++++++++++
 2 files changed, 104 insertions(+), 1 deletion(-)
 create mode 100644 lld/test/ELF/arm-thunk-overlay-reuse.s

diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index ac7752a423440..f94ca80a81e1b 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1788,6 +1788,19 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *os,
   return ts;
 }
 
+static bool isThunkSectionCompatible(InputSection *source,
+                                     SectionBase *target) {
+  OutputSection *sourceOS = source->getOutputSection();
+  OutputSection *targetOS = target->getOutputSection();
+  assert(sourceOS && targetOS);
+  // Thunks in a different Overlay Output Section can't be reused
+  // as we can't guarantee that the Overlay will be in memory.
+  if (sourceOS != targetOS && targetOS->inOverlay)
+    return false;
+
+  return true;
+}
+
 std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
                                                 Relocation &rel, uint64_t src) {
   SmallVector<std::unique_ptr<Thunk>, 0> *thunkVec = nullptr;
@@ -1812,7 +1825,8 @@ 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->getThunkTargetSym()->section) &&
+        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/arm-thunk-overlay-reuse.s b/lld/test/ELF/arm-thunk-overlay-reuse.s
new file mode 100644
index 0000000000000..1d42e1cbc4320
--- /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 different 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: 00001000 <_start>:
+// CHECK-NEXT: 1000: bl 0x1004
+// CHECK-LABEL 00001004 <__Thumbv4ABSLongThunk_far>:
+
+// CHECK-LABEL: 00002000 <over1>:
+// CHECK-NEXT: 2000: bl 0x1004
+// CHECK-NEXT:       bl 0x200c
+// CHECK-NEXT:       bl 0x200c
+// CHECK-LABEL: 0000200c <__Thumbv4ABSLongThunk_far2>:
+
+// CHECK-LABEL: 00002000 <over2>:
+// CHECK-NEXT: 2000: bl 0x1004
+// CHECK-NEXT:       bl 0x2010
+// CHECK-NEXT:       bl 0x2010
+// CHECK-LABEL: 00002010 <__Thumbv4ABSLongThunk_far2>:
+
+// CHECK-LABEL: 00003000 <nonover>:
+// CHECK-NEXT: 3000: bl 0x3004
+// CHECK-LABEL: 00003004 <__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) }
+}

>From 8503093d67f8ca8cd7fc6a45d87bd55b0fe45387 Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.smith at arm.com>
Date: Mon, 1 Jun 2026 14:49:00 +0100
Subject: [PATCH 2/2] [LLD][ELF] Review comments, allow prefix thunks to be
 reused.

Review Comment Changes:
* Added in missing colon in test.
* Consolidated in one return statement.

Additional Changes:
Always allow thunks that are a prefix of the target section to be
reused. These are logically alterntative entry points. Add a new
test to check this.
---
 lld/ELF/Relocations.cpp                       | 18 +++--
 .../ELF/aarch64-thunk-bti-overlay-reuse.s     | 70 +++++++++++++++++++
 lld/test/ELF/arm-thunk-overlay-reuse.s        |  2 +-
 3 files changed, 82 insertions(+), 8 deletions(-)
 create mode 100644 lld/test/ELF/aarch64-thunk-bti-overlay-reuse.s

diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index f94ca80a81e1b..8e093b718c6bb 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1788,17 +1788,21 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *os,
   return ts;
 }
 
-static bool isThunkSectionCompatible(InputSection *source,
-                                     SectionBase *target) {
+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 different Overlay Output Section can't be reused
   // as we can't guarantee that the Overlay will be in memory.
-  if (sourceOS != targetOS && targetOS->inOverlay)
-    return false;
-
-  return true;
+  return (source->getOutputSection() == targetOS->getOutputSection() ||
+          !targetOS->inOverlay);
 }
 
 std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
@@ -1825,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 (isThunkSectionCompatible(isec, t->getThunkTargetSym()->section) &&
+    if (isThunkSectionCompatible(isec, *t) &&
         t->isCompatibleWith(*isec, rel) &&
         ctx.target->inBranchRange(rel.type, src,
                                   t->getThunkTargetSym()->getVA(ctx, -pcBias)))
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 different 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
index 1d42e1cbc4320..7aca0274cb8e5 100644
--- a/lld/test/ELF/arm-thunk-overlay-reuse.s
+++ b/lld/test/ELF/arm-thunk-overlay-reuse.s
@@ -10,7 +10,7 @@
 
 // CHECK-LABEL: 00001000 <_start>:
 // CHECK-NEXT: 1000: bl 0x1004
-// CHECK-LABEL 00001004 <__Thumbv4ABSLongThunk_far>:
+// CHECK-LABEL: 00001004 <__Thumbv4ABSLongThunk_far>:
 
 // CHECK-LABEL: 00002000 <over1>:
 // CHECK-NEXT: 2000: bl 0x1004



More information about the llvm-commits mailing list