[PATCH v2 3/4] Kbuild: Create intermediate vmlinux build with relocations preserved

Ard Biesheuvel
2025-03-11T11:06:36Z

From: Ard Biesheuvel <ardb@kernel.org>

The imperative paradigm used to build vmlinux, extract some info from it
or perform some checks on it, and subsequently modify it again goes
against the declarative paradigm that is usually employed for defining
make rules.

In particular, the Makefile.postlink files that consume their input via
an output rule result in some dodgy logic in the decompressor makefiles
for RISC-V and x86, given that the vmlinux.relocs input file needed to
generate the arch-specific relocation tables may not exist or be out of
date, but cannot be constructed using the ordinary Make dependency based
rules, because the info needs to be extracted while vmlinux is in its
ephemeral, non-stripped form.

So instead, for architectures that require the static relocations that
are emitted into vmlinux when passing --emit-relocs to the linker, and
are subsequently stripped out again, introduce an intermediate vmlinux
target called vmlinux.unstripped, and organize the reset of the build
logic accordingly:

- vmlinux.unstripped is created only once, and not updated again
- build rules under arch/*/boot can depend on vmlinux.unstripped without
running the risk of the data disappearing or being out of date
- the final vmlinux generated by the build is not bloated with static
relocations that are never needed again after the build completes.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
.gitignore | 1 +
Makefile | 2 +-
arch/mips/Makefile.postlink | 2 +-
arch/riscv/Makefile.postlink | 11 +-------
arch/riscv/boot/Makefile | 5 +---
arch/s390/Makefile.postlink | 4 +--
arch/x86/Makefile.postlink | 8 +++---
scripts/Makefile.lib | 3 ---
scripts/Makefile.vmlinux | 28 +++++++++++++++-----
9 files changed, 30 insertions(+), 34 deletions(-)

diff --git a/.gitignore b/.gitignore
index 5937c74d3dc1..f2f63e47fb88 100644
--- a/.gitignore
+++ b/.gitignore
@@ -65,6 +65,7 @@ modules.order
/vmlinux.32
/vmlinux.map
/vmlinux.symvers
+/vmlinux.unstripped
/vmlinux-gdb.py
/vmlinuz
/System.map
diff --git a/Makefile b/Makefile
index a3302dce56de..c07295a980a0 100644
--- a/Makefile
+++ b/Makefile
@@ -1560,7 +1560,7 @@ endif # CONFIG_MODULES
# Directories & files removed with 'make clean'
CLEAN_FILES += vmlinux.symvers modules-only.symvers \
modules.builtin modules.builtin.modinfo modules.nsdeps \
- modules.builtin.ranges vmlinux.o.map \
+ modules.builtin.ranges vmlinux.o.map vmlinux.unstripped \
compile_commands.json rust/test \
rust-project.json .vmlinux.objs .vmlinux.export.c \
.builtin-dtbs-list .builtin-dtb.S
diff --git a/arch/mips/Makefile.postlink b/arch/mips/Makefile.postlink
index 6cfdc149d3bc..ea0add7d56b2 100644
--- a/arch/mips/Makefile.postlink
+++ b/arch/mips/Makefile.postlink
@@ -22,7 +22,7 @@ quiet_cmd_relocs = RELOCS $@

# `@true` prevents complaint when there is nothing to be done

-vmlinux: FORCE
+vmlinux vmlinux.unstripped: FORCE
@true
ifeq ($(CONFIG_CPU_LOONGSON3_WORKAROUNDS),y)
$(call if_changed,ls3_llsc)
diff --git a/arch/riscv/Makefile.postlink b/arch/riscv/Makefile.postlink
index 6b0580949b6a..0e4cf8ad2f14 100644
--- a/arch/riscv/Makefile.postlink
+++ b/arch/riscv/Makefile.postlink
@@ -10,26 +10,17 @@ __archpost:

-include include/config/auto.conf
include $(srctree)/scripts/Kbuild.include
-include $(srctree)/scripts/Makefile.lib

quiet_cmd_relocs_check = CHKREL $@
cmd_relocs_check = \
$(CONFIG_SHELL) $(srctree)/arch/riscv/tools/relocs_check.sh "$(OBJDUMP)" "$(NM)" "$@"

-ifdef CONFIG_RELOCATABLE
-quiet_cmd_cp_vmlinux_relocs = CPREL vmlinux.relocs
-cmd_cp_vmlinux_relocs = cp vmlinux vmlinux.relocs
-
-endif
-
# `@true` prevents complaint when there is nothing to be done

-vmlinux: FORCE
+vmlinux vmlinux.unstripped: FORCE
@true
ifdef CONFIG_RELOCATABLE
$(call if_changed,relocs_check)
- $(call if_changed,cp_vmlinux_relocs)
- $(call if_changed,strip_relocs)
endif

clean:
diff --git a/arch/riscv/boot/Makefile b/arch/riscv/boot/Makefile
index b25d524ce5eb..bfc3d0b75b9b 100644
--- a/arch/riscv/boot/Makefile
+++ b/arch/riscv/boot/Makefile
@@ -32,10 +32,7 @@ $(obj)/xipImage: vmlinux FORCE
endif

ifdef CONFIG_RELOCATABLE
-vmlinux.relocs: vmlinux
- @ (! [ -f vmlinux.relocs ] && echo "vmlinux.relocs can't be found, please remove vmlinux and try again") || true
-
-$(obj)/Image: vmlinux.relocs FORCE
+$(obj)/Image: vmlinux.unstripped FORCE
else
$(obj)/Image: vmlinux FORCE
endif
diff --git a/arch/s390/Makefile.postlink b/arch/s390/Makefile.postlink
index 1ae5478cd6ac..c2b737500a91 100644
--- a/arch/s390/Makefile.postlink
+++ b/arch/s390/Makefile.postlink
@@ -11,7 +11,6 @@ __archpost:

-include include/config/auto.conf
include $(srctree)/scripts/Kbuild.include
-include $(srctree)/scripts/Makefile.lib

CMD_RELOCS=arch/s390/tools/relocs
OUT_RELOCS = arch/s390/boot
@@ -20,9 +19,8 @@ quiet_cmd_relocs = RELOCS $(OUT_RELOCS)/relocs.S
mkdir -p $(OUT_RELOCS); \
$(CMD_RELOCS) $@ > $(OUT_RELOCS)/relocs.S

-vmlinux: FORCE
+vmlinux.unstripped: FORCE
$(call cmd,relocs)
- $(call cmd,strip_relocs)

clean:
@rm -f $(OUT_RELOCS)/relocs.S
diff --git a/arch/x86/Makefile.postlink b/arch/x86/Makefile.postlink
index 8b8a68162c94..445fce66630f 100644
--- a/arch/x86/Makefile.postlink
+++ b/arch/x86/Makefile.postlink
@@ -11,23 +11,21 @@ __archpost:

-include include/config/auto.conf
include $(srctree)/scripts/Kbuild.include
-include $(srctree)/scripts/Makefile.lib

CMD_RELOCS = arch/x86/tools/relocs
OUT_RELOCS = arch/x86/boot/compressed
-quiet_cmd_relocs = RELOCS $(OUT_RELOCS)/$@.relocs
+quiet_cmd_relocs = RELOCS $(OUT_RELOCS)/vmlinux.relocs
cmd_relocs = \
mkdir -p $(OUT_RELOCS); \
- $(CMD_RELOCS) $@ > $(OUT_RELOCS)/$@.relocs; \
+ $(CMD_RELOCS) $@ > $(OUT_RELOCS)/vmlinux.relocs; \
$(CMD_RELOCS) --abs-relocs $@

# `@true` prevents complaint when there is nothing to be done

-vmlinux: FORCE
+vmlinux vmlinux.unstripped: FORCE
@true
ifeq ($(CONFIG_X86_NEED_RELOCS),y)
$(call cmd,relocs)
- $(call cmd,strip_relocs)
endif

clean:
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index cad20f0e66ee..6abfefd1bd31 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -376,9 +376,6 @@ quiet_cmd_ar = AR $@
quiet_cmd_objcopy = OBJCOPY $@
cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@

-quiet_cmd_strip_relocs = RSTRIP $@
-cmd_strip_relocs = $(OBJCOPY) --remove-section='.rel*' $@
-
# Gzip
# ---------------------------------------------------------------------------

diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux
index 3523ce3ce3dc..dd744551a896 100644
--- a/scripts/Makefile.vmlinux
+++ b/scripts/Makefile.vmlinux
@@ -9,6 +9,20 @@ include $(srctree)/scripts/Makefile.lib

targets :=

+ifdef CONFIG_ARCH_VMLINUX_NEEDS_RELOCS
+vmlinux-final := vmlinux.unstripped
+
+quiet_cmd_strip_relocs = RSTRIP $@
+ cmd_strip_relocs = $(OBJCOPY) --remove-section='.rel*' $< $@
+
+vmlinux: $(vmlinux-final) FORCE
+ $(call if_changed,strip_relocs)
+
+targets += vmlinux
+else
+vmlinux-final := vmlinux
+endif
+
%.o: %.c FORCE
$(call if_changed_rule,cc_o_c)

@@ -47,7 +61,7 @@ targets += .builtin-dtbs-list

ifdef CONFIG_GENERIC_BUILTIN_DTB
targets += .builtin-dtbs.S .builtin-dtbs.o
-vmlinux: .builtin-dtbs.o
+$(vmlinux-final): .builtin-dtbs.o
endif

# vmlinux
@@ -55,11 +69,11 @@ endif

ifdef CONFIG_MODULES
targets += .vmlinux.export.o
-vmlinux: .vmlinux.export.o
+$(vmlinux-final): .vmlinux.export.o
endif

ifdef CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX
-vmlinux: arch/$(SRCARCH)/tools/vmlinux.arch.o
+$(vmlinux-final): arch/$(SRCARCH)/tools/vmlinux.arch.o

arch/$(SRCARCH)/tools/vmlinux.arch.o: vmlinux.o FORCE
$(Q)$(MAKE) $(build)=arch/$(SRCARCH)/tools $@
@@ -72,11 +86,11 @@ cmd_link_vmlinux = \
$< "$(LD)" "$(KBUILD_LDFLAGS)" "$(LDFLAGS_vmlinux)" "$@"; \
$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true)

-targets += vmlinux
-vmlinux: scripts/link-vmlinux.sh vmlinux.o $(KBUILD_LDS) FORCE
+targets += $(vmlinux-final)
+$(vmlinux-final): scripts/link-vmlinux.sh vmlinux.o $(KBUILD_LDS) FORCE
+$(call if_changed_dep,link_vmlinux)
ifdef CONFIG_DEBUG_INFO_BTF
-vmlinux: $(RESOLVE_BTFIDS)
+$(vmlinux-final): $(RESOLVE_BTFIDS)
endif

# module.builtin.ranges
@@ -92,7 +106,7 @@ 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
+vmlinux.map: $(vmlinux-final)
@:

endif
--
2.49.0.rc0.332.g42c0ae87b1-goog