Linking an allyesconfig kernel (~700MB of text) with the GNU linker and CONFIG_ARM64_BTI_KERNEL triggers a seg fault in the linker:
#1 elf64_aarch64_stub_name (input_section=0x100000040, sym_sec=..., hash=..., rel=...) at ../../bfd/elfnn-aarch64.c:3042 #2 _bfd_aarch64_add_call_stub_entries (...) at ../../bfd/elfnn-aarch64.c:4674 #3 elf64_aarch64_size_stubs (...) at ../../bfd/elfnn-aarch64.c:4839 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. The GNU linker assumes each target has an input section. But linker-defined symbols don't have input sections, and ld crashes trying to access their veneer data. vmlinux.lds.S (via image-vars.h) uses PROVIDE() to alias some function symbols into the __efistub_ and __pi_ namespaces, which are used by the EFI stub and the position-independent startup code, respectively. Work around the crash by defining those aliases in code. Note this might also end up being a permanent fix, depending on whether the ld fix ends up reporting an error for such cases, or whether it will infer the alias's section from the aliasee. Define the five affected aliases in the objects which define their aliasees so they live in a real input section. Link: https://sourceware.org/bugzilla/show_bug.cgi?id=34525 Signed-off-by: Josh Poimboeuf <[email protected]> --- arch/arm64/kernel/head.S | 1 + arch/arm64/kernel/image-vars.h | 13 +------------ arch/arm64/lib/memcpy.S | 3 +++ arch/arm64/lib/memset.S | 2 ++ arch/arm64/mm/cache.S | 1 + 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 541721488bef9..e96af16b421d8 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -130,6 +130,7 @@ SYM_CODE_START(primary_entry) bl __cpu_setup // initialise processor b __primary_switch SYM_CODE_END(primary_entry) +SYM_FUNC_ALIAS(__efistub_primary_entry, primary_entry) __INIT SYM_CODE_START_LOCAL(record_mmu_state) diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h index d4c7d45ae6bc8..713b96cf5dc89 100644 --- a/arch/arm64/kernel/image-vars.h +++ b/arch/arm64/kernel/image-vars.h @@ -20,19 +20,12 @@ PROVIDE(pisym = sym); \ ASSERT((sym - KIMAGE_VADDR) < (__bss_start - KIMAGE_VADDR), #msg) -PROVIDE(__efistub_primary_entry = primary_entry); - /* * The EFI stub has its own symbol namespace prefixed by __efistub_, to * isolate it from the kernel proper. The following symbols are legally * accessed by the stub, so provide some aliases to make them accessible. - * Only include data symbols here, or text symbols of functions that are - * guaranteed to be safe when executed at another offset than they were - * linked at. The routines below are all implemented in assembler in a - * position independent manner + * Only include data symbols here. */ -PROVIDE(__efistub_caches_clean_inval_pou = __pi_caches_clean_inval_pou); - PROVIDE(__efistub__text = _text); PROVIDE(__efistub__end = _end); PROVIDE(__efistub___inittext_end = __inittext_end); @@ -42,10 +35,6 @@ PROVIDE(__efistub_sysfb_primary_display = sysfb_primary_display); #endif PROVIDE(__efistub__ctype = _ctype); -PROVIDE(__pi___memcpy = __pi_memcpy); -PROVIDE(__pi___memmove = __pi_memmove); -PROVIDE(__pi___memset = __pi_memset); - PI_EXPORT_SYM(id_aa64isar1_override); PI_EXPORT_SYM(id_aa64isar2_override); PI_EXPORT_SYM(id_aa64mmfr0_override); diff --git a/arch/arm64/lib/memcpy.S b/arch/arm64/lib/memcpy.S index 9b99106fb95f1..90dbb0d3acdef 100644 --- a/arch/arm64/lib/memcpy.S +++ b/arch/arm64/lib/memcpy.S @@ -268,3 +268,6 @@ SYM_FUNC_ALIAS(__memmove, __pi_memmove) EXPORT_SYMBOL(__memmove) SYM_FUNC_ALIAS_WEAK(memmove, __memmove) EXPORT_SYMBOL(memmove) + +SYM_FUNC_ALIAS(__pi___memcpy, __pi_memcpy) +SYM_FUNC_ALIAS(__pi___memmove, __pi_memmove) diff --git a/arch/arm64/lib/memset.S b/arch/arm64/lib/memset.S index 97157da65ec6b..31e514f020aa3 100644 --- a/arch/arm64/lib/memset.S +++ b/arch/arm64/lib/memset.S @@ -226,3 +226,5 @@ EXPORT_SYMBOL(__memset) SYM_FUNC_ALIAS_WEAK(memset, __pi_memset) EXPORT_SYMBOL(memset) + +SYM_FUNC_ALIAS(__pi___memset, __pi_memset) diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index ab75c050f5590..ab2cd6c524073 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S @@ -57,6 +57,7 @@ SYM_FUNC_START(caches_clean_inval_pou) ret SYM_FUNC_END(caches_clean_inval_pou) SYM_FUNC_ALIAS(__pi_caches_clean_inval_pou, caches_clean_inval_pou) +SYM_FUNC_ALIAS(__efistub_caches_clean_inval_pou, caches_clean_inval_pou) /* * caches_clean_inval_user_pou(start,end) -- 2.55.0

