On Fri, Jun 27, 2025 at 12:53:28PM +0200, Peter Zijlstra wrote: > On Thu, Jun 26, 2025 at 04:55:29PM -0700, Josh Poimboeuf wrote: > > An upcoming patch will add the SHF_MERGE flag to x86 __jump_table and > > __bug_table so their entry sizes can be defined in inline asm. > > > > However, those sections have SHF_WRITE, which the Clang linker (lld) > > explicitly forbids combining with SHF_MERGE. > > > > Those sections are modified at runtime and must remain writable. While > > SHF_WRITE is ignored by vmlinux, it's still needed for modules. > > > > To work around the linker interference, remove SHF_WRITE during > > compilation and restore it after linking the module. > > This is vile... but I'm not sure I have a better solution. > > Eventually we should get the toolchains fixed, but we can't very well > mandate clang-21+ to build x86 just yet.
Yeah, I really hate this too. I really tried to find something better, including mucking with the linker script, but this was unfortunately the only thing that worked. Though, looking at it again, I realize we can localize the pain to Clang (and the makefile) by leaving the code untouched and instead strip SHF_WRITE before the link and re-add it afterwards. Then we can tie this horrible hack to specific Clang versions when it gets fixed. Something like so: diff --git a/arch/Kconfig b/arch/Kconfig index a3308a220f86..350ea5df5e8d 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1314,6 +1314,9 @@ config HAVE_NOINSTR_HACK config HAVE_NOINSTR_VALIDATION bool +config NEED_MODULE_PERMISSIONS_FIX + bool + config HAVE_UACCESS_VALIDATION bool select OBJTOOL diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 71019b3b54ea..0cac13c03a90 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -310,6 +310,7 @@ config X86 select HOTPLUG_SPLIT_STARTUP if SMP && X86_32 select IRQ_FORCED_THREADING select LOCK_MM_AND_FIND_VMA + select NEED_MODULE_PERMISSIONS_FIX if LD_IS_LLD select NEED_PER_CPU_EMBED_FIRST_CHUNK select NEED_PER_CPU_PAGE_FIRST_CHUNK select NEED_SG_DMA_LENGTH diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 542ba462ed3e..cbc3213427ba 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -28,12 +28,37 @@ ccflags-remove-y := $(CC_FLAGS_CFI) .module-common.o: $(srctree)/scripts/module-common.c FORCE $(call if_changed_rule,cc_o_c) + +ifdef CONFIG_NEED_MODULE_PERMISSIONS_FIX + +# The LLVM linker forbids SHF_MERGE+SHF_WRITE. Hack around that by +# temporarily removing SHF_WRITE from affected sections before linking. + +cmd_fix_mod_permissions_pre_link = \ + $(OBJCOPY) --set-section-flags __jump_table=alloc,readonly \ + --set-section-flags __bug_table=alloc,readonly $@ \ + --set-section-flags .static_call_sites=alloc,readonly $@ + +cmd_fix_mod_permissions_post_link = \ + $(OBJCOPY) --set-section-flags __jump_table=alloc,data \ + --set-section-flags __bug_table=alloc,data $@ \ + --set-section-flags .static_call_sites=alloc,data $@ + +endif # CONFIG_NEED_MODULE_PERMISSIONS_FIX + + quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o = \ $(LD) -r $(KBUILD_LDFLAGS) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -T $(objtree)/scripts/module.lds -o $@ $(filter %.o, $^) +define rule_ld_ko_o + $(call cmd,fix_mod_permissions_pre_link) + $(call cmd_and_savecmd,ld_ko_o) + $(call cmd,fix_mod_permissions_post_link) +endef + quiet_cmd_btf_ko = BTF [M] $@ cmd_btf_ko = \ if [ ! -f $(objtree)/vmlinux ]; then \ @@ -46,14 +71,11 @@ quiet_cmd_btf_ko = BTF [M] $@ # Same as newer-prereqs, but allows to exclude specified extra dependencies newer_prereqs_except = $(filter-out $(PHONY) $(1),$?) -# Same as if_changed, but allows to exclude specified extra dependencies -if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \ - $(cmd); \ - printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:) +if_changed_rule_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check),$(rule_$(1)),@:) # Re-generate module BTFs if either module's .ko or vmlinux changed %.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE - +$(call if_changed_except,ld_ko_o,$(objtree)/vmlinux) + +$(call if_changed_rule_except,ld_ko_o,$(objtree)/vmlinux) ifdef CONFIG_DEBUG_INFO_BTF_MODULES +$(if $(newer-prereqs),$(call cmd,btf_ko)) endif