On Wed, Sep 17, 2025 at 09:03:10AM -0700, Josh Poimboeuf wrote: > TEXT_MAIN, DATA_MAIN and friends are defined differently depending on > whether certain config options enable -ffunction-sections and/or > -fdata-sections. > > There's no technical reason for that beyond voodoo coding. Keeping the > separate implementations adds unnecessary complexity, fragments the > logic, and increases the risk of subtle bugs. > > Unify the macros by using the same input section patterns across all > configs. > > This is a prerequisite for the upcoming livepatch klp-build tooling > which will manually enable -ffunction-sections and -fdata-sections via > KCFLAGS. > > Cc: Heiko Carstens <[email protected]> > Cc: Vasily Gorbik <[email protected]> > Cc: Alexander Gordeev <[email protected]> > Signed-off-by: Josh Poimboeuf <[email protected]> > --- > include/asm-generic/vmlinux.lds.h | 40 ++++++++++--------------------- > scripts/module.lds.S | 12 ++++------ > 2 files changed, 17 insertions(+), 35 deletions(-) > > diff --git a/include/asm-generic/vmlinux.lds.h > b/include/asm-generic/vmlinux.lds.h > index ae2d2359b79e9..6b2311fa41393 100644 > --- a/include/asm-generic/vmlinux.lds.h > +++ b/include/asm-generic/vmlinux.lds.h > @@ -87,39 +87,24 @@ > #define ALIGN_FUNCTION() . = ALIGN(CONFIG_FUNCTION_ALIGNMENT) > > /* > - * LD_DEAD_CODE_DATA_ELIMINATION option enables -fdata-sections, which > - * generates .data.identifier sections, which need to be pulled in with > - * .data. We don't want to pull in .data..other sections, which Linux > - * has defined. Same for text and bss. > + * Support -ffunction-sections by matching .text and .text.*, > + * but exclude '.text..*'. > * > - * With LTO_CLANG, the linker also splits sections by default, so we need > - * these macros to combine the sections during the final link. > - * > - * With AUTOFDO_CLANG and PROPELLER_CLANG, by default, the linker splits > - * text sections and regroups functions into subsections. > - * > - * RODATA_MAIN is not used because existing code already defines .rodata.x > - * sections to be brought in with rodata. > + * Special .text.* sections that are typically grouped separately, such as > + * .text.unlikely or .text.hot, must be matched explicitly before using > + * TEXT_MAIN. > */ > -#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || > defined(CONFIG_LTO_CLANG) || \ > -defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG) > #define TEXT_MAIN .text .text.[0-9a-zA-Z_]* > -#else > -#define TEXT_MAIN .text > -#endif > -#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || > defined(CONFIG_LTO_CLANG) > + > +/* > + * Support -fdata-sections by matching .data, .data.*, and others, > + * but exclude '.data..*'. > + */ > #define DATA_MAIN .data .data.[0-9a-zA-Z_]* .data.rel.* .data..L* > .data..compoundliteral* .data.$__unnamed_* .data.$L* > #define SDATA_MAIN .sdata .sdata.[0-9a-zA-Z_]* > #define RODATA_MAIN .rodata .rodata.[0-9a-zA-Z_]* .rodata..L* > #define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* .bss..L* .bss..compoundliteral* > #define SBSS_MAIN .sbss .sbss.[0-9a-zA-Z_]* > -#else > -#define DATA_MAIN .data .data.rel .data.rel.local > -#define SDATA_MAIN .sdata > -#define RODATA_MAIN .rodata > -#define BSS_MAIN .bss > -#define SBSS_MAIN .sbss > -#endif > > /* > * GCC 4.5 and later have a 32 bytes section alignment for structures. > @@ -580,9 +565,8 @@ defined(CONFIG_AUTOFDO_CLANG) || > defined(CONFIG_PROPELLER_CLANG) > * during second ld run in second ld pass when generating System.map > * > * TEXT_MAIN here will match symbols with a fixed pattern (for example, > - * .text.hot or .text.unlikely) if dead code elimination or > - * function-section is enabled. Match these symbols first before > - * TEXT_MAIN to ensure they are grouped together. > + * .text.hot or .text.unlikely). Match those before TEXT_MAIN to ensure > + * they get grouped together. > * > * Also placing .text.hot section at the beginning of a page, this > * would help the TLB performance. > diff --git a/scripts/module.lds.S b/scripts/module.lds.S > index ee79c41059f3d..2632c6cb8ebe7 100644 > --- a/scripts/module.lds.S > +++ b/scripts/module.lds.S > @@ -38,12 +38,10 @@ SECTIONS { > __kcfi_traps : { KEEP(*(.kcfi_traps)) } > #endif > > -#ifdef CONFIG_LTO_CLANG > - /* > - * With CONFIG_LTO_CLANG, LLD always enables -fdata-sections and > - * -ffunction-sections, which increases the size of the final module. > - * Merge the split sections in the final binary. > - */ > + .text : { > + *(.text .text.[0-9a-zA-Z_]*) > + } > +
Cc: Ard Biesheuvel <[email protected]> Cc: Sami Tolvanen <[email protected]> I'm seeing some KP when trying to load modules after this change. I believe there is some sort of incompatibility with the SCS (Shadow Call Stack) code in arm64? The panic is always on __pi_scs_handle_fde_frame: init: Loading module [...]/drivers/net/wireless/virtual/mac80211_hwsim.ko Unable to handle kernel paging request at virtual address ffffffe6468f0ffc [...] pc : __pi_scs_handle_fde_frame+0xd8/0x15c lr : __pi_$x+0x74/0x138 sp : ffffffc08005bb10 x29: ffffffc08005bb10 x28: ffffffc081873010 x27: 0000000000000000 x26: 0000000000000007 x25: 0000000000000000 x24: 0000000000000000 x23: 0000000000000001 x22: ffffffe649794fa0 x21: ffffffe6469190b4 x20: 000000000000182c x19: 0000000000000001 x18: ffffffc080053000 x17: 000000000000002d x16: ffffffe6469190c5 x15: ffffffe6468f1000 x14: 000000000000003e x13: ffffffe6469190c6 x12: 00000000d50323bf x11: 00000000d503233f x10: ffffffe649119cb8 x9 : ffffffe6468f1000 x8 : 0000000000000100 x7 : 00656d6172665f68 x6 : 0000000000000001 x5 : 6372610000000000 x4 : 0000008000000000 x3 : 0000000000000000 x2 : ffffffe647e528f4 x1 : 0000000000000001 x0 : 0000000000000004 Call trace: __pi_scs_handle_fde_frame+0xd8/0x15c (P) module_finalize+0xfc/0x164 post_relocation+0xbc/0xd8 load_module+0xfd4/0x11a8 __arm64_sys_finit_module+0x23c/0x328 invoke_syscall+0x58/0xe4 el0_svc_common+0x80/0xdc do_el0_svc+0x1c/0x28 el0_svc+0x54/0x1c4 el0t_64_sync_handler+0x68/0xdc el0t_64_sync+0x1c4/0x1c8 Code: 54fffd4c 1400001f 3707ff63 aa0903ef (b85fcdf0) This is not a problem if I disable UNWIND_PATCH_PAC_INTO_SCS but I have no idea why. Looking around it seems like this might related: $ cat arch/arm64/include/asm/module.lds.h SECTIONS { [...] #ifdef CONFIG_UNWIND_TABLES /* * Currently, we only use unwind info at module load time, so we can * put it into the .init allocation. */ .init.eh_frame : { *(.eh_frame) } #endif I must note that I've only seen this in Android kernels and I have not tried to reproduce the issue elsewhere. However, the incompatibility seems like it could be applicable upstream too and I'm hoping that the issue is evident to others (I can't understand any of this). Thanks, -- Carlos Llamas

