Skip to content

Commit

Permalink
kbuild: implement CONFIG_TRIM_UNUSED_KSYMS without recursion
Browse files Browse the repository at this point in the history
When CONFIG_TRIM_UNUSED_KSYMS is enabled, Kbuild recursively traverses
the directory tree to determine which EXPORT_SYMBOL to trim. If an
EXPORT_SYMBOL turns out to be unused by anyone, Kbuild begins the
second traverse, where some source files are recompiled with their
EXPORT_SYMBOL() tuned into a no-op.

Linus stated negative opinions about this slowness in commits:

 - 5cf0fd5 ("Kbuild: disable TRIM_UNUSED_KSYMS option")
 - a555bdd ("Kbuild: enable TRIM_UNUSED_KSYMS again, with some guarding")

We can do this better now. The final data structures of EXPORT_SYMBOL
are generated by the modpost stage, so modpost can selectively emit
KSYMTAB entries that are really used by modules.

Commit f73edc8 ("kbuild: unify two modpost invocations") is another
ground-work to do this in a one-pass algorithm. With the list of modules,
modpost sets sym->used if it is used by a module. modpost emits KSYMTAB
only for symbols with sym->used==true.

BTW, Nicolas explained why the trimming was implemented with recursion:

  https://lore.kernel.org/all/[email protected]/

Actually, we never achieved that level of optimization where the chain
reaction of trimming comes into play because:

 - CONFIG_LTO_CLANG cannot remove any unused symbols
 - CONFIG_LD_DEAD_CODE_DATA_ELIMINATION is enabled only for vmlinux,
   but not modules

If deeper trimming is required, we need to revisit this, but I guess
that is unlikely to happen.

Signed-off-by: Masahiro Yamada <[email protected]>
  • Loading branch information
masahir0y committed Jun 22, 2023
1 parent 700c48b commit 5e9e95c
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 264 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
*.symversions
*.tab.[ch]
*.tar
*.usyms
*.xz
*.zst
Module.symvers
Expand Down Expand Up @@ -112,7 +111,6 @@ modules.order
#
/include/config/
/include/generated/
/include/ksym/
/arch/*/include/generated/

# stgit generated dirs
Expand Down
22 changes: 3 additions & 19 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1193,28 +1193,12 @@ endif
export KBUILD_VMLINUX_LIBS
export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds

# Recurse until adjust_autoksyms.sh is satisfied
PHONY += autoksyms_recursive
ifdef CONFIG_TRIM_UNUSED_KSYMS
# For the kernel to actually contain only the needed exported symbols,
# we have to build modules as well to determine what those symbols are.
# (this can be evaluated only once include/config/auto.conf has been included)
KBUILD_MODULES := 1

autoksyms_recursive: $(build-dir) modules.order
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh \
"$(MAKE) -f $(srctree)/Makefile autoksyms_recursive"
endif

autoksyms_h := $(if $(CONFIG_TRIM_UNUSED_KSYMS), include/generated/autoksyms.h)

quiet_cmd_autoksyms_h = GEN $@
cmd_autoksyms_h = mkdir -p $(dir $@); \
$(CONFIG_SHELL) $(srctree)/scripts/gen_autoksyms.sh $@

$(autoksyms_h):
$(call cmd,autoksyms_h)

# '$(AR) mPi' needs 'T' to workaround the bug of llvm-ar <= 14
quiet_cmd_ar_vmlinux.a = AR $@
cmd_ar_vmlinux.a = \
Expand All @@ -1223,7 +1207,7 @@ quiet_cmd_ar_vmlinux.a = AR $@
$(AR) mPiT $$($(AR) t $@ | sed -n 1p) $@ $$($(AR) t $@ | grep -F -f $(srctree)/scripts/head-object-list.txt)

targets += vmlinux.a
vmlinux.a: $(KBUILD_VMLINUX_OBJS) scripts/head-object-list.txt autoksyms_recursive FORCE
vmlinux.a: $(KBUILD_VMLINUX_OBJS) scripts/head-object-list.txt FORCE
$(call if_changed,ar_vmlinux.a)

PHONY += vmlinux_o
Expand Down Expand Up @@ -1279,7 +1263,7 @@ scripts: scripts_basic scripts_dtc
PHONY += prepare archprepare

archprepare: outputmakefile archheaders archscripts scripts include/config/kernel.release \
asm-generic $(version_h) $(autoksyms_h) include/generated/utsrelease.h \
asm-generic $(version_h) include/generated/utsrelease.h \
include/generated/compile.h include/generated/autoconf.h remove-stale-files

prepare0: archprepare
Expand Down Expand Up @@ -2039,7 +2023,7 @@ clean: $(clean-dirs)
-o -name '*.dtb.S' -o -name '*.dtbo.S' \
-o -name '*.dt.yaml' \
-o -name '*.dwo' -o -name '*.lst' \
-o -name '*.su' -o -name '*.mod' -o -name '*.usyms' \
-o -name '*.su' -o -name '*.mod' \
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
-o -name '*.lex.c' -o -name '*.tab.[ch]' \
-o -name '*.asn1.[ch]' \
Expand Down
67 changes: 10 additions & 57 deletions include/linux/export.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,32 +42,14 @@ extern struct module __this_module;
.long sym
#endif

#define ____EXPORT_SYMBOL(sym, license, ns) \
#define ___EXPORT_SYMBOL(sym, license, ns) \
.section ".export_symbol","a" ASM_NL \
__export_symbol_##sym: ASM_NL \
.asciz license ASM_NL \
.asciz ns ASM_NL \
__EXPORT_SYMBOL_REF(sym) ASM_NL \
.previous

#ifdef __GENKSYMS__

#define ___EXPORT_SYMBOL(sym, sec, ns) __GENKSYMS_EXPORT_SYMBOL(sym)

#elif defined(__ASSEMBLY__)

#define ___EXPORT_SYMBOL(sym, license, ns) \
____EXPORT_SYMBOL(sym, license, ns)

#else

#define ___EXPORT_SYMBOL(sym, license, ns) \
extern typeof(sym) sym; \
__ADDRESSABLE(sym) \
asm(__stringify(____EXPORT_SYMBOL(sym, license, ns)))

#endif

#if !defined(CONFIG_MODULES) || defined(__DISABLE_EXPORTS)

/*
Expand All @@ -77,50 +59,21 @@ extern struct module __this_module;
*/
#define __EXPORT_SYMBOL(sym, sec, ns)

