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.

The linker only emits the BTI veneer if *all* input objects have
GNU_PROPERTY_AARCH64_FEATURE_1_BTI, which is not being done for
hand-written asm.

Force-include a property note with the BTI bit into every assembly
translation unit, which is accurate as SYM_FUNC_START*() already emits a
"bti c" landing pad for callable assembly functions.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
 arch/arm64/Makefile               |  4 ++++
 arch/arm64/include/asm/bti-note.h | 32 +++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+)
 create mode 100644 arch/arm64/include/asm/bti-note.h

diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 6b005c8fef706..4eee721c0b278 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -23,6 +23,10 @@ ifeq ($(CONFIG_ARM64_ERRATUM_843419),y)
 LDFLAGS_vmlinux        += --fix-cortex-a53-843419
 endif
 
+ifeq ($(CONFIG_ARM64_BTI_KERNEL),y)
+KBUILD_AFLAGS  += -include $(srctree)/arch/arm64/include/asm/bti-note.h
+endif
+
 cc_has_k_constraint := $(call try-run,echo                             \
        'int main(void) {                                               \
                asm volatile("and w0, w0, %w0" :: "K" (4294967295));    \
diff --git a/arch/arm64/include/asm/bti-note.h 
b/arch/arm64/include/asm/bti-note.h
new file mode 100644
index 0000000000000..17ef5692987f7
--- /dev/null
+++ b/arch/arm64/include/asm/bti-note.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Emit a GNU_PROPERTY_AARCH64_FEATURE_1_BTI note.  This is force-included in
+ * every assembly file so the linker emits BTI veneers for >128MB kernels.
+ *
+ * Clang has -mmark-bti-property, but there's no equivalent for GCC/GAS.
+ *
+ * Binutils 2.44+ and LLVM 22+ support a much more compact version:
+ *
+ *   .aeabi_subsection aeabi_feature_and_bits, optional, ULEB128
+ *   .aeabi_attribute Tag_Feature_BTI, 1
+ */
+#ifndef __ASM_BTI_NOTE_H
+#define __ASM_BTI_NOTE_H
+
+       .pushsection .note.gnu.property, "a"
+       .align  3
+       .long   2f - 1f
+       .long   6f - 3f
+       .long   5               /* NT_GNU_PROPERTY_TYPE_0 */
+1:     .string "GNU"
+2:
+       .align  3
+3:     .long   0xc0000000      /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+       .long   5f - 4f
+4:     .long   1               /* GNU_PROPERTY_AARCH64_FEATURE_1_BTI */
+5:
+       .align  3
+6:
+       .popsection
+
+#endif /* __ASM_BTI_NOTE_H */
-- 
2.55.0


Reply via email to