[lld] [LLD][AArch64][ARM] Delay adding long thunk mapping symbols (PR #116975)

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 21 05:42:20 PST 2024


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

>From ac419d73bdecd8bdfa21bba97b03ea7655d20807 Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.smith at arm.com>
Date: Wed, 20 Nov 2024 09:28:33 +0000
Subject: [PATCH 1/2] [LLD][AArch64][ARM] Delay adding long thunk mapping
 symbols

When we create a thunk we don't know whether it will be short or
long. Move the emission of the long thunk mapping symbol to
when we transition to a long thunk. This improves disassembly and
binary analysis as tools like BOLT identify thunks by disassembly.
---
 lld/ELF/Thunks.cpp                         | 153 +++++++++++++++++----
 lld/test/ELF/aarch64-thunk-bti-multipass.s |   8 +-
 2 files changed, 127 insertions(+), 34 deletions(-)

diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp
index 4f04c33f0e5c5a..6134f403eaee46 100644
--- a/lld/ELF/Thunks.cpp
+++ b/lld/ELF/Thunks.cpp
@@ -69,6 +69,7 @@ class AArch64Thunk : public Thunk {
 private:
   bool mayUseShortThunk = true;
   virtual void writeLong(uint8_t *buf) = 0;
+  virtual void addLongMapSyms() {}
 };
 
 // AArch64 long range Thunks.
@@ -82,6 +83,8 @@ class AArch64ABSLongThunk final : public AArch64Thunk {
 
 private:
   void writeLong(uint8_t *buf) override;
+  void addLongMapSyms() override;
+  ThunkSection *tsec = nullptr;
 };
 
 class AArch64ADRPThunk final : public AArch64Thunk {
@@ -148,6 +151,7 @@ class ARMThunk : public Thunk {
   // can create layout oscillations in certain corner cases which would prevent
   // the layout from converging.
   bool mayUseShortThunk = true;
+  virtual void addLongMapSyms() {}
 };
 
 // Base class for Thumb-2 thunks.
@@ -176,6 +180,7 @@ class ThumbThunk : public Thunk {
 private:
   // See comment in ARMThunk above.
   bool mayUseShortThunk = true;
+  virtual void addLongMapSyms() {}
 };
 
 // Specific ARM Thunk implementations. The naming convention is:
@@ -229,6 +234,10 @@ class ThumbV6MABSLongThunk final : public ThumbThunk {
   uint32_t sizeLong() override { return 12; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
+
+private:
+  void addLongMapSyms() override;
+  ThunkSection *tsec = nullptr;
 };
 
 class ThumbV6MABSXOLongThunk final : public ThumbThunk {
@@ -249,6 +258,10 @@ class ThumbV6MPILongThunk final : public ThumbThunk {
   uint32_t sizeLong() override { return 16; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
+
+private:
+  void addLongMapSyms() override;
+  ThunkSection *tsec = nullptr;
 };
 
 // Architectures v4, v5 and v6 do not support the movt/movw instructions. v5 and
@@ -267,6 +280,10 @@ class ARMV5LongLdrPcThunk final : public ARMThunk {
   uint32_t sizeLong() override { return 8; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
+
+private:
+  void addLongMapSyms() override;
+  ThunkSection *tsec = nullptr;
 };
 
 // Implementations of Thunks for v4. BLX is not supported, and loads
@@ -279,6 +296,10 @@ class ARMV4PILongBXThunk final : public ARMThunk {
   uint32_t sizeLong() override { return 16; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
+
+private:
+  void addLongMapSyms() override;
+  ThunkSection *tsec = nullptr;
 };
 
 class ARMV4PILongThunk final : public ARMThunk {
@@ -289,6 +310,10 @@ class ARMV4PILongThunk final : public ARMThunk {
   uint32_t sizeLong() override { return 12; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
+
+private:
+  void addLongMapSyms() override;
+  ThunkSection *tsec = nullptr;
 };
 
 class ThumbV4PILongBXThunk final : public ThumbThunk {
@@ -299,6 +324,10 @@ class ThumbV4PILongBXThunk final : public ThumbThunk {
   uint32_t sizeLong() override { return 16; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
+
+private:
+  void addLongMapSyms() override;
+  ThunkSection *tsec = nullptr;
 };
 
 class ThumbV4PILongThunk final : public ThumbThunk {
@@ -309,6 +338,10 @@ class ThumbV4PILongThunk final : public ThumbThunk {
   uint32_t sizeLong() override { return 20; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
+
+private:
+  void addLongMapSyms() override;
+  ThunkSection *tsec = nullptr;
 };
 
 class ARMV4ABSLongBXThunk final : public ARMThunk {
@@ -319,6 +352,10 @@ class ARMV4ABSLongBXThunk final : public ARMThunk {
   uint32_t sizeLong() override { return 12; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
+
+private:
+  void addLongMapSyms() override;
+  ThunkSection *tsec = nullptr;
 };
 
 class ThumbV4ABSLongBXThunk final : public ThumbThunk {
@@ -329,6 +366,10 @@ class ThumbV4ABSLongBXThunk final : public ThumbThunk {
   uint32_t sizeLong() override { return 12; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
+
+private:
+  void addLongMapSyms() override;
+  ThunkSection *tsec = nullptr;
 };
 
 class ThumbV4ABSLongThunk final : public ThumbThunk {
@@ -339,6 +380,10 @@ class ThumbV4ABSLongThunk final : public ThumbThunk {
   uint32_t sizeLong() override { return 16; }
   void writeLong(uint8_t *buf) override;
   void addSymbols(ThunkSection &isec) override;
+
+private:
+  void addLongMapSyms() override;
+  ThunkSection *tsec = nullptr;
 };
 
 // The AVR devices need thunks for R_AVR_LO8_LDI_GS/R_AVR_HI8_LDI_GS
@@ -560,6 +605,8 @@ bool AArch64Thunk::getMayUseShortThunk() {
   uint64_t s = getAArch64ThunkDestVA(ctx, destination, addend);
   uint64_t p = getThunkTargetSym()->getVA(ctx);
   mayUseShortThunk = llvm::isInt<28>(s - p);
+  if (!mayUseShortThunk)
+    addLongMapSyms();
   return mayUseShortThunk;
 }
 
@@ -602,8 +649,12 @@ void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
   addSymbol(ctx.saver.save("__AArch64AbsLongThunk_" + destination.getName()),
             STT_FUNC, 0, isec);
   addSymbol("$x", STT_NOTYPE, 0, isec);
-  if (!getMayUseShortThunk())
-    addSymbol("$d", STT_NOTYPE, 8, isec);
+  tsec = &isec;
+  (void)getMayUseShortThunk();
+}
+
+void AArch64ABSLongThunk::addLongMapSyms() {
+  addSymbol("$d", STT_NOTYPE, 8, *tsec);
 }
 
 // This Thunk has a maximum range of 4Gb, this is sufficient for all programs
@@ -691,11 +742,14 @@ bool ARMThunk::getMayUseShortThunk() {
   uint64_t s = getARMThunkDestVA(ctx, destination);
   if (s & 1) {
     mayUseShortThunk = false;
+    addLongMapSyms();
     return false;
   }
   uint64_t p = getThunkTargetSym()->getVA(ctx);
   int64_t offset = s - p - 8;
   mayUseShortThunk = llvm::isInt<26>(offset);
+  if (!mayUseShortThunk)
+    addLongMapSyms();
   return mayUseShortThunk;
 }
 
@@ -729,16 +783,19 @@ bool ARMThunk::isCompatibleWith(const InputSection &isec,
 //    (see comment for mayUseShortThunk)
 // && the arch supports Thumb branch range extension.
 bool ThumbThunk::getMayUseShortThunk() {
-  if (!mayUseShortThunk || !ctx.arg.armJ1J2BranchEncoding)
+  if (!mayUseShortThunk)
     return false;
   uint64_t s = getARMThunkDestVA(ctx, destination);
-  if ((s & 1) == 0) {
+  if ((s & 1) == 0 || !ctx.arg.armJ1J2BranchEncoding) {
     mayUseShortThunk = false;
+    addLongMapSyms();
     return false;
   }
   uint64_t p = getThunkTargetSym()->getVA(ctx) & ~1;
   int64_t offset = s - p - 4;
   mayUseShortThunk = llvm::isInt<25>(offset);
+  if (!mayUseShortThunk)
+    addLongMapSyms();
   return mayUseShortThunk;
 }
 
@@ -856,8 +913,12 @@ void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
   addSymbol(ctx.saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
             STT_FUNC, 1, isec);
   addSymbol("$t", STT_NOTYPE, 0, isec);
-  if (!getMayUseShortThunk())
-    addSymbol("$d", STT_NOTYPE, 8, isec);
+  tsec = &isec;
+  (void)getMayUseShortThunk();
+}
+
+void ThumbV6MABSLongThunk::addLongMapSyms() {
+  addSymbol("$d", STT_NOTYPE, 8, *tsec);
 }
 
 void ThumbV6MABSXOLongThunk::writeLong(uint8_t *buf) {
@@ -912,8 +973,12 @@ void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
   addSymbol(ctx.saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
             STT_FUNC, 1, isec);
   addSymbol("$t", STT_NOTYPE, 0, isec);
-  if (!getMayUseShortThunk())
-    addSymbol("$d", STT_NOTYPE, 12, isec);
+  tsec = &isec;
+  (void)getMayUseShortThunk();
+}
+
+void ThumbV6MPILongThunk::addLongMapSyms() {
+  addSymbol("$d", STT_NOTYPE, 12, *tsec);
 }
 
 void ARMV5LongLdrPcThunk::writeLong(uint8_t *buf) {
@@ -927,8 +992,12 @@ void ARMV5LongLdrPcThunk::addSymbols(ThunkSection &isec) {
   addSymbol(ctx.saver.save("__ARMv5LongLdrPcThunk_" + destination.getName()),
             STT_FUNC, 0, isec);
   addSymbol("$a", STT_NOTYPE, 0, isec);
-  if (!getMayUseShortThunk())
-    addSymbol("$d", STT_NOTYPE, 4, isec);
+  tsec = &isec;
+  (void)getMayUseShortThunk();
+}
+
+void ARMV5LongLdrPcThunk::addLongMapSyms() {
+  addSymbol("$d", STT_NOTYPE, 4, *tsec);
 }
 
 void ARMV4ABSLongBXThunk::writeLong(uint8_t *buf) {
@@ -943,8 +1012,12 @@ void ARMV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
   addSymbol(ctx.saver.save("__ARMv4ABSLongBXThunk_" + destination.getName()),
             STT_FUNC, 0, isec);
   addSymbol("$a", STT_NOTYPE, 0, isec);
-  if (!getMayUseShortThunk())
-    addSymbol("$d", STT_NOTYPE, 8, isec);
+  tsec = &isec;
+  (void)getMayUseShortThunk();
+}
+
+void ARMV4ABSLongBXThunk::addLongMapSyms() {
+  addSymbol("$d", STT_NOTYPE, 8, *tsec);
 }
 
 void ThumbV4ABSLongBXThunk::writeLong(uint8_t *buf) {
@@ -961,9 +1034,13 @@ void ThumbV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
   addSymbol(ctx.saver.save("__Thumbv4ABSLongBXThunk_" + destination.getName()),
             STT_FUNC, 1, isec);
   addSymbol("$t", STT_NOTYPE, 0, isec);
-  addSymbol("$a", STT_NOTYPE, 4, isec);
-  if (!getMayUseShortThunk())
-    addSymbol("$d", STT_NOTYPE, 8, isec);
+  tsec = &isec;
+  (void)getMayUseShortThunk();
+}
+
+void ThumbV4ABSLongBXThunk::addLongMapSyms() {
+  addSymbol("$a", STT_NOTYPE, 4, *tsec);
+  addSymbol("$d", STT_NOTYPE, 8, *tsec);
 }
 
 void ThumbV4ABSLongThunk::writeLong(uint8_t *buf) {
@@ -981,9 +1058,13 @@ void ThumbV4ABSLongThunk::addSymbols(ThunkSection &isec) {
   addSymbol(ctx.saver.save("__Thumbv4ABSLongThunk_" + destination.getName()),
             STT_FUNC, 1, isec);
   addSymbol("$t", STT_NOTYPE, 0, isec);
-  addSymbol("$a", STT_NOTYPE, 4, isec);
-  if (!getMayUseShortThunk())
-    addSymbol("$d", STT_NOTYPE, 12, isec);
+  tsec = &isec;
+  (void)getMayUseShortThunk();
+}
+
+void ThumbV4ABSLongThunk::addLongMapSyms() {
+  addSymbol("$a", STT_NOTYPE, 4, *tsec);
+  addSymbol("$d", STT_NOTYPE, 12, *tsec);
 }
 
 void ARMV4PILongBXThunk::writeLong(uint8_t *buf) {
@@ -1000,8 +1081,12 @@ void ARMV4PILongBXThunk::addSymbols(ThunkSection &isec) {
   addSymbol(ctx.saver.save("__ARMv4PILongBXThunk_" + destination.getName()),
             STT_FUNC, 0, isec);
   addSymbol("$a", STT_NOTYPE, 0, isec);
-  if (!getMayUseShortThunk())
-    addSymbol("$d", STT_NOTYPE, 12, isec);
+  tsec = &isec;
+  (void)getMayUseShortThunk();
+}
+
+void ARMV4PILongBXThunk::addLongMapSyms() {
+  addSymbol("$d", STT_NOTYPE, 12, *tsec);
 }
 
 void ARMV4PILongThunk::writeLong(uint8_t *buf) {
@@ -1017,8 +1102,12 @@ void ARMV4PILongThunk::addSymbols(ThunkSection &isec) {
   addSymbol(ctx.saver.save("__ARMv4PILongThunk_" + destination.getName()),
             STT_FUNC, 0, isec);
   addSymbol("$a", STT_NOTYPE, 0, isec);
-  if (!getMayUseShortThunk())
-    addSymbol("$d", STT_NOTYPE, 8, isec);
+  tsec = &isec;
+  (void)getMayUseShortThunk();
+}
+
+void ARMV4PILongThunk::addLongMapSyms() {
+  addSymbol("$d", STT_NOTYPE, 8, *tsec);
 }
 
 void ThumbV4PILongBXThunk::writeLong(uint8_t *buf) {
@@ -1037,9 +1126,13 @@ void ThumbV4PILongBXThunk::addSymbols(ThunkSection &isec) {
   addSymbol(ctx.saver.save("__Thumbv4PILongBXThunk_" + destination.getName()),
             STT_FUNC, 1, isec);
   addSymbol("$t", STT_NOTYPE, 0, isec);
-  addSymbol("$a", STT_NOTYPE, 4, isec);
-  if (!getMayUseShortThunk())
-    addSymbol("$d", STT_NOTYPE, 12, isec);
+  tsec = &isec;
+  (void)getMayUseShortThunk();
+}
+
+void ThumbV4PILongBXThunk::addLongMapSyms() {
+  addSymbol("$a", STT_NOTYPE, 4, *tsec);
+  addSymbol("$d", STT_NOTYPE, 12, *tsec);
 }
 
 void ThumbV4PILongThunk::writeLong(uint8_t *buf) {
@@ -1059,9 +1152,13 @@ void ThumbV4PILongThunk::addSymbols(ThunkSection &isec) {
   addSymbol(ctx.saver.save("__Thumbv4PILongThunk_" + destination.getName()),
             STT_FUNC, 1, isec);
   addSymbol("$t", STT_NOTYPE, 0, isec);
-  addSymbol("$a", STT_NOTYPE, 4, isec);
-  if (!getMayUseShortThunk())
-    addSymbol("$d", STT_NOTYPE, 16, isec);
+  tsec = &isec;
+  (void)getMayUseShortThunk();
+}
+
+void ThumbV4PILongThunk::addLongMapSyms() {
+  addSymbol("$a", STT_NOTYPE, 4, *tsec);
+  addSymbol("$d", STT_NOTYPE, 16, *tsec);
 }
 
 // Use the long jump which covers a range up to 8MiB.
diff --git a/lld/test/ELF/aarch64-thunk-bti-multipass.s b/lld/test/ELF/aarch64-thunk-bti-multipass.s
index 6569d6d00ec37f..4f0d7343cc6bfc 100644
--- a/lld/test/ELF/aarch64-thunk-bti-multipass.s
+++ b/lld/test/ELF/aarch64-thunk-bti-multipass.s
@@ -40,15 +40,11 @@ _start:
 // CHECK-LABEL: <_start>:
 // CHECK-NEXT: 10001000: bl  0x10002004 <__AArch64AbsLongThunk_fn1>
 
-/// FIXME, the 2nd ldr and udf are a result of mapping symbols being generated
-/// on Thunk insertion. When that is fixed in lld they will be data statements
-/// like in __AArch64AbsLongThunk_far below.
 // CHECK-LABEL: <__AArch64AbsLongThunk_fn1>:
 // CHECK-NEXT: 10002004: ldr     x16, 0x1000200c <__AArch64AbsLongThunk_fn1+0x8>
 // CHECK-NEXT:           br      x16
-// CHECK-NEXT:           ldr     w0, 0x1000260c <__AArch64AbsLongThunk_fn1+0x608>
-// CHECK-NEXT:           udf     #0x0
-
+// CHECK-NEXT:           00 30 00 18    .word   0x18003000
+// CHECK-NEXT:           00 00 00 00    .word   0x00000000
 
 .section .text.1, "ax", %progbits
 .balign 0x1000

>From 24b1a3db5f12ccc1463a2d60db6e4a5eba6e019f Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.smith at arm.com>
Date: Thu, 21 Nov 2024 11:51:12 +0000
Subject: [PATCH 2/2] Improve comments for addLongMapSyms

Explain why the function is needed. We don't know for certain at
creation time whether a long thunk will be written so delay the
choice until we know for certain.
---
 lld/ELF/Thunks.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp
index 6134f403eaee46..629ce356ce2e7d 100644
--- a/lld/ELF/Thunks.cpp
+++ b/lld/ELF/Thunks.cpp
@@ -69,6 +69,10 @@ class AArch64Thunk : public Thunk {
 private:
   bool mayUseShortThunk = true;
   virtual void writeLong(uint8_t *buf) = 0;
+  // A thunk may be written out as a short or long, and we may not know which
+  // type at thunk creation time. In some thunk implementations the long thunk
+  // has additional mapping symbols. Thus function can be overridden to add
+  // these additional mapping symbols.
   virtual void addLongMapSyms() {}
 };
 
@@ -151,6 +155,7 @@ class ARMThunk : public Thunk {
   // can create layout oscillations in certain corner cases which would prevent
   // the layout from converging.
   bool mayUseShortThunk = true;
+  // See comment in AArch64Thunk.
   virtual void addLongMapSyms() {}
 };
 
@@ -180,6 +185,7 @@ class ThumbThunk : public Thunk {
 private:
   // See comment in ARMThunk above.
   bool mayUseShortThunk = true;
+  // See comment in AArch64Thunk.
   virtual void addLongMapSyms() {}
 };
 



More information about the llvm-commits mailing list