#elif defined(CONFIG_TRIM_UNUSED_KSYMS)
#elif defined(__GENKSYMS__)

#include <generated/autoksyms.h>
#define __EXPORT_SYMBOL(sym, sec, ns) __GENKSYMS_EXPORT_SYMBOL(sym)

/*
* For fine grained build dependencies, we want to tell the build system
* about each possible exported symbol even if they're not actually exported.
* We use a symbol pattern __ksym_marker_<symbol> that the build system filters
* from the $(NM) output (see scripts/gen_ksymdeps.sh). These symbols are
* discarded in the final link stage.
*/

#ifdef __ASSEMBLY__

#define __ksym_marker(sym) \
.section ".discard.ksym","a" ; \
__ksym_marker_##sym: ; \
.previous

#else

#define __ksym_marker(sym) \
static int __ksym_marker_##sym[0] __section(".discard.ksym") __used

#endif
#elif defined(__ASSEMBLY__)

#define __EXPORT_SYMBOL(sym, sec, ns) \
__ksym_marker(sym); \
__cond_export_sym(sym, sec, ns, __is_defined(__KSYM_##sym))
#define __cond_export_sym(sym, sec, ns, conf) \
___cond_export_sym(sym, sec, ns, conf)
#define ___cond_export_sym(sym, sec, ns, enabled) \
__cond_export_sym_##enabled(sym, sec, ns)
#define __cond_export_sym_1(sym, sec, ns) ___EXPORT_SYMBOL(sym, sec, ns)

#ifdef __GENKSYMS__
#define __cond_export_sym_0(sym, sec, ns) __GENKSYMS_EXPORT_SYMBOL(sym)
#else
#define __cond_export_sym_0(sym, sec, ns) /* nothing */
#endif
#define __EXPORT_SYMBOL(sym, license, ns) \
___EXPORT_SYMBOL(sym, license, ns)

#else

#define __EXPORT_SYMBOL(sym, sec, ns) ___EXPORT_SYMBOL(sym, sec, ns)
#define __EXPORT_SYMBOL(sym, license, ns) \
extern typeof(sym) sym; \
__ADDRESSABLE(sym) \
asm(__stringify(___EXPORT_SYMBOL(sym, license, ns)))

#endif /* CONFIG_MODULES */

Expand Down
15 changes: 1 addition & 14 deletions scripts/Makefile.build
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ ifdef need-builtin
targets-for-builtin += $(obj)/built-in.a
endif

targets-for-modules := $(foreach x, o mod $(if $(CONFIG_TRIM_UNUSED_KSYMS), usyms), \
targets-for-modules := $(foreach x, o mod, \
$(patsubst %.o, %.$x, $(filter %.o, $(obj-m))))

ifdef need-modorder
Expand Down Expand Up @@ -217,18 +217,12 @@ is-standard-object = $(if $(filter-out y%, $(OBJECT_FILES_NON_STANDARD_$(basetar

$(obj)/%.o: objtool-enabled = $(if $(is-standard-object),$(if $(delay-objtool),$(is-single-obj-m),y))

ifdef CONFIG_TRIM_UNUSED_KSYMS
cmd_gen_ksymdeps = \
$(CONFIG_SHELL) $(srctree)/scripts/gen_ksymdeps.sh $@ >> $(dot-target).cmd
endif

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)))
endif

define rule_cc_o_c
$(call cmd_and_fixdep,cc_o_c)
$(call cmd,gen_ksymdeps)
$(call cmd,checksrc)
$(call cmd,checkdoc)
$(call cmd,gen_objtooldep)
Expand All @@ -239,7 +233,6 @@ endef

define rule_as_o_S
$(call cmd_and_fixdep,as_o_S)
$(call cmd,gen_ksymdeps)
$(call cmd,gen_objtooldep)
$(call cmd,gen_symversions_S)
$(call cmd,warn_shared_object)
Expand All @@ -258,12 +251,6 @@ cmd_mod = printf '%s\n' $(call real-search, $*.o, .o, -objs -y -m) | \
$(obj)/%.mod: FORCE
$(call if_changed,mod)

# List module undefined symbols
cmd_undefined_syms = $(NM) $< | sed -n 's/^ *U //p' > $@

$(obj)/%.usyms: $(obj)/%.o FORCE
$(call if_changed,undefined_syms)

quiet_cmd_cc_lst_c = MKLST $@
cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
$(CONFIG_SHELL) $(srctree)/scripts/makelst $*.o \
Expand Down
7 changes: 7 additions & 0 deletions scripts/Makefile.modpost
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ targets += .vmlinux.objs
.vmlinux.objs: vmlinux.a $(KBUILD_VMLINUX_LIBS) FORCE
$(call if_changed,vmlinux_objs)

ifdef CONFIG_TRIM_UNUSED_KSYMS
ksym-wl := $(CONFIG_UNUSED_KSYMS_WHITELIST)
ksym-wl := $(if $(filter-out /%, $(ksym-wl)),$(srctree)/)$(ksym-wl)
modpost-args += -t $(addprefix -u , $(ksym-wl))
modpost-deps += $(ksym-wl)
endif

ifeq ($(wildcard vmlinux.o),)
missing-input := vmlinux.o
output-symdump := modules-only.symvers
Expand Down
73 changes: 0 additions & 73 deletions scripts/adjust_autoksyms.sh

This file was deleted.

3 changes: 1 addition & 2 deletions scripts/basic/fixdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,7 @@ static void *read_file(const char *filename)
/* Ignore certain dependencies */
static int is_ignored_file(const char *s, int len)
{
return str_ends_with(s, len, "include/generated/autoconf.h") ||
str_ends_with(s, len, "include/generated/autoksyms.h");
return str_ends_with(s, len, "include/generated/autoconf.h");
}

/* Do not parse these files */
Expand Down
62 changes: 0 additions & 62 deletions scripts/gen_autoksyms.sh

This file was deleted.

Loading

0 comments on commit 5e9e95c

Please sign in to comment.