linux/scripts/Makefile.vmlinux
Lorenzo Stoakes (ARM) 5fe4dd5966
kbuild: do not allocate .modinfo in vmlinux
Commit 3e86e4d74c ("kbuild: keep .modinfo section in vmlinux.unstripped")
placed MODULE_INFO() strings in the .modinfo section in vmlinux.unstripped,
however it left the section allocatable, so it gets assigned an address and
on arm64, arm and riscv, the section is tagged as PT_LOAD.

This is useless as the data is ultimately stripped anyway.

Doing this results in a lot of unnecessary work - each pass copies the
whole file, 450 MiB with relocations for an x86 allmodconfig build and 250
MiB for an arm64 allmodconfig build.

This adds ~0.7s on the serial tail of every build for arm64 and ~0.2s for
x86 (the tail is single-threaded work done after parallel work has
finished).

Nothing requires .modinfo to exist at an address, so mark the output
section (INFO) so that it's not allocated and use --dump-section to extract
it as -O only emits allocated sections.

The dump doesn't pick up the arch's OBJCOPYFLAGS any longer as they should
not impact the output of this section.

Image, bzImage, System.map and modules.builtin.modinfo are unchanged and
the stripped vmlinux differs only in its program headers.

The objcopy passes are on the serial tail of every build that links
vmlinux, no-op builds are unchanged.

Whole build, 128-thread Threadripper 9980X, best of N runs:

                                         before   after     delta
                                         -------------------------------
  x86 defconfig, touch mm/vma.c, gcc       11.2s    11.1s    -0.15s (-1%)
  x86 defconfig, touch mm/vma.c, clang     11.3s    11.1s    -0.19s (-2%)
  x86 defconfig, clean, gcc                32.5s    32.3s    -0.16s (-1%)
  x86 defconfig, clean, clang              34.5s    34.2s    -0.26s (-1%)
  x86 allmodconfig, touch mm/vma.c, gcc    40.1s    39.7s    -0.44s (-1%)

Assisted-by: LLM
Reviewed-by: Kees Cook <kees@kernel.org>
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Reviewed-by: Nicolas Schier <n.schier@fritz.com>
Link: https://patch.msgid.link/20260923-build-speedup-v4-1-73128809a4a4@kernel.org
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
2026-09-26 00:16:33 +01:00

160 lines
5.0 KiB
Makefile

