On Thu 12 May 2022 01:45:06, Masahiro Yamada wrote: > include/{linux,asm-generic}/export.h defines a weak symbol, __crc_* > as a placeholder. > > Genksyms writes the version CRCs into the linker script, which will be > used for filling the __crc_* symbols. The linker script format depends > on CONFIG_MODULE_REL_CRCS. If it is enabled, __crc_* holds the offset > to the reference of CRC. > > It is time to get rid of this complexity. > > Now that modpost parses text files (.*.cmd) to collect all the CRCs, > it can generate C code that will be linked to the vmlinux or modules. > > Generate a new C file, .vmlinux.export.c, which contains the CRCs of > symbols exported by vmlinux. It is compiled and linked to vmlinux in > scripts/link-vmlinux.sh. > > Put the CRCs of symbols exported by modules into the existing *.mod.c > files. No additional build step is needed for modules. As before, > *.mod.c are compiled and linked to *.ko in scripts/Makefile.modfinal. > > No linker magic is used here. The new C implementation works in the > same way, whether CONFIG_RELOCATABLE is enabled or not. > CONFIG_MODULE_REL_CRCS is no longer needed. > > Previously, Kbuild invoked additional $(LD) to update the CRCs in > objects, but this step is unneeded too. > > Signed-off-by: Masahiro Yamada <masahiroy@xxxxxxxxxx> > Tested-by: Nathan Chancellor <nathan@xxxxxxxxxx> > --- > > Changes in v5: > - Fix the build error when CONFIG_DEBUG_INFO_BTF=y (reported by Nathan) > - Clean up arch/m68k/include/asm/export.h (Nick) > - Keep gen_symversions (and will be removed by a later patch) > > Changes in v4: > - Rename .vmlinux-symver.c to .vmlinux.export.c > because I notice this approach is useful for further cleanups, > not only for modversioning but also for overall EXPORT_SYMBOL. > > Changes in v3: > - New patch > > arch/m68k/include/asm/Kbuild | 1 + > arch/m68k/include/asm/export.h | 2 -- > arch/powerpc/Kconfig | 1 - > arch/s390/Kconfig | 1 - > arch/um/Kconfig | 1 - > include/asm-generic/export.h | 22 ++++++++-------------- > include/linux/export-internal.h | 16 ++++++++++++++++ > include/linux/export.h | 30 ++++++++---------------------- > init/Kconfig | 4 ---- > kernel/module.c | 10 +--------- > scripts/Makefile.build | 27 ++++----------------------- > scripts/genksyms/genksyms.c | 18 ++++-------------- > scripts/link-vmlinux.sh | 14 +++++++++++++- > scripts/mod/modpost.c | 28 ++++++++++++++++++++++++---- > 14 files changed, 79 insertions(+), 96 deletions(-) > delete mode 100644 arch/m68k/include/asm/export.h > create mode 100644 include/linux/export-internal.h > > diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild > index 0dbf9c5c6fae..1b720299deb1 100644 > --- a/arch/m68k/include/asm/Kbuild > +++ b/arch/m68k/include/asm/Kbuild > @@ -1,5 +1,6 @@ > # SPDX-License-Identifier: GPL-2.0 > generated-y += syscall_table.h > +generic-y += export.h > generic-y += extable.h > generic-y += kvm_para.h > generic-y += mcs_spinlock.h > diff --git a/arch/m68k/include/asm/export.h b/arch/m68k/include/asm/export.h > deleted file mode 100644 > index b53008b67ce1..000000000000 > --- a/arch/m68k/include/asm/export.h > +++ /dev/null > @@ -1,2 +0,0 @@ > -#define KCRC_ALIGN 2 > -#include <asm-generic/export.h> > diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig > index 174edabb74fa..a4e8dd889e29 100644 > --- a/arch/powerpc/Kconfig > +++ b/arch/powerpc/Kconfig > @@ -566,7 +566,6 @@ config RELOCATABLE > bool "Build a relocatable kernel" > depends on PPC64 || (FLATMEM && (44x || FSL_BOOKE)) > select NONSTATIC_KERNEL > - select MODULE_REL_CRCS if MODVERSIONS > help > This builds a kernel image that is capable of running at the > location the kernel is loaded at. For ppc32, there is no any > diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig > index 77b5a03de13a..aa5848004c76 100644 > --- a/arch/s390/Kconfig > +++ b/arch/s390/Kconfig > @@ -567,7 +567,6 @@ endchoice > > config RELOCATABLE > bool "Build a relocatable kernel" > - select MODULE_REL_CRCS if MODVERSIONS > default y > help > This builds a kernel image that retains relocation information > diff --git a/arch/um/Kconfig b/arch/um/Kconfig > index 4d398b80aea8..e8983d098e73 100644 > --- a/arch/um/Kconfig > +++ b/arch/um/Kconfig > @@ -106,7 +106,6 @@ config LD_SCRIPT_DYN > bool > default y > depends on !LD_SCRIPT_STATIC > - select MODULE_REL_CRCS if MODVERSIONS > > config LD_SCRIPT_DYN_RPATH > bool "set rpath in the binary" if EXPERT > diff --git a/include/asm-generic/export.h b/include/asm-generic/export.h > index 07a36a874dca..5e4b1f2369d2 100644 > --- a/include/asm-generic/export.h > +++ b/include/asm-generic/export.h > @@ -2,6 +2,14 @@ > #ifndef __ASM_GENERIC_EXPORT_H > #define __ASM_GENERIC_EXPORT_H > > +/* > + * This comment block is used by fixdep. Please do not remove. > + * > + * When CONFIG_MODVERSIONS is changed from n to y, all source files having > + * EXPORT_SYMBOL variants must be re-compiled because genksyms is run as a > + * side effect of the *.o build rule. > + */ > + > #ifndef KSYM_FUNC > #define KSYM_FUNC(x) x > #endif > @@ -12,9 +20,6 @@ > #else > #define KSYM_ALIGN 4 > #endif > -#ifndef KCRC_ALIGN > -#define KCRC_ALIGN 4 > -#endif > > .macro __put, val, name > #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS > @@ -43,17 +48,6 @@ __ksymtab_\name: > __kstrtab_\name: > .asciz "\name" > .previous > -#ifdef CONFIG_MODVERSIONS > - .section ___kcrctab\sec+\name,"a" > - .balign KCRC_ALIGN > -#if defined(CONFIG_MODULE_REL_CRCS) > - .long __crc_\name - . > -#else > - .long __crc_\name > -#endif > - .weak __crc_\name > - .previous > -#endif > #endif > .endm > > diff --git a/include/linux/export-internal.h b/include/linux/export-internal.h > new file mode 100644 > index 000000000000..77175d561058 > --- /dev/null > +++ b/include/linux/export-internal.h > @@ -0,0 +1,16 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Please do not include this explicitly. > + * This is used by C files generated by modpost. > + */ > + > +#ifndef __LINUX_EXPORT_INTERNAL_H__ > +#define __LINUX_EXPORT_INTERNAL_H__ > + > +#include <linux/compiler.h> > +#include <linux/types.h> > + > +#define SYMBOL_CRC(sym, crc, sec) \ > + u32 __section("___kcrctab" sec "+" #sym) __crc_##sym = crc > + > +#endif /* __LINUX_EXPORT_INTERNAL_H__ */ > diff --git a/include/linux/export.h b/include/linux/export.h > index 27d848712b90..565c5ffcb26f 100644 > --- a/include/linux/export.h > +++ b/include/linux/export.h > @@ -11,6 +11,14 @@ > * hackers place grumpy comments in header files. > */ > > +/* > + * This comment block is used by fixdep. Please do not remove. > + * > + * When CONFIG_MODVERSIONS is changed from n to y, all source files having > + * EXPORT_SYMBOL variants must be re-compiled because genksyms is run as a > + * side effect of the *.o build rule. > + */ > + > #ifndef __ASSEMBLY__ > #ifdef MODULE > extern struct module __this_module; > @@ -19,26 +27,6 @@ extern struct module __this_module; > #define THIS_MODULE ((struct module *)0) > #endif > > -#ifdef CONFIG_MODVERSIONS > -/* Mark the CRC weak since genksyms apparently decides not to > - * generate a checksums for some symbols */ > -#if defined(CONFIG_MODULE_REL_CRCS) > -#define __CRC_SYMBOL(sym, sec) \ > - asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \ > - " .weak __crc_" #sym " \n" \ > - " .long __crc_" #sym " - . \n" \ > - " .previous \n") > -#else > -#define __CRC_SYMBOL(sym, sec) \ > - asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \ > - " .weak __crc_" #sym " \n" \ > - " .long __crc_" #sym " \n" \ > - " .previous \n") > -#endif > -#else > -#define __CRC_SYMBOL(sym, sec) > -#endif > - > #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS > #include <linux/compiler.h> > /* > @@ -85,7 +73,6 @@ struct kernel_symbol { > /* > * For every exported symbol, do the following: > * > - * - If applicable, place a CRC entry in the __kcrctab section. > * - Put the name of the symbol and namespace (empty string "" for none) in > * __ksymtab_strings. > * - Place a struct kernel_symbol entry in the __ksymtab section. > @@ -98,7 +85,6 @@ struct kernel_symbol { > extern typeof(sym) sym; \ > extern const char __kstrtab_##sym[]; \ > extern const char __kstrtabns_##sym[]; \ > - __CRC_SYMBOL(sym, sec); \ > asm(" .section \"__ksymtab_strings\",\"aMS\",%progbits,1 \n" \ > "__kstrtab_" #sym ": \n" \ > " .asciz \"" #sym "\" \n" \ > diff --git a/init/Kconfig b/init/Kconfig > index ddcbefe535e9..f5b14318dfcb 100644 > --- a/init/Kconfig > +++ b/init/Kconfig > @@ -2136,10 +2136,6 @@ config ASM_MODVERSIONS > assembly. This can be enabled only when the target architecture > supports it. > > -config MODULE_REL_CRCS > - bool > - depends on MODVERSIONS > - > config MODULE_SRCVERSION_ALL > bool "Source checksum for all modules" > help > diff --git a/kernel/module.c b/kernel/module.c > index 6cea788fd965..c9e2342da28e 100644 > --- a/kernel/module.c > +++ b/kernel/module.c > @@ -1231,11 +1231,6 @@ static int try_to_force_load(struct module *mod, const char *reason) > > #ifdef CONFIG_MODVERSIONS > > -static u32 resolve_rel_crc(const s32 *crc) > -{ > - return *(u32 *)((void *)crc + *crc); > -} > - > static int check_version(const struct load_info *info, > const char *symname, > struct module *mod, > @@ -1264,10 +1259,7 @@ static int check_version(const struct load_info *info, > if (strcmp(versions[i].name, symname) != 0) > continue; > > - if (IS_ENABLED(CONFIG_MODULE_REL_CRCS)) > - crcval = resolve_rel_crc(crc); > - else > - crcval = *crc; > + crcval = *crc; > if (versions[i].crc == crcval) > return 1; > pr_debug("Found checksum %X vs module %lX\n", > diff --git a/scripts/Makefile.build b/scripts/Makefile.build > index a1023868775f..ddd9080fc028 100644 > --- a/scripts/Makefile.build > +++ b/scripts/Makefile.build > @@ -128,7 +128,6 @@ $(obj)/%.i: $(src)/%.c FORCE > > genksyms = scripts/genksyms/genksyms \ > $(if $(1), -T $(2)) \ > - $(if $(CONFIG_MODULE_REL_CRCS), -R) \ > $(if $(KBUILD_PRESERVE), -p) \ > -r $(or $(wildcard $(2:.symtypes=.symref)), /dev/null) > > @@ -162,19 +161,11 @@ ifdef CONFIG_MODVERSIONS > # o if <file>.o doesn't contain a __ksymtab version, i.e. does > # not export symbols, it's done. > # o otherwise, we calculate symbol versions using the good old > -# genksyms on the preprocessed source and postprocess them in a way > -# that they are usable as a linker script > -# o generate .tmp_<file>.o from <file>.o using the linker to > -# replace the unresolved symbols __crc_exported_symbol with > -# the actual value of the checksum generated by genksyms > -# o remove .tmp_<file>.o to <file>.o > +# genksyms on the preprocessed source and dump them into the .cmd file. > +# o modpost will extract versions from that file and create *.c files that will > +# be compiled and linked to the kernel and/or modules. > > -# Generate .o.symversions files for each .o with exported symbols, and link these > -# to the kernel and/or modules at the end. > - > -genksyms_format_rel_crc := [^_]*__crc_\([^ ]*\) = \.; LONG(\([^)]*\)).* > -genksyms_format_normal := __crc_\(.*\) = \(.*\); > -genksyms_format := $(if $(CONFIG_MODULE_REL_CRCS),$(genksyms_format_rel_crc),$(genksyms_format_normal)) > +genksyms_format := __crc_\(.*\) = \(.*\); > > gen_symversions = \ > if $(NM) $@ 2>/dev/null | grep -q __ksymtab; then \ > @@ -188,12 +179,6 @@ gen_symversions = \ > > cmd_gen_symversions_c = $(call gen_symversions,c) > > -cmd_modversions = \ > - if [ -r $@.symversions ]; then \ > - $(LD) $(KBUILD_LDFLAGS) -r -o $(@D)/.tmp_$(@F) $@ \ > - -T $@.symversions; \ > - mv -f $(@D)/.tmp_$(@F) $@; \ > - fi > endif > > ifdef CONFIG_FTRACE_MCOUNT_USE_RECORDMCOUNT > @@ -273,7 +258,6 @@ define rule_cc_o_c > $(call cmd,checkdoc) > $(call cmd,gen_objtooldep) > $(call cmd,gen_symversions_c) > - $(if $(CONFIG_LTO_CLANG),,$(call cmd,modversions)) > $(call cmd,record_mcount) > endef > > @@ -282,7 +266,6 @@ define rule_as_o_S > $(call cmd,gen_ksymdeps) > $(call cmd,gen_objtooldep) > $(call cmd,gen_symversions_S) > - $(call cmd,modversions) > endef > > # Built-in and composite module parts > @@ -296,8 +279,6 @@ ifneq ($(CONFIG_LTO_CLANG)$(CONFIG_X86_KERNEL_IBT),) > quiet_cmd_cc_prelink_modules = LD [M] $@ > cmd_cc_prelink_modules = \ > $(LD) $(ld_flags) -r -o $@ \ > - $(shell [ -s $(@:.prelink.o=.o.symversions) ] && \ > - echo -T $(@:.prelink.o=.o.symversions)) \ > --whole-archive $(filter-out FORCE,$^) \ > $(cmd_objtool) > > diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c > index 4827c5abe5b7..67b23cc0df0f 100644 > --- a/scripts/genksyms/genksyms.c > +++ b/scripts/genksyms/genksyms.c > @@ -33,7 +33,7 @@ char *cur_filename; > int in_source_file; > > static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types, > - flag_preserve, flag_warnings, flag_rel_crcs; > + flag_preserve, flag_warnings; > > static int errors; > static int nsyms; > @@ -680,11 +680,7 @@ void export_symbol(const char *name) > if (flag_dump_defs) > fputs(">\n", debugfile); > > - /* Used as a linker script. */ > - printf(!flag_rel_crcs ? "__crc_%s = 0x%08lx;\n" : > - "SECTIONS { .rodata : ALIGN(4) { " > - "__crc_%s = .; LONG(0x%08lx); } }\n", > - name, crc); > + printf("__crc_%s = 0x%08lx;\n", name, crc); > } > } > > @@ -733,7 +729,6 @@ static void genksyms_usage(void) > " -q, --quiet Disable warnings (default)\n" > " -h, --help Print this message\n" > " -V, --version Print the release version\n" > - " -R, --relative-crc Emit section relative symbol CRCs\n" > #else /* __GNU_LIBRARY__ */ > " -s Select symbol prefix\n" > " -d Increment the debug level (repeatable)\n" > @@ -745,7 +740,6 @@ static void genksyms_usage(void) > " -q Disable warnings (default)\n" > " -h Print this message\n" > " -V Print the release version\n" > - " -R Emit section relative symbol CRCs\n" > #endif /* __GNU_LIBRARY__ */ > , stderr); > } > @@ -766,14 +760,13 @@ int main(int argc, char **argv) > {"preserve", 0, 0, 'p'}, > {"version", 0, 0, 'V'}, > {"help", 0, 0, 'h'}, > - {"relative-crc", 0, 0, 'R'}, > {0, 0, 0, 0} > }; > > - while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR", > + while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph", > &long_opts[0], NULL)) != EOF) > #else /* __GNU_LIBRARY__ */ > - while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF) > + while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF) > #endif /* __GNU_LIBRARY__ */ > switch (o) { > case 'd': > @@ -813,9 +806,6 @@ int main(int argc, char **argv) > case 'h': > genksyms_usage(); > return 0; > - case 'R': > - flag_rel_crcs = 1; > - break; > default: > genksyms_usage(); > return 1; > diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh > index eceb3ee7ec06..7313cbd755df 100755 > --- a/scripts/link-vmlinux.sh > +++ b/scripts/link-vmlinux.sh > @@ -90,7 +90,6 @@ modpost_link() > > if is_enabled CONFIG_MODVERSIONS; then > gen_symversions > - lds="${lds} -T .tmp_symversions.lds" > fi > > # This might take a while, so indicate that we're doing > @@ -183,6 +182,10 @@ vmlinux_link() > libs="${KBUILD_VMLINUX_LIBS}" > fi > > + if is_enabled CONFIG_MODULES; then > + objs="${objs} .vmlinux.export.o" > + fi > + > if [ "${SRCARCH}" = "um" ]; then > wl=-Wl, > ld="${CC}" > @@ -312,6 +315,7 @@ cleanup() > rm -f vmlinux.o > rm -f .vmlinux.d > rm -f .vmlinux.objs > + rm -f .vmlinux.export.c > } > > # Use "make V=1" to debug this script > @@ -363,6 +367,14 @@ info GEN modules.builtin > tr '\0' '\n' < modules.builtin.modinfo | sed -n 's/^[[:alnum:]:_]*\.file=//p' | > tr ' ' '\n' | uniq | sed -e 's:^:kernel/:' -e 's/$/.ko/' > modules.builtin > > +if is_enabled CONFIG_MODULES; then > + info CC .vmlinux.export.c > + ${CC} ${NOSTDINC_FLAGS} ${LINUXINCLUDE} \ > + ${KBUILD_CPPFLAGS} ${KBUILD_CFLAGS} \ > + ${KBUILD_CFLAGS_KERNEL} ${CFLAGS_KERNEL} \ > + -c -o .vmlinux.export.o .vmlinux.export.c > +fi > + > btf_vmlinux_bin_o="" > if is_enabled CONFIG_DEBUG_INFO_BTF; then > btf_vmlinux_bin_o=.btf.vmlinux.bin.o > diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c > index e0f9c02d9f83..6b47a8723389 100644 > --- a/scripts/mod/modpost.c > +++ b/scripts/mod/modpost.c > @@ -1040,6 +1040,7 @@ static void add_header(struct buffer *b, struct module *mod) > buf_printf(b, "#define INCLUDE_VERMAGIC\n"); > buf_printf(b, "#include <linux/build-salt.h>\n"); > buf_printf(b, "#include <linux/elfnote-lto.h>\n"); > + buf_printf(b, "#include <linux/export-internal.h>\n"); > buf_printf(b, "#include <linux/vermagic.h>\n"); > buf_printf(b, "#include <linux/compiler.h>\n"); > buf_printf(b, "\n"); > @@ -1074,20 +1075,26 @@ static void add_header(struct buffer *b, struct module *mod) > buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); > } > > -static void check_symversions(struct module *mod) > +static void add_exported_symbols(struct buffer *buf, struct module *mod) > { > struct symbol *sym; > > if (!modversions) > return; > > + /* record CRCs for exported symbols */ > + buf_printf(buf, "\n"); > list_for_each_entry(sym, &mod->exported_symbols, list) { > if (!sym->crc_valid) { > warn("EXPORT symbol \"%s\" [%s%s] version generation failed, symbol will not be versioned.\n" > "Is \"%s\" prototyped in <asm/asm-prototypes.h>?\n", > sym->name, mod->name, mod->is_vmlinux ? "" : ".ko", > sym->name); > + continue; > } > + > + buf_printf(buf, "SYMBOL_CRC(%s, 0x%08x, \"%s\");\n", > + sym->name, sym->crc, sym->is_gpl_only ? "_gpl" : ""); > } > } > > @@ -1224,6 +1231,18 @@ static void write_if_changed(struct buffer *b, const char *fname) > write_buf(b, fname); > } > > +static void write_vmlinux_export_c_file(struct module *mod) > +{ > + struct buffer buf = { }; > + > + buf_printf(&buf, > + "#include <linux/export-internal.h>\n"); > + > + add_exported_symbols(&buf, mod); > + write_if_changed(&buf, ".vmlinux.export.c"); > + free(buf.p); > +} > + > /* do sanity checks, and generate *.mod.c file */ > static void write_mod_c_file(struct module *mod) > { > @@ -1235,6 +1254,7 @@ static void write_mod_c_file(struct module *mod) > check_exports(mod); > > add_header(&buf, mod); > + add_exported_symbols(&buf, mod); > add_versions(&buf, mod); > add_depends(&buf, mod); > add_moddevtable(&buf, mod); > @@ -1432,9 +1452,9 @@ int main(int argc, char **argv) > if (mod->from_dump) > continue; > > - check_symversions(mod); > - > - if (!mod->is_vmlinux) > + if (mod->is_vmlinux) > + write_vmlinux_export_c_file(mod); > + else > write_mod_c_file(mod); > } > > -- > 2.32.0 Tested-by: Nicolas Schier <nicolas@xxxxxxxxx> Reviewed-by: Nicolas Schier <nicolas@xxxxxxxxx>