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

