From d2eefad4e17a332d64f11881acf14eda7e085fd8 Mon Sep 17 00:00:00 2001 From: Gergely Balint 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 : +# FORCE-BTI-NEXT: 2103a0: bti c + .section ".note.gnu.property", "a" .long 4 .long 0x10