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


Reply via email to