[lld] [LLD][ELF][AArch64] Add BTI Aware long branch thunks (PR #108989)

Peter Smith via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 23 08:57:50 PDT 2024


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

>From 7c542b2209fae66d461b26af855ceb7bc1ba26aa Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.smith at arm.com>
Date: Tue, 3 Sep 2024 17:31:47 +0100
Subject: [PATCH 1/2] Add BTI Aware long branch thunks

When Branch Target Identification BTI is enabled all indirect
branches must target a BTI instruction. A long branch thunk
is a source of indirect branches. To date LLD has been
assuming that the object producer is responsible for putting
a BTI instruction at all places the linker might generate an
indirect branch to. This is true for clang, but not for GCC.
GCC will elide the BTI instruction when it can prove that
there are no indirect branches from outside the translation
unit(s). GNU ld was fixed to generate a landing pad stub
(gnu ld speak for thunk) for the destination when a long
range stub was needed [1].

This means that using GCC compiled objects with LLD may
lead to LLD generating an indirect branch to a location
without a BTI. The ABI [2] has also been clarified to say
that it is a static linker's responsibility to generate
a landing pad when the target does not have a BTI.

This patch implements the same mechansim as GNU ld. When
the output ELF file is setting the
GNU_PROPERTY_AARCH64_FEATURE_1_BTI property, then we check
the destination to see if it has a BTI instruction. If it
does not we generate a landing pad consisting of:
BTI c
B <destination>

The B <destination> can be elided if the thunk can be placed
so that control flow drops through. For example:
BTI c
<destination>:
This will be common when -ffunction-sections is used.

The landing pad thunks are effectively alternative entry
points for the function. Direct branches are unaffected
but any linker generated indirect branch needs to use
the alternative. We place these as close as possible
to the destination section.

There is some further optimization possible. Consider the
case:
.text
fn1
...
fn2
...

If we need landing pad thunks for both fn1 and fn2 we could
order them so that the thunk for fn1 immediately precedes fn1.
This could save a single branch. However I didn't think that
would be worth the additional complexity.

[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106671
[2] https://github.com/ARM-software/abi-aa/issues/196
---
 lld/ELF/Arch/AArch64.cpp         |  32 ++
 lld/ELF/Relocations.cpp          |  23 ++
 lld/ELF/Relocations.h            |  11 +
 lld/ELF/Target.h                 |   1 +
 lld/ELF/Thunks.cpp               | 116 ++++++-
 lld/ELF/Thunks.h                 |  11 +-
 lld/test/ELF/aarch64-thunk-bti.s | 513 +++++++++++++++++++++++++++++++
 7 files changed, 697 insertions(+), 10 deletions(-)
 create mode 100644 lld/test/ELF/aarch64-thunk-bti.s

diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 36880bf67e9f23..d56f4b4ae5136a 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -28,6 +28,38 @@ uint64_t elf::getAArch64Page(uint64_t expr) {
   return expr & ~static_cast<uint64_t>(0xFFF);
 }
 
+// A BTI landing pad is a valid target for an indirect branch
+// when the Branch Target Identification has been enabled.
+// As linker generated branches are via x16 the
+// BTI landing pads are defined as:
+// BTI C, BTI J, BTI JC, PACIASP, PACIBSP.
+bool elf::isAArch64BTILandingPad(Symbol &s, int64_t a) {
+  // PLT entries accessed indirectly have a BTI c.
+  if (s.isInPlt())
+    return true;
+  Defined *d = dyn_cast_or_null<Defined>(&s);
+  if (d == nullptr || d->section == nullptr ||
+      d->section->kind() != InputSectionBase::Regular)
+    // All places that we cannot disassemble are responsible for making
+    // the target a BTI landing pad.
+    return true;
+  InputSection *isec = cast<InputSection>(d->section);
+  int64_t off = d->value + a;
+  // Likely user error, but protect ourselves against out of bounds
+  // access.
+  if (off < 0 || static_cast<uint64_t>(off) >= isec->getSize())
+    return true;
+  const uint8_t *buf = isec->content().begin();
+  const uint32_t instr = read32le(buf + off);
+  if (instr == 0xd503233f || // PACIASP.
+      instr == 0xd503237f || // PACIBSP.
+      instr == 0xd503245f || // BTI C.
+      instr == 0xd503249f || // BTI J.
+      instr == 0xd50324df)   // BTI JC.
+    return true;
+  return false;
+}
+
 namespace {
 class AArch64 : public TargetInfo {
 public:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 6c07051a231537..b7f714bc2158b7 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -2243,6 +2243,14 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
   return std::make_pair(t, true);
 }
 
+std::pair<Thunk *, bool> ThunkCreator::getSyntheticLandingPad(Defined &d,
+                                                              int64_t a) {
+  Thunk *lp = landingPadsBySectionAndAddend[{{d.section, d.value}, a}];
+  if (lp)
+    return std::make_pair(lp, false);
+  return std::make_pair(addLandingPadThunk(d, a), true);
+}
+
 // Return true if the relocation target is an in range Thunk.
 // Return false if the relocation is not to a Thunk. If the relocation target
 // was originally to a Thunk, but is no longer in range we revert the
@@ -2326,6 +2334,21 @@ bool ThunkCreator::createThunks(uint32_t pass,
                 ts = getISDThunkSec(os, isec, isd, rel, src);
               ts->addThunk(t);
               thunks[t->getThunkTargetSym()] = t;
+
+              // When indirect branches are restricted, such as AArch64 BTI
+              // Thunks may need to target a linker generated landing pad
+              // instead of the target.
+              if (t->needsSyntheticLandingPad()) {
+                Thunk *lpt;
+                auto &dr = cast<Defined>(t->destination);
+                std::tie(lpt, isNew) = getSyntheticLandingPad(dr, t->addend);
+                if (isNew) {
+                  InputSection *targetsec = dyn_cast<InputSection>(dr.section);
+                  ts = getISThunkSec(targetsec);
+                  ts->addThunk(lpt);
+                }
+                t->landingPad = lpt->getThunkTargetSym();
+              }
             }
 
             // Redirect relocation to Thunk, we never go via the PLT to a Thunk
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index aaa4581490a285..2e53962d800fc1 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -16,6 +16,7 @@
 #include <vector>
 
 namespace lld::elf {
+class Defined;
 class Symbol;
 class InputSection;
 class InputSectionBase;
@@ -173,6 +174,8 @@ class ThunkCreator {
   std::pair<Thunk *, bool> getThunk(InputSection *isec, Relocation &rel,
                                     uint64_t src);
 
+  std::pair<Thunk *, bool> getSyntheticLandingPad(Defined &d, int64_t a);
+
   ThunkSection *addThunkSection(OutputSection *os, InputSectionDescription *,
                                 uint64_t off);
 
@@ -200,6 +203,14 @@ class ThunkCreator {
   // The Mips LA25 Thunk is an example of an inline ThunkSection.
   llvm::DenseMap<InputSection *, ThunkSection *> thunkedSections;
 
+  // Record landing pads, generated for a section + offset destination.
+  // Landling pads are alternative entry points for destinations that need
+  // to be reached via thunks that use indirect branches. A destination
+  // needs at most one landing pad as that can be reused by all callers.
+  llvm::DenseMap<std::pair<std::pair<SectionBase *, uint64_t>, int64_t>,
+                 Thunk *>
+      landingPadsBySectionAndAddend;
+
   // The number of completed passes of createThunks this permits us
   // to do one time initialization on Pass 0 and put a limit on the
   // number of times it can be called to prevent infinite loops.
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 9894fb32c503c3..3142a3ec9959d9 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -230,6 +230,7 @@ void writePrefixedInstruction(uint8_t *loc, uint64_t insn);
 void addPPC64SaveRestore();
 uint64_t getPPC64TocBase();
 uint64_t getAArch64Page(uint64_t expr);
+bool isAArch64BTILandingPad(Symbol &s, int64_t a);
 template <typename ELFT> void writeARMCmseImportLib();
 uint64_t getLoongArchPageDelta(uint64_t dest, uint64_t pc, RelType type);
 void riscvFinalizeRelax(int passes);
diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp
index 349e31332f59aa..599e053c13a6e5 100644
--- a/lld/ELF/Thunks.cpp
+++ b/lld/ELF/Thunks.cpp
@@ -51,12 +51,20 @@ namespace {
 // distance from the thunk to the target is less than 128MB. Long thunks can
 // branch to any virtual address and they are implemented in the derived
 // classes. This class tries to create a short thunk if the target is in range,
-// otherwise it creates a long thunk.
+// otherwise it creates a long thunk. When BTI is enabled indirect branches
+// must land on a BTI instruction. If the destination does not have a BTI
+// instruction mayNeedLandingPad is set to true and Thunk::landingPad points
+// to an alternative entry point with a BTI.
 class AArch64Thunk : public Thunk {
 public:
-  AArch64Thunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
+  AArch64Thunk(Symbol &dest, int64_t addend, bool mayNeedLandingPad)
+      : Thunk(dest, addend), mayNeedLandingPad(mayNeedLandingPad) {}
   bool getMayUseShortThunk();
   void writeTo(uint8_t *buf) override;
+  bool needsSyntheticLandingPad() override;
+
+protected:
+  bool mayNeedLandingPad;
 
 private:
   bool mayUseShortThunk = true;
@@ -66,8 +74,8 @@ class AArch64Thunk : public Thunk {
 // AArch64 long range Thunks.
 class AArch64ABSLongThunk final : public AArch64Thunk {
 public:
-  AArch64ABSLongThunk(Symbol &dest, int64_t addend)
-      : AArch64Thunk(dest, addend) {}
+  AArch64ABSLongThunk(Symbol &dest, int64_t addend, bool mayNeedLandingPad)
+      : AArch64Thunk(dest, addend, mayNeedLandingPad) {}
   uint32_t size() override { return getMayUseShortThunk() ? 4 : 16; }
   void addSymbols(ThunkSection &isec) override;
 
@@ -77,7 +85,8 @@ class AArch64ABSLongThunk final : public AArch64Thunk {
 
 class AArch64ADRPThunk final : public AArch64Thunk {
 public:
-  AArch64ADRPThunk(Symbol &dest, int64_t addend) : AArch64Thunk(dest, addend) {}
+  AArch64ADRPThunk(Symbol &dest, int64_t addend, bool mayNeedLandingPad)
+      : AArch64Thunk(dest, addend, mayNeedLandingPad) {}
   uint32_t size() override { return getMayUseShortThunk() ? 4 : 12; }
   void addSymbols(ThunkSection &isec) override;
 
@@ -85,6 +94,27 @@ class AArch64ADRPThunk final : public AArch64Thunk {
   void writeLong(uint8_t *buf) override;
 };
 
+// AArch64 BTI Landing Pad
+// When BTI is enabled indirect branches must land on a BTI
+// compatible instruction. When the destination does not have a
+// BTI compatible instruction a Thunk doing an indirect branch
+// targets a Landing Pad Thunk that direct branches to the target.
+class AArch64BTILandingPadThunk final : public Thunk {
+public:
+  AArch64BTILandingPadThunk(Symbol &dest, int64_t addend)
+      : Thunk(dest, addend) {}
+
+  uint32_t size() override { return getMayUseShortThunk() ? 4 : 8; }
+  void addSymbols(ThunkSection &isec) override;
+  InputSection *getTargetInputSection() const override;
+  void writeTo(uint8_t *buf) override;
+
+private:
+  bool getMayUseShortThunk();
+  void writeLong(uint8_t *buf);
+  bool mayUseShortThunk = true;
+};
+
 // Base class for ARM thunks.
 //
 // An ARM thunk may be either short or long. A short thunk is simply a branch
@@ -532,6 +562,12 @@ void AArch64Thunk::writeTo(uint8_t *buf) {
   ctx.target->relocateNoSym(buf, R_AARCH64_CALL26, s - p);
 }
 
+bool AArch64Thunk::needsSyntheticLandingPad() {
+  // Short Thunks use a direct branch, no synthetic landing pad
+  // required.
+  return mayNeedLandingPad && !getMayUseShortThunk();
+}
+
 // AArch64 long range Thunks.
 void AArch64ABSLongThunk::writeLong(uint8_t *buf) {
   const uint8_t data[] = {
@@ -540,7 +576,11 @@ void AArch64ABSLongThunk::writeLong(uint8_t *buf) {
     0x00, 0x00, 0x00, 0x00, // L0: .xword S
     0x00, 0x00, 0x00, 0x00,
   };
-  uint64_t s = getAArch64ThunkDestVA(destination, addend);
+  // if mayNeedLandingPad is true then destination is an
+  // AArch64BTILandingPadThunk that defines landingPad.
+  assert(!mayNeedLandingPad || landingPad != nullptr);
+  uint64_t s = mayNeedLandingPad ? landingPad->getVA(0)
+                                 : getAArch64ThunkDestVA(destination, addend);
   memcpy(buf, data, sizeof(data));
   ctx.target->relocateNoSym(buf + 8, R_AARCH64_ABS64, s);
 }
@@ -564,7 +604,11 @@ void AArch64ADRPThunk::writeLong(uint8_t *buf) {
       0x10, 0x02, 0x00, 0x91, // add  x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest)
       0x00, 0x02, 0x1f, 0xd6, // br   x16
   };
-  uint64_t s = getAArch64ThunkDestVA(destination, addend);
+  // if mayNeedLandingPad is true then destination is an
+  // AArch64BTILandingPadThunk that defines landingPad.
+  assert(!mayNeedLandingPad || landingPad != nullptr);
+  uint64_t s = mayNeedLandingPad ? landingPad->getVA(0)
+                                 : getAArch64ThunkDestVA(destination, addend);
   uint64_t p = getThunkTargetSym()->getVA();
   memcpy(buf, data, sizeof(data));
   ctx.target->relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
@@ -578,6 +622,48 @@ void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
   addSymbol("$x", STT_NOTYPE, 0, isec);
 }
 
+void AArch64BTILandingPadThunk::addSymbols(ThunkSection &isec) {
+  addSymbol(saver().save("__AArch64BTIThunk_" + destination.getName()),
+            STT_FUNC, 0, isec);
+  addSymbol("$x", STT_NOTYPE, 0, isec);
+}
+
+InputSection *AArch64BTILandingPadThunk::getTargetInputSection() const {
+  auto &dr = cast<Defined>(destination);
+  return dyn_cast<InputSection>(dr.section);
+}
+
+void AArch64BTILandingPadThunk::writeTo(uint8_t *buf) {
+  if (!getMayUseShortThunk()) {
+    writeLong(buf);
+    return;
+  }
+  write32(buf, 0xd503245f); // BTI c
+  // Control falls through to target in following section.
+}
+
+bool AArch64BTILandingPadThunk::getMayUseShortThunk() {
+  if (!mayUseShortThunk)
+    return false;
+  // If the target is the following instruction then
+  // we can fall through without the indirect branch.
+  uint64_t s = destination.getVA(addend);
+  uint64_t p = getThunkTargetSym()->getVA();
+  // <= 4 as Thunks start off with the same offset
+  // within the section as the destination, so
+  // s - p == 0 until addresses are assigned.
+  mayUseShortThunk = (s - p <= 4);
+  return mayUseShortThunk;
+}
+
+void AArch64BTILandingPadThunk::writeLong(uint8_t *buf) {
+  uint64_t s = destination.getVA(addend);
+  uint64_t p = getThunkTargetSym()->getVA() + 4;
+  write32(buf, 0xd503245f);     // BTI c
+  write32(buf + 4, 0x14000000); // B S
+  ctx.target->relocateNoSym(buf + 4, R_AARCH64_CALL26, s - p);
+}
+
 // ARM Target Thunks
 static uint64_t getARMThunkDestVA(const Symbol &s) {
   uint64_t v = s.isInPlt() ? s.getPltVA() : s.getVA();
@@ -1264,9 +1350,12 @@ static Thunk *addThunkAArch64(RelType type, Symbol &s, int64_t a) {
   if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 &&
       type != R_AARCH64_PLT32)
     fatal("unrecognized relocation type");
+  bool mayNeedLandingPad =
+      (config->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) &&
+      !isAArch64BTILandingPad(s, a);
   if (config->picThunk)
-    return make<AArch64ADRPThunk>(s, a);
-  return make<AArch64ABSLongThunk>(s, a);
+    return make<AArch64ADRPThunk>(s, a, mayNeedLandingPad);
+  return make<AArch64ABSLongThunk>(s, a, mayNeedLandingPad);
 }
 
 // Creates a thunk for long branches or Thumb-ARM interworking.
@@ -1480,3 +1569,12 @@ Thunk *elf::addThunk(const InputSection &isec, Relocation &rel) {
     llvm_unreachable("add Thunk only supported for ARM, AVR, Mips and PowerPC");
   }
 }
+
+Thunk *elf::addLandingPadThunk(Symbol &s, int64_t a) {
+  switch (config->emachine) {
+  case EM_AARCH64:
+    return make<AArch64BTILandingPadThunk>(s, a);
+  default:
+    llvm_unreachable("add landing pad only supported for AArch64");
+  }
+}
diff --git a/lld/ELF/Thunks.h b/lld/ELF/Thunks.h
index 12ddf08cadc090..4d797434aa70d0 100644
--- a/lld/ELF/Thunks.h
+++ b/lld/ELF/Thunks.h
@@ -54,10 +54,17 @@ class Thunk {
     return true;
   }
 
+  // Thunks that indirectly branch to targets may need a synthetic landing
+  // pad generated close to the target. For example AArch64 when BTI is
+  // enabled.
+  virtual bool needsSyntheticLandingPad() { return false; }
+
   Defined *getThunkTargetSym() const { return syms[0]; }
 
   Symbol &destination;
   int64_t addend;
+  // Alternative target when indirect branch to destination can't be used.
+  Symbol *landingPad = nullptr;
   llvm::SmallVector<Defined *, 3> syms;
   uint64_t offset = 0;
   // The alignment requirement for this Thunk, defaults to the size of the
@@ -68,7 +75,9 @@ class Thunk {
 // For a Relocation to symbol S create a Thunk to be added to a synthetic
 // ThunkSection.
 Thunk *addThunk(const InputSection &isec, Relocation &rel);
-
+// Create a landing pad Thunk for use when indirect branches from Thunks
+// are restricted.
+Thunk *addLandingPadThunk(Symbol &s, int64_t a);
 void writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
                            const InputFile *file, int64_t addend);
 void writePPC64LoadAndBranch(uint8_t *buf, int64_t offset);
diff --git a/lld/test/ELF/aarch64-thunk-bti.s b/lld/test/ELF/aarch64-thunk-bti.s
new file mode 100644
index 00000000000000..f23c7c1c789b09
--- /dev/null
+++ b/lld/test/ELF/aarch64-thunk-bti.s
@@ -0,0 +1,513 @@
+// REQUIRES: aarch64
+// RUN: split-file %s %t
+// RUN: llvm-mc -filetype=obj -triple=aarch64 %t/asm -o %t.o
+// RUN: ld.lld --shared --script=%t/lds %t.o -o %t.so --defsym absolute=0xf0000000
+// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x10000000 --stop-address=0x10000028 %t.so | FileCheck --check-prefix=CHECK-SO %s
+// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x17fc0028 --stop-address=0x17fc0050 %t.so | FileCheck --check-prefix=CHECK-SO2 %s
+// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x18000050 --stop-address=0x180000a8 %t.so | FileCheck --check-prefix=CHECK-BTI %s
+// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x180000b0 --stop-address=0x18000100 %t.so | FileCheck --check-prefix=CHECK-SO3 %s
+// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x30000000 --stop-address=0x300000c0 %t.so | FileCheck --check-prefix=CHECK-SO4 %s
+// RUN: rm %t.so
+// RUN: llvm-mc -filetype=obj -triple=aarch64 %t/shared -o %tshared.o
+// RUN: ld.lld --shared -o %tshared.so %tshared.o
+// RUN: ld.lld %tshared.so --script=%t/lds %t.o -o %t.exe --defsym absolute=0xf0000000
+// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x10000000 --stop-address=0x10000028 %t.exe | FileCheck --check-prefix=CHECK-EXE %s
+// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x17fc0028 --stop-address=0x17fc0050 %t.exe | FileCheck --check-prefix=CHECK-EXE2 %s
+// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x18000050 --stop-address=0x180000a8 %t.exe | FileCheck --check-prefix=CHECK-BTI %s
+// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x180000b0 --stop-address=0x180000e8 %t.exe | FileCheck --check-prefix=CHECK-EXE3 %s
+// RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x30000000 --stop-address=0x300000ec %t.exe | FileCheck --check-prefix=CHECK-EXE4 %s
+// RUN: rm %t.o %tshared.o %tshared.so
+
+/// Test thunk generation when destination does not have
+/// a BTI compatible landing pad. Linker must generate
+/// landing pad sections for thunks that use indirect
+/// branches.
+
+//--- asm
+.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
+
+
+/// Short thunks are direct branches so we don't
+/// need landing pads. Expect all thunks to branch
+/// to target.
+.section .text.0, "ax", %progbits
+.balign 0x1000
+.global _start
+.type _start, %function
+_start:
+ bl bti_c_target
+ bl bti_j_target
+ bl bti_jc_target
+ bl paciasp_target
+ bl pacibsp_target
+ bl fn1
+ bl fn2
+ bl fn3
+ bl  fn4
+ bl via_plt
+
+// CHECK-SO-LABEL: <_start>:
+// CHECK-SO-NEXT: 10000000: bl      0x17fc0028 <__AArch64ADRPThunk_>
+// CHECK-SO-NEXT:           bl      0x17fc002c <__AArch64ADRPThunk_>
+// CHECK-SO-NEXT:           bl      0x17fc0030 <__AArch64ADRPThunk_>
+// CHECK-SO-NEXT:           bl      0x17fc0034 <__AArch64ADRPThunk_>
+// CHECK-SO-NEXT:           bl      0x17fc0038 <__AArch64ADRPThunk_>
+// CHECK-SO-NEXT:           bl      0x17fc003c <__AArch64ADRPThunk_>
+// CHECK-SO-NEXT:           bl      0x17fc0040 <__AArch64ADRPThunk_>
+// CHECK-SO-NEXT:           bl      0x17fc0044 <__AArch64ADRPThunk_>
+// CHECK-SO-NEXT:           bl      0x17fc0048 <__AArch64ADRPThunk_>
+// CHECK-SO-NEXT:           bl      0x17fc004c <__AArch64ADRPThunk_via_plt>
+
+// CHECK-SO2:      <__AArch64ADRPThunk_>:
+// CHECK-SO2-NEXT:17fc0028: b       0x18000050 <bti_c_target>
+// CHECK-SO2-EMPTY:
+// CHECK-SO2-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO2-NEXT:          b       0x18000058 <bti_j_target>
+// CHECK-SO2-EMPTY:
+// CHECK-SO2-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO2-NEXT:          b       0x18000060 <bti_jc_target>
+// CHECK-SO2-EMPTY:
+// CHECK-SO2-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO2-NEXT:          b       0x18000068 <paciasp_target>
+// CHECK-SO2-EMPTY:
+// CHECK-SO2-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO2-NEXT:          b       0x18000070 <pacibsp_target>
+// CHECK-SO2-EMPTY:
+// CHECK-SO2-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO2-NEXT:          b       0x18000088 <fn1>
+// CHECK-SO2-EMPTY:
+// CHECK-SO2-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO2-NEXT:          b       0x1800008c <fn2>
+// CHECK-SO2-EMPTY:
+// CHECK-SO2-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO2-NEXT:          b       0x18000094 <fn3>
+// CHECK-SO2-EMPTY:
+// CHECK-SO2-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO2-NEXT:          b       0x180000a0 <fn4>
+// CHECK-SO2-EMPTY:
+// CHECK-SO2-NEXT: <__AArch64ADRPThunk_via_plt>:
+// CHECK-SO2-NEXT:          b       0x180000d0 <fn4+0x30>
+
+// CHECK-EXE-LABEL: <_start>:
+// CHECK-EXE-NEXT: 10000000: bl      0x17fc0028 <__AArch64AbsLongThunk_>
+// CHECK-EXE-NEXT:           bl      0x17fc002c <__AArch64AbsLongThunk_>
+// CHECK-EXE-NEXT:           bl      0x17fc0030 <__AArch64AbsLongThunk_>
+// CHECK-EXE-NEXT:           bl      0x17fc0034 <__AArch64AbsLongThunk_>
+// CHECK-EXE-NEXT:           bl      0x17fc0038 <__AArch64AbsLongThunk_>
+// CHECK-EXE-NEXT:           bl      0x17fc003c <__AArch64AbsLongThunk_>
+// CHECK-EXE-NEXT:           bl      0x17fc0040 <__AArch64AbsLongThunk_>
+// CHECK-EXE-NEXT:           bl      0x17fc0044 <__AArch64AbsLongThunk_>
+// CHECK-EXE-NEXT:           bl      0x17fc0048 <__AArch64AbsLongThunk_>
+// CHECK-EXE-NEXT:           bl      0x17fc004c <__AArch64AbsLongThunk_via_plt>
+
+// CHECK-EXE2: <__AArch64AbsLongThunk_>:
+// CHECK-EXE2-NEXT: 17fc0028: b       0x18000050 <bti_c_target>
+// CHECK-EXE2-EMPTY:
+// CHECK-EXE2-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE2-NEXT:           b       0x18000058 <bti_j_target>
+// CHECK-EXE2-EMPTY:
+// CHECK-EXE2-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE2-NEXT:           b       0x18000060 <bti_jc_target>
+// CHECK-EXE2-EMPTY:
+// CHECK-EXE2-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE2-NEXT:           b       0x18000068 <paciasp_target>
+// CHECK-EXE2-EMPTY:
+// CHECK-EXE2-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE2-NEXT:           b       0x18000070 <pacibsp_target>
+// CHECK-EXE2-EMPTY:
+// CHECK-EXE2-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE2-NEXT:           b       0x18000088 <fn1>
+// CHECK-EXE2-EMPTY:
+// CHECK-EXE2-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE2-NEXT:           b       0x1800008c <fn2>
+// CHECK-EXE2-EMPTY:
+// CHECK-EXE2-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE2-NEXT:           b       0x18000094 <fn3>
+// CHECK-EXE2-EMPTY:
+// CHECK-EXE2-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE2-NEXT:           b       0x180000a0 <fn4>
+// CHECK-EXE2-EMPTY:
+// CHECK-EXE2-NEXT: <__AArch64AbsLongThunk_via_plt>:
+// CHECK-EXE2-NEXT:           b       0x180000d0 <fn4+0x30>
+
+// padding to put .text.short out of
+// range, but with enough gaps to
+// place a pool that can short thunk
+// to targets.
+.section .text.1, "ax", %progbits
+.space 0x2000000
+
+.section .text.2, "ax", %progbits
+.space 0x2000000
+
+.section .text.3, "ax", %progbits
+.space 0x2000000
+
+.section .text.4, "ax", %progbits
+.space 0x2000000 - 0x40000
+
+.section .text.5, "ax", %progbits
+.space 0x40000
+
+.section .text.6, "ax", %progbits
+/// Indirect branch targets have BTI compatible landing pad
+/// No alternative entry point required.
+.hidden bti_c_target
+.type bti_c_target, %function
+bti_c_target:
+ bti c
+ ret
+
+.hidden bti_j_target
+.type bti_j_target, %function
+bti_j_target:
+ bti j
+ ret
+
+.hidden bti_jc_target
+.type bti_jc_target, %function
+bti_jc_target:
+ bti jc
+ ret
+
+.hidden paciasp_target
+.type paciasp_target, %function
+paciasp_target:
+ paciasp
+ ret
+
+.hidden pacibsp_target
+.type pacibsp_target, %function
+pacibsp_target:
+ pacibsp
+ ret
+
+// CHECK-BTI-LABEL: <bti_c_target>:
+// CHECK-BTI-NEXT: 18000050: bti     c
+// CHECK-BTI-NEXT:           ret
+// CHECK-BTI-EMPTY:
+// CHECK-BTI-LABEL: <bti_j_target>:
+// CHECK-BTI-NEXT:           bti     j
+// CHECK-BTI-NEXT:           ret
+// CHECK-BTI-EMPTY:
+// CHECK-BTI-LABEL: <bti_jc_target>:
+// CHECK-BTI-NEXT:           bti     jc
+// CHECK-BTI-NEXT:           ret
+// CHECK-BTI-EMPTY:
+// CHECK-BTI-LABEL: <paciasp_target>:
+// CHECK-BTI-NEXT:           paciasp
+// CHECK-BTI-NEXT:           ret
+// CHECK-BTI-EMPTY:
+// CHECK-BTI-LABEL: <pacibsp_target>:
+// CHECK-BTI-NEXT:           pacibsp
+// CHECK-BTI-NEXT:           ret
+
+/// functions do not have BTI compatible landing pads.
+/// Expect linker generated landing pads.
+.section .text.7, "ax", %progbits
+.hidden fn1
+.type fn1, %function
+fn1:
+ ret
+.hidden fn2
+.type fn2, %function
+fn2:
+ ret
+
+// CHECK-BTI: <__AArch64BTIThunk_>:
+// CHECK-BTI-NEXT: 18000078: bti     c
+// CHECK-BTI-NEXT:           b       0x18000088 <fn1>
+// CHECK-BTI-EMPTY:
+// CHECK-BTI-NEXT: <__AArch64BTIThunk_>:
+// CHECK-BTI-NEXT:           bti     c
+// CHECK-BTI-NEXT:           b       0x1800008c <fn2>
+// CHECK-BTI-EMPTY:
+// CHECK-BTI-LABEL: <fn1>:
+// CHECK-BTI-NEXT:           ret
+// CHECK-BTI-EMPTY:
+// CHECK-BTI-LABEL:  <fn2>:
+// CHECK-BTI-NEXT:           ret
+
+/// Section with only one function at offset 0. Landing pad should
+/// be able to fall through.
+.section .text.8, "ax", %progbits
+.hidden fn3
+.type fn3, %function
+fn3:
+ ret
+
+// CHECK-BTI: <__AArch64BTIThunk_>:
+// CHECK-BTI-NEXT: 18000090: bti     c
+// CHECK-BTI-EMPTY:
+// CHECK-BTI-LABEL: <fn3>:
+// CHECK-BTI-NEXT:           ret
+
+/// Section with only one function at offset 0, also with a high
+/// alignment requirement. Check that we don't fall through into
+/// alignment padding.
+.section .text.9, "ax", %progbits
+.balign 16
+.hidden fn4
+.type fn4, %function
+fn4:
+ ret
+
+// CHECK-BTI: <__AArch64BTIThunk_>:
+// CHECK-BTI-NEXT: 18000098: bti     c
+// CHECK-BTI-NEXT:           b       0x180000a0 <fn4>
+// CHECK-BTI-EMPTY:
+// CHECK-BTI-LABEL: <fn4>:
+// CHECK-BTI-NEXT:           ret
+
+/// PLT has bti c.
+// CHECK-SO3: 180000b0: bti     c
+// CHECK-SO3-NEXT: stp     x16, x30, [sp, #-0x10]!
+// CHECK-SO3-NEXT: adrp    x16, 0x30000000 <via_plt+0x30000000>
+// CHECK-SO3-NEXT: ldr     x17, [x16, #0x2d0]
+// CHECK-SO3-NEXT: add     x16, x16, #0x2d0
+// CHECK-SO3-NEXT: br      x17
+// CHECK-SO3-NEXT: nop
+// CHECK-SO3-NEXT: nop
+// CHECK-SO3-NEXT: bti     c
+// CHECK-SO3-NEXT: adrp    x16, 0x30000000 <via_plt+0x30000000>
+// CHECK-SO3-NEXT: ldr     x17, [x16, #0x2d8]
+// CHECK-SO3-NEXT: add     x16, x16, #0x2d8
+// CHECK-SO3-NEXT: br      x17
+// CHECK-SO3-NEXT: nop
+// CHECK-SO3-NEXT: bti     c
+// CHECK-SO3-NEXT: adrp    x16, 0x30000000 <via_plt+0x30000000>
+// CHECK-SO3-NEXT: ldr     x17, [x16, #0x2e0]
+// CHECK-SO3-NEXT: add     x16, x16, #0x2e0
+// CHECK-SO3-NEXT: br      x17
+// CHECK-SO3-NEXT: nop
+
+// CHECK-EXE3: 180000b0: bti     c
+// CHECK-EXE3-NEXT:      stp     x16, x30, [sp, #-0x10]!
+// CHECK-EXE3-NEXT:      adrp    x16, 0x30000000 <via_plt+0x30000000>
+// CHECK-EXE3-NEXT:      ldr     x17, [x16, #0x320]
+// CHECK-EXE3-NEXT:      add     x16, x16, #0x320
+// CHECK-EXE3-NEXT:      br      x17
+// CHECK-EXE3-NEXT:      nop
+// CHECK-EXE3-NEXT:      nop
+// CHECK-EXE3-NEXT:      bti     c
+// CHECK-EXE3-NEXT:      adrp    x16, 0x30000000 <via_plt+0x30000000>
+// CHECK-EXE3-NEXT:      ldr     x17, [x16, #0x328]
+// CHECK-EXE3-NEXT:      add     x16, x16, #0x328
+// CHECK-EXE3-NEXT:      br      x17
+// CHECK-EXE3-NEXT:      nop
+
+.section .long_calls, "ax", %progbits
+.global long_calls
+.type long_calls, %function
+/// Expect thunk to target as targets have
+/// BTI or implicit BTI.
+ bl bti_c_target
+ bl bti_j_target
+ bl bti_jc_target
+ bl paciasp_target
+ bl pacibsp_target
+/// Expect thunk to target a linker generated
+/// entry point with BTI landing pad.
+/// Two calls to make sure only one landing
+/// pad is created.
+ bl fn1
+ b  fn1
+ bl fn2
+ b  fn2
+ bl fn3
+ b  fn3
+ bl fn4
+ b  fn4
+/// PLT entries reachable via Thunks have a
+/// BTI c at the start of each entry so no
+/// additional landing pad required.
+ bl via_plt
+/// We cannot add landing pads for absolute
+/// symbols.
+ bl absolute
+
+// CHECK-SO4-LABEL: <.text_high>:
+// CHECK-SO4-NEXT: 30000000: bl      0x3000003c <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           bl      0x30000048 <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           bl      0x30000054 <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           bl      0x30000060 <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           bl      0x3000006c <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           bl      0x30000078 <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           b       0x30000078 <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           bl      0x30000084 <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           b       0x30000084 <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           bl      0x30000090 <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           b       0x30000090 <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           bl      0x3000009c <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           b       0x3000009c <__AArch64ADRPThunk_>
+// CHECK-SO4-NEXT:           bl      0x300000a8 <__AArch64ADRPThunk_via_plt>
+// CHECK-SO4-NEXT:           bl      0x300000b4 <__AArch64ADRPThunk_absolute>
+// CHECK-SO4-EMPTY:
+// CHECK-SO4-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO4-NEXT:           adrp    x16, 0x18000000 <__AArch64ADRPThunk_via_plt+0x3ffb4>
+// CHECK-SO4-NEXT:           add     x16, x16, #0x50
+// CHECK-SO4-NEXT:           br      x16
+// CHECK-SO4-EMPTY:
+// CHECK-SO4-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO4-NEXT:           adrp    x16, 0x18000000 <__AArch64ADRPThunk_via_plt+0x3ffb4>
+// CHECK-SO4-NEXT:           add     x16, x16, #0x58
+// CHECK-SO4-NEXT:           br      x16
+// CHECK-SO4-EMPTY:
+// CHECK-SO4-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO4-NEXT:           adrp    x16, 0x18000000 <__AArch64ADRPThunk_via_plt+0x3ffb4>
+// CHECK-SO4-NEXT:           add     x16, x16, #0x60
+// CHECK-SO4-NEXT:           br      x16
+// CHECK-SO4-EMPTY:
+// CHECK-SO4-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO4-NEXT:           adrp    x16, 0x18000000 <__AArch64ADRPThunk_via_plt+0x3ffb4>
+// CHECK-SO4-NEXT:           add     x16, x16, #0x68
+// CHECK-SO4-NEXT:           br      x16
+// CHECK-SO4-EMPTY:
+// CHECK-SO4-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO4-NEXT:           adrp    x16, 0x18000000 <__AArch64ADRPThunk_via_plt+0x3ffb4>
+// CHECK-SO4-NEXT:           add     x16, x16, #0x70
+// CHECK-SO4-NEXT:           br      x16
+// CHECK-SO4-EMPTY:
+// CHECK-SO4-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO4-NEXT:           adrp    x16, 0x18000000 <__AArch64ADRPThunk_via_plt+0x3ffb4>
+// CHECK-SO4-NEXT:           add     x16, x16, #0x78
+// CHECK-SO4-NEXT:           br      x16
+// CHECK-SO4-EMPTY:
+// CHECK-SO4-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO4-NEXT:           adrp    x16, 0x18000000 <__AArch64ADRPThunk_via_plt+0x3ffb4>
+// CHECK-SO4-NEXT:           add     x16, x16, #0x80
+// CHECK-SO4-NEXT:           br      x16
+// CHECK-SO4-EMPTY:
+// CHECK-SO4-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO4-NEXT:           adrp    x16, 0x18000000 <__AArch64ADRPThunk_via_plt+0x3ffb4>
+// CHECK-SO4-NEXT:           add     x16, x16, #0x90
+// CHECK-SO4-NEXT:           br      x16
+// CHECK-SO4-EMPTY:
+// CHECK-SO4-NEXT: <__AArch64ADRPThunk_>:
+// CHECK-SO4-NEXT:           adrp    x16, 0x18000000 <__AArch64ADRPThunk_via_plt+0x3ffb4>
+// CHECK-SO4-NEXT:           add     x16, x16, #0x98
+// CHECK-SO4-NEXT:           br      x16
+// CHECK-SO4-EMPTY:
+// CHECK-SO4-NEXT: <__AArch64ADRPThunk_via_plt>:
+// CHECK-SO4-NEXT:           adrp    x16, 0x18000000 <__AArch64ADRPThunk_via_plt+0x3ffb4>
+// CHECK-SO4-NEXT:           add     x16, x16, #0xd0
+// CHECK-SO4-NEXT:           br      x16
+// CHECK-SO4-EMPTY:
+// CHECK-SO4-NEXT: <__AArch64ADRPThunk_absolute>:
+// CHECK-SO4-NEXT:           adrp    x16, 0x18000000 <__AArch64ADRPThunk_via_plt+0x3ffb4>
+// CHECK-SO4-NEXT:           add     x16, x16, #0xe8
+// CHECK-SO4-NEXT:           br      x16
+
+// CHECK-EXE4-LABEL: <.text_high>:
+// CHECK-EXE4-NEXT: 30000000: bl      0x3000003c <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           bl      0x3000004c <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           bl      0x3000005c <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           bl      0x3000006c <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           bl      0x3000007c <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           bl      0x3000008c <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           b       0x3000008c <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           bl      0x3000009c <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           b       0x3000009c <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           bl      0x300000ac <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           b       0x300000ac <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           bl      0x300000bc <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           b       0x300000bc <__AArch64AbsLongThunk_>
+// CHECK-EXE4-NEXT:           bl      0x300000cc <__AArch64AbsLongThunk_via_plt>
+// CHECK-EXE4-NEXT:           bl      0x300000dc <__AArch64AbsLongThunk_absolute>
+// CHECK-EXE4-EMPTY:
+// CHECK-EXE4-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE4-NEXT:           ldr     x16, 0x30000044 <__AArch64AbsLongThunk_+0x8>
+// CHECK-EXE4-NEXT:           br      x16
+// CHECK-EXE4-NEXT:           50 00 00 18       .word   0x18000050
+// CHECK-EXE4-NEXT:           00 00 00 00       .word   0x00000000
+// CHECK-EXE4-EMPTY:
+// CHECK-EXE4-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE4-NEXT:           ldr     x16, 0x30000054 <__AArch64AbsLongThunk_+0x8>
+// CHECK-EXE4-NEXT:           br      x16
+// CHECK-EXE4-NEXT:           58 00 00 18       .word   0x18000058
+// CHECK-EXE4-NEXT:           00 00 00 00       .word   0x00000000
+// CHECK-EXE4-EMPTY:
+// CHECK-EXE4-NEXT:  <__AArch64AbsLongThunk_>:
+// CHECK-EXE4-NEXT:           ldr     x16, 0x30000064 <__AArch64AbsLongThunk_+0x8>
+// CHECK-EXE4-NEXT:           br      x16
+// CHECK-EXE4-NEXT:           60 00 00 18       .word   0x18000060
+// CHECK-EXE4-NEXT:           00 00 00 00       .word   0x00000000
+// CHECK-EXE4-EMPTY:
+// CHECK-EXE4-NEXT:  <__AArch64AbsLongThunk_>:
+// CHECK-EXE4-NEXT:           ldr     x16, 0x30000074 <__AArch64AbsLongThunk_+0x8>
+// CHECK-EXE4-NEXT:           br      x16
+// CHECK-EXE4-NEXT:           68 00 00 18       .word   0x18000068
+// CHECK-EXE4-NEXT:           00 00 00 00       .word   0x00000000
+// CHECK-EXE4-EMPTY:
+// CHECK-EXE4-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE4-NEXT:           ldr     x16, 0x30000084 <__AArch64AbsLongThunk_+0x8>
+// CHECK-EXE4-NEXT:           br      x16
+// CHECK-EXE4-NEXT:           70 00 00 18        .word   0x18000070
+// CHECK-EXE4-NEXT:           00 00 00 00        .word   0x00000000
+// CHECK-EXE4-EMPTY:
+// CHECK-EXE4-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE4-NEXT:           ldr     x16, 0x30000094 <__AArch64AbsLongThunk_+0x8>
+// CHECK-EXE4-NEXT:           br      x16
+// CHECK-EXE4-NEXT:           78 00 00 18        .word   0x18000078
+// CHECK-EXE4-NEXT:           00 00 00 00        .word   0x00000000
+// CHECK-EXE4-EMPTY:
+// CHECK-EXE4-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE4-NEXT:           ldr     x16, 0x300000a4 <__AArch64AbsLongThunk_+0x8>
+// CHECK-EXE4-NEXT:           br      x16
+// CHECK-EXE4-NEXT:           80 00 00 18        .word   0x18000080
+// CHECK-EXE4-NEXT:           00 00 00 00        .word   0x00000000
+// CHECK-EXE4-EMPTY:
+// CHECK-EXE4-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE4-NEXT:           ldr     x16, 0x300000b4 <__AArch64AbsLongThunk_+0x8>
+// CHECK-EXE4-NEXT:           br      x16
+// CHECK-EXE4-NEXT:           90 00 00 18        .word   0x18000090
+// CHECK-EXE4-NEXT:           00 00 00 00        .word   0x00000000
+// CHECK-EXE4-EMPTY:
+// CHECK-EXE4-NEXT: <__AArch64AbsLongThunk_>:
+// CHECK-EXE4-NEXT:           ldr     x16, 0x300000c4 <__AArch64AbsLongThunk_+0x8>
+// CHECK-EXE4-NEXT:           br      x16
+// CHECK-EXE4-NEXT:           98 00 00 18        .word   0x18000098
+// CHECK-EXE4-NEXT:           00 00 00 00        .word   0x00000000
+// CHECK-EXE4-EMPTY:
+// CHECK-EXE4-NEXT: <__AArch64AbsLongThunk_via_plt>:
+// CHECK-EXE4-NEXT:           ldr     x16, 0x300000d4 <__AArch64AbsLongThunk_via_plt+0x8>
+// CHECK-EXE4-NEXT:           br      x16
+// CHECK-EXE4-NEXT:           d0 00 00 18        .word   0x180000d0
+// CHECK-EXE4-NEXT:           00 00 00 00        .word   0x00000000
+// CHECK-EXE4-EMPTY:
+// CHECK-EXE4-NEXT: <__AArch64AbsLongThunk_absolute>:
+// CHECK-EXE4-NEXT:           ldr     x16, 0x300000e4 <__AArch64AbsLongThunk_absolute+0x8>
+// CHECK-EXE4-NEXT:           br      x16
+// CHECK-EXE4-NEXT:           00 00 00 f0        .word   0xf0000000
+// CHECK-EXE4-NEXT:           00 00 00 00        .word   0x00000000
+
+//--- lds
+PHDRS {
+  low PT_LOAD FLAGS(0x1 | 0x4);
+  high PT_LOAD FLAGS(0x1 | 0x4);
+}
+SECTIONS {
+    .text_low 0x10000000 : {
+        *(.text.*)
+	*(.plt)
+    } :low
+    .text_high 0x30000000 : { *(.long_calls) } :high
+}
+
+//--- shared
+.text
+.global via_plt
+.type via_plt, %function
+via_plt:
+ ret

>From c07640071c828d82488bdc57fd03e61115b23f0f Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.smith at arm.com>
Date: Tue, 17 Sep 2024 17:29:40 +0100
Subject: [PATCH 2/2] Make test more robust to pathname changes

The .dynstr is in between the .plt and the .got.plt. If this
contains a DT_NEEDED tag then the pathname of the shared object
will be used. This path is machine dependent. Don't hard code
the offsets in the .plt in this case. We are only disassembling
the .plt to show that there is a BTI at the start of it.
---
 lld/test/ELF/aarch64-thunk-bti.s | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/lld/test/ELF/aarch64-thunk-bti.s b/lld/test/ELF/aarch64-thunk-bti.s
index f23c7c1c789b09..9063c3dd1e9e54 100644
--- a/lld/test/ELF/aarch64-thunk-bti.s
+++ b/lld/test/ELF/aarch64-thunk-bti.s
@@ -16,7 +16,7 @@
 // RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x18000050 --stop-address=0x180000a8 %t.exe | FileCheck --check-prefix=CHECK-BTI %s
 // RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x180000b0 --stop-address=0x180000e8 %t.exe | FileCheck --check-prefix=CHECK-EXE3 %s
 // RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex --start-address=0x30000000 --stop-address=0x300000ec %t.exe | FileCheck --check-prefix=CHECK-EXE4 %s
-// RUN: rm %t.o %tshared.o %tshared.so
+// RUN: rm %t.o %tshared.o %tshared.so %t.exe
 
 /// Test thunk generation when destination does not have
 /// a BTI compatible landing pad. Linker must generate
@@ -295,15 +295,15 @@ fn4:
 // CHECK-EXE3: 180000b0: bti     c
 // CHECK-EXE3-NEXT:      stp     x16, x30, [sp, #-0x10]!
 // CHECK-EXE3-NEXT:      adrp    x16, 0x30000000 <via_plt+0x30000000>
-// CHECK-EXE3-NEXT:      ldr     x17, [x16, #0x320]
-// CHECK-EXE3-NEXT:      add     x16, x16, #0x320
+// CHECK-EXE3-NEXT:      ldr     x17, [x16, #0x{{.*}}]
+// CHECK-EXE3-NEXT:      add     x16, x16, #0x{{.*}}
 // CHECK-EXE3-NEXT:      br      x17
 // CHECK-EXE3-NEXT:      nop
 // CHECK-EXE3-NEXT:      nop
 // CHECK-EXE3-NEXT:      bti     c
 // CHECK-EXE3-NEXT:      adrp    x16, 0x30000000 <via_plt+0x30000000>
-// CHECK-EXE3-NEXT:      ldr     x17, [x16, #0x328]
-// CHECK-EXE3-NEXT:      add     x16, x16, #0x328
+// CHECK-EXE3-NEXT:      ldr     x17, [x16, #0x{{.*}}]
+// CHECK-EXE3-NEXT:      add     x16, x16, #0x{{.*}}
 // CHECK-EXE3-NEXT:      br      x17
 // CHECK-EXE3-NEXT:      nop
 



More information about the llvm-commits mailing list