[PATCH 23/27] kbuild: Do the per-module objtool pass right before linking
From: Josh Poimboeuf
Date: Fri Aug 28 2026 - 00:56:37 EST
With CONFIG_OBJTOOL_CONTROL_FLOW, the objtool pass on vmlinux.o is going
to be generating a list of its exported noreturns which will then be
read by the modules' objtool pass, so there will need to be a build
dependency between them.
In preparation for that, run objtool right before the module link so its
no longer done on the descend in the deferred case.
Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx>
---
scripts/Makefile.build | 31 +++++++++++++++----------------
scripts/Makefile.modfinal | 20 +++++++++++++++-----
scripts/livepatch/klp-build | 4 ++--
3 files changed, 32 insertions(+), 23 deletions(-)
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 84ef12f784330..9e672979a976c 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -270,15 +270,21 @@ cmd_record_mcount = $(if $(findstring $(strip $(CC_FLAGS_FTRACE)),$(_c_flags)),
$(sub_cmd_record_mcount))
endif # CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT
-# 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory
-# 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file
-# 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file
-
+ifdef CONFIG_OBJTOOL
+#
+# NOTE: these variables are deprecated, and have no effect when
+# CONFIG_OBJTOOL_DEFERRED is enabled. Objtool-allergic code can instead be
+# marked with STACK_FRAME_NON_STANDARD() or ANNOTATE_*().
+#
+# 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory
+# 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file
+# 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file
+#
is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(target-stem).o)$(OBJECT_FILES_NON_STANDARD)n),$(is-kernel-object))
-ifdef CONFIG_OBJTOOL
-$(obj)/%.o: private objtool-enabled = $(if $(is-standard-object),$(if $(CONFIG_OBJTOOL_DEFERRED),$(is-single-obj-m),y))
-endif
+# Enable per-TU objtool for !CONFIG_OBJTOOL_DEFERRED
+$(obj)/%.o: private objtool-enabled = $(if $(CONFIG_OBJTOOL_DEFERRED),,$(if $(is-standard-object),y))
+endif # CONFIG_OBJTOOL
ifneq ($(findstring 1, $(KBUILD_EXTRA_WARN)),)
cmd_warn_shared_object = $(if $(word 2, $(modname-multi)),$(warning $(kbuild-file): $*.o is added to multiple modules: $(modname-multi)))
@@ -495,17 +501,10 @@ $(obj)/lib.a: $(lib-y) FORCE
$(call if_changed,ar)
quiet_cmd_ld_multi_m = LD [M] $@
- cmd_ld_multi_m = $(LD) $(ld_flags) -r -o $@ @$< $(cmd_objtool)
+ cmd_ld_multi_m = $(LD) $(ld_flags) -r -o $@ @$<
-define rule_ld_multi_m
- $(call cmd_and_savecmd,ld_multi_m)
- $(call cmd,gen_objtooldep)
-endef
-
-$(multi-obj-m): private objtool-enabled := $(CONFIG_OBJTOOL_DEFERRED)
-$(multi-obj-m): private part-of-module := y
$(multi-obj-m): %.o: %.mod FORCE
- $(call if_changed_rule,ld_multi_m)
+ $(call if_changed,ld_multi_m)
$(call multi_depend, $(multi-obj-m), .o, -objs -y -m)
# Add intermediate targets:
diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
index 01a37ec872b90..56b4227cc6863 100644
--- a/scripts/Makefile.modfinal
+++ b/scripts/Makefile.modfinal
@@ -32,11 +32,18 @@ ifneq ($(WARN_ON_UNUSED_TRACEPOINTS),)
cmd_check_tracepoint = $(objtree)/scripts/tracepoint-update --module $<;
endif
+$(modules:%.o=%.ko): private objtool-enabled = $(CONFIG_OBJTOOL_DEFERRED)
+
+mod-objtool = $(if $(objtool-enabled),$(objtool) $(objtool-args) -o $@.o $< ;)
+mod-obj = $(if $(objtool-enabled),$@.o,$<)
+
quiet_cmd_ld_ko_o = LD [M] $@
cmd_ld_ko_o = \
+ $(mod-objtool) \
$(LD) -r $(KBUILD_LDFLAGS) \
$(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
- -T $(objtree)/scripts/module.lds -o $@ $(filter %.o, $^)
+ -T $(objtree)/scripts/module.lds -o $@ \
+ $(mod-obj) $(filter-out $<, $(filter %.o, $^))
quiet_cmd_btf_ko = BTF [M] $@
cmd_btf_ko = \
@@ -46,12 +53,15 @@ quiet_cmd_btf_ko = BTF [M] $@
$(CONFIG_SHELL) $(srctree)/scripts/gen-btf.sh --btf_base $(objtree)/vmlinux $@; \
fi;
+define rule_ld_ko_o
+ +$(call cmd_and_savecmd,ld_ko_o)
+ +$(call cmd,gen_objtooldep)
+ +$(if $(CONFIG_DEBUG_INFO_BTF_MODULES),$(if $(newer-prereqs),$(call cmd,btf_ko)))
+endef
+
# 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,ld_ko_o)
-ifdef CONFIG_DEBUG_INFO_BTF_MODULES
- +$(if $(newer-prereqs),$(call cmd,btf_ko))
-endif
+ $(call if_changed_rule,ld_ko_o)
+$(call cmd,check_tracepoint)
targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o) .module-common.o
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index b52a8489d9f67..5237bad90f2cb 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -600,7 +600,7 @@ copy_orig_objects() {
xtrace_save "copying original objects"
for _file in "${files[@]}"; do
local rel_file="${_file/.ko/.o}"
- local file="$PWD/$rel_file"
+ local file="$PWD/${_file/%.ko/.ko.o}"
local orig_file="$ORIG_DIR/$rel_file"
local orig_dir="$(dirname "$orig_file")"
@@ -636,7 +636,7 @@ copy_patched_objects() {
xtrace_save "copying changed objects"
for _file in "${files[@]}"; do
local rel_file="${_file/.ko/.o}"
- local file="$PWD/$rel_file"
+ local file="$PWD/${_file/%.ko/.ko.o}"
local orig_file="$ORIG_DIR/$rel_file"
local patched_file="$PATCHED_DIR/$rel_file"
local patched_dir="$(dirname "$patched_file")"
--
2.55.0