[lld] [LLD] Add flag to force PLT entries to have a BTI (PR #168365)

Gergely Bálint via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 17 05:19:40 PST 2025


https://github.com/bgergely0 created https://github.com/llvm/llvm-project/pull/168365

None

>From d2eefad4e17a332d64f11881acf14eda7e085fd8 Mon Sep 17 00:00:00 2001
From: Gergely Balint <gergely.balint at arm.com>
Date: Thu, 13 Nov 2025 12:26:03 +0000
Subject: [PATCH] [LLD] Add flag to force PLT entries to have a BTI

---
 lld/ELF/Arch/AArch64.cpp           | 4 ++--
 lld/ELF/Config.h                   | 1 +
 lld/ELF/Driver.cpp                 | 1 +
 lld/ELF/Options.td                 | 2 ++
 lld/test/ELF/aarch64-feature-bti.s | 7 +++++++
 5 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index 2a97df4785ecb..a9702fde05b9b 100644
--- a/lld/ELF/Arch/AArch64.cpp
+++ b/lld/ELF/Arch/AArch64.cpp
@@ -1186,8 +1186,8 @@ void AArch64BtiPac::writePlt(uint8_t *buf, const Symbol &sym,
   // address may escape if referenced by a direct relocation. If relative
   // vtables are used then if the vtable is in a shared object the offsets will
   // be to the PLT entry. The condition is conservative.
-  bool hasBti = btiHeader &&
-                (sym.hasFlag(NEEDS_COPY) || sym.isInIplt || sym.thunkAccessed);
+  bool hasBti = btiHeader && (sym.hasFlag(NEEDS_COPY) || sym.isInIplt ||
+                              sym.thunkAccessed || ctx.arg.forceBtiPlt);
   if (hasBti) {
     memcpy(buf, btiData, sizeof(btiData));
     buf += sizeof(btiData);
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 8ec5a2c04e71c..b1060bf165ac8 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -330,6 +330,7 @@ struct Config {
   bool exportDynamic;
   bool fixCortexA53Errata843419;
   bool fixCortexA8;
+  bool forceBtiPlt = false;
   bool formatBinary = false;
   bool fortranCommon;
   bool gcSections;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 8647752be31fe..14c6b6f8a1dad 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1486,6 +1486,7 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
   ctx.arg.nmagic = args.hasFlag(OPT_nmagic, OPT_no_nmagic, false);
   ctx.arg.noinhibitExec = args.hasArg(OPT_noinhibit_exec);
   ctx.arg.nostdlib = args.hasArg(OPT_nostdlib);
+  ctx.arg.forceBtiPlt = args.hasArg(OPT_bti_plt);
   ctx.arg.oFormatBinary = isOutputFormatBinary(ctx, args);
   ctx.arg.omagic = args.hasFlag(OPT_omagic, OPT_no_omagic, false);
   ctx.arg.optRemarksFilename = args.getLastArgValue(OPT_opt_remarks_filename);
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 75184de496448..2059e0c62d748 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -212,6 +212,8 @@ defm eh_frame_hdr: B<"eh-frame-hdr",
 
 def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
 
+def bti_plt: FF<"force-bti-plt">, HelpText<"Force all PLT entries to have BTI">;
+
 def enable_new_dtags: F<"enable-new-dtags">,
   HelpText<"Enable new dynamic tags (default)">;
 
diff --git a/lld/test/ELF/aarch64-feature-bti.s b/lld/test/ELF/aarch64-feature-bti.s
index 8d7c1f2826c17..191e3710054f8 100644
--- a/lld/test/ELF/aarch64-feature-bti.s
+++ b/lld/test/ELF/aarch64-feature-bti.s
@@ -262,6 +262,13 @@
 # REPORT-ERR: error: unknown -z bti-report= value: u{{$}}
 # REPORT-EMPTY:
 
+## Force all PLT entries to start with BTI with the force-bti-plt command line option.
+# RUN: ld.lld %t.o %t2.o -z force-bti --force-bti-plt %t.so -o %tforcebtiplt.exe
+# RUN: llvm-objdump --no-print-imm-hex -d --mattr=+bti --no-show-raw-insn %tforcebtiplt.exe | FileCheck --check-prefix=FORCE-BTI %s
+
+# FORCE-BTI: 00000000002103a0 <func2 at plt>:
+# FORCE-BTI-NEXT:   2103a0: bti c
+
 .section ".note.gnu.property", "a"
 .long 4
 .long 0x10



More information about the llvm-commits mailing list