# SPDX-License-Identifier: GPL-2.0-only
PHONY := __default
__default: vmlinux
include include/config/auto.conf
include $(srctree)/scripts/Kbuild.include
include $(srctree)/scripts/Makefile.lib
targets :=
%.o: %.c FORCE
$(call if_changed_rule,cc_o_c)
%.o: %.S FORCE
$(call if_changed_rule,as_o_S)
# Built-in dtb
# ---------------------------------------------------------------------------
quiet_cmd_wrap_dtbs = WRAP $@
cmd_wrap_dtbs = { \
echo '\#include <asm-generic/vmlinux.lds.h>'; \
echo '.section .dtb.init.rodata,"a"'; \
while read dtb; do \
symbase=__dtb_$$(basename -s .dtb "$${dtb}" | tr - _); \
echo '.balign STRUCT_ALIGNMENT'; \
echo ".global $${symbase}_begin"; \
echo "$${symbase}_begin:"; \
echo '.incbin "'$$dtb'" '; \
echo ".global $${symbase}_end"; \
echo "$${symbase}_end:"; \
done < $<; \
} > $@
.builtin-dtbs.S: .builtin-dtbs-list FORCE
$(call if_changed,wrap_dtbs)
quiet_cmd_gen_dtbs_list = GEN $@
cmd_gen_dtbs_list = \
$(if $(CONFIG_BUILTIN_DTB_NAME), echo "arch/$(SRCARCH)/boot/dts/$(CONFIG_BUILTIN_DTB_NAME).dtb",:) > $@
.builtin-dtbs-list: arch/$(SRCARCH)/boot/dts/dtbs-list FORCE
$(call if_changed,$(if $(CONFIG_BUILTIN_DTB_ALL),copy,gen_dtbs_list))
targets += .builtin-dtbs-list
ifdef CONFIG_GENERIC_BUILTIN_DTB
targets += .builtin-dtbs.S .builtin-dtbs.o
vmlinux.unstripped: .builtin-dtbs.o
endif
# vmlinux.unstripped
# ---------------------------------------------------------------------------
ifdef CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX
vmlinux.unstripped: arch/$(SRCARCH)/tools/vmlinux.arch.o
arch/$(SRCARCH)/tools/vmlinux.arch.o: vmlinux.o FORCE
$(Q)$(MAKE) $(build)=arch/$(SRCARCH)/tools $@
endif
ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink)
# Final link of vmlinux with optional arch pass after final link
cmd_link_vmlinux = \
$< "$(LD)" "$(KBUILD_LDFLAGS)" "$(LDFLAGS_vmlinux)" "$@"; \
$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)
targets += vmlinux.unstripped .vmlinux.export.o
vmlinux.unstripped: scripts/link-vmlinux.sh vmlinux.o .vmlinux.export.o $(KBUILD_LDS) FORCE
+$(call if_changed_dep,link_vmlinux)
ifdef CONFIG_DEBUG_INFO_BTF
vmlinux.unstripped: $(RESOLVE_BTFIDS) $(srctree)/scripts/gen-btf.sh
endif
ifdef CONFIG_BUILDTIME_TABLE_SORT
vmlinux.unstripped: scripts/sorttable
endif
# vmlinux
# ---------------------------------------------------------------------------
remove-section-y := .modinfo
remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel*' '!.rel*.dyn'
# for compatibility with binutils < 2.32
# https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=c12d9fa2afe7abcbe407a00e15719e1a1350c2a7
remove-section-$(CONFIG_ARCH_VMLINUX_NEEDS_RELOCS) += '.rel.*'
remove-symbols := -w --strip-unneeded-symbol='__mod_device_table__*'
quiet_cmd_strip_relocs = OBJCOPY $@
cmd_strip_relocs = $(OBJCOPY) $(addprefix --remove-section=,$(remove-section-y)) $(remove-symbols) $< $@
targets += vmlinux
vmlinux: vmlinux.unstripped FORCE
$(call if_changed,strip_relocs)
# modules.builtin.modinfo
# ---------------------------------------------------------------------------
quiet_cmd_modules_builtin_modinfo = GEN $@
cmd_modules_builtin_modinfo = $(OBJCOPY) -O binary -j .modinfo --dump-section .modinfo=$@ $< /dev/null
targets += modules.builtin.modinfo
modules.builtin.modinfo: vmlinux.unstripped FORCE
$(call if_changed,modules_builtin_modinfo)
# modules.builtin
# ---------------------------------------------------------------------------
__default: modules.builtin
# The second line aids cases where multiple modules share the same object.
quiet_cmd_modules_builtin = GEN $@
cmd_modules_builtin = \
tr '\0' '\n' < $< | \
sed -n 's/^[[:alnum:]:_]*\.file=//p' | \
tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$$/.ko/' > $@
targets += modules.builtin
modules.builtin: modules.builtin.modinfo FORCE
$(call if_changed,modules_builtin)
# modules.builtin.ranges
# ---------------------------------------------------------------------------
ifdef CONFIG_BUILTIN_MODULE_RANGES
__default: modules.builtin.ranges
quiet_cmd_modules_builtin_ranges = GEN $@
cmd_modules_builtin_ranges = gawk -f $(real-prereqs) > $@
targets += modules.builtin.ranges
modules.builtin.ranges: $(srctree)/scripts/generate_builtin_ranges.awk \
modules.builtin vmlinux.map vmlinux.o.map FORCE
$(call if_changed,modules_builtin_ranges)
vmlinux.map: vmlinux.unstripped
@:
endif
# Add FORCE to the prerequisites of a target to force it to be always rebuilt.
# ---------------------------------------------------------------------------
PHONY += FORCE
FORCE:
# Read all saved command lines and dependencies for the $(targets) we
# may be building above, using $(if_changed{,_dep}). As an
# optimization, we don't need to read them if the target does not
# exist, we will rebuild anyway in that case.
existing-targets := $(wildcard $(sort $(targets)))
-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
.PHONY: $(PHONY)