[PATCH 05/12] arm64/bti: Add link error for large kernels with BTI and unsupported toolchains
From: Josh Poimboeuf
Date: Sat Aug 15 2026 - 00:47:47 EST
On a kernel whose text exceeds the +/128MB direct branch range, the
linker inserts veneers. With BTI enabled, the veneers' indirect branch
targets need a BTI landing pad, which not all functions have starting
with Clang 21 (and for all versions of GCC).
In such cases the linker can emit a second veneer close to the target
which has the landing pad along with a direct branch to the target.
However, that's currently not being done, so GCC and Clang 21+ are
broken with BTI on large kernels.
Only newer linkers have proper support for adding the second veneer,
starting with binutils 2.42 and LLVM 20.
Only allow a large kernel with the right combination of compiler and
linker.
Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
---
arch/arm64/Kconfig | 7 +++++++
arch/arm64/kernel/vmlinux.lds.S | 5 +++++
2 files changed, 12 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b3afe0688919b..2687b71438661 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2123,6 +2123,13 @@ config ARM64_BTI_KERNEL
is enabled and the system supports BTI all kernel code including
modular code must have BTI enabled.
+config CC_OMITS_BTI_LANDING_PADS
+ def_bool !CC_IS_CLANG || CLANG_VERSION >= 210000
+
+config LD_HAS_BTI_STUBS
+ def_bool (LD_IS_BFD && LD_VERSION >= 24200) || \
+ (LD_IS_LLD && LLD_VERSION >= 200000)
+
config CC_HAS_BRANCH_PROT_PAC_RET_BTI
# GCC 9 or later, clang 8 or later
def_bool $(cc-option,-mbranch-protection=pac-ret+leaf+bti)
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index af1d720209764..3a88da9212831 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -414,6 +414,11 @@ ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) <= 3*PAGE_SIZE,
#ifdef CONFIG_KVM
ASSERT(__hyp_bss_start == __bss_start, "HYP and Host BSS are misaligned")
#endif
+
+#if defined(CONFIG_ARM64_BTI_KERNEL) && !defined(CONFIG_COMPILE_TEST) && \
+ defined(CONFIG_CC_OMITS_BTI_LANDING_PADS) && !defined(CONFIG_LD_HAS_BTI_STUBS)
+ASSERT(__exittext_end - _text <= SZ_128M, "Kernel text too big for BTI")
+#endif
/*
* If padding is applied before .head.text, virt<->phys conversions will fail.
*/
--
2.55.0