kbuild: link symbol CRCs at final link, removing CONFIG_MODULE_REL_CRCS
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@kernel.org> Tested-by: Nathan Chancellor <nathan@kernel.org> Tested-by: Nicolas Schier <nicolas@fjasle.eu> Reviewed-by: Nicolas Schier <nicolas@fjasle.eu> Tested-by: Sedat Dilek <sedat.dilek@gmail.com> # LLVM-14 (x86-64)
This commit is contained in:
parent
f292d875d0
commit
7b4537199a
|
@ -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
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
#define KCRC_ALIGN 2
|
||||
#include <asm-generic/export.h>
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/* 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>
|
||||
|
||||
/* __used is needed to keep __crc_* for LTO */
|
||||
#define SYMBOL_CRC(sym, crc, sec) \
|
||||
u32 __section("___kcrctab" sec "+" #sym) __used __crc_##sym = crc
|
||||
|
||||
#endif /* __LINUX_EXPORT_INTERNAL_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" \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
include include/config/auto.conf
|
||||
include $(srctree)/scripts/Kbuild.include
|
||||
|
||||
# for c_flags
|
||||
include $(srctree)/scripts/Makefile.lib
|
||||
|
||||
quiet_cmd_cc_o_c = CC $@
|
||||
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
|
||||
|
||||
%.o: %.c FORCE
|
||||
$(call if_changed_dep,cc_o_c)
|
||||
|
||||
targets := $(MAKECMDGOALS)
|
||||
|
||||
# Add FORCE to the prequisites 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)
|
|
@ -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;
|
||||
|
|
|
@ -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,10 @@ 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
|
||||
${MAKE} -f "${srctree}/scripts/Makefile.vmlinux" .vmlinux.export.o
|
||||
fi
|
||||
|
||||
btf_vmlinux_bin_o=""
|
||||
if is_enabled CONFIG_DEBUG_INFO_BTF; then
|
||||
btf_vmlinux_bin_o=.btf.vmlinux.bin.o
|
||||
|
|
|
@ -2234,6 +2234,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");
|
||||
|
@ -2268,20 +2269,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" : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2418,6 +2425,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)
|
||||
{
|
||||
|
@ -2429,6 +2448,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);
|
||||
|
@ -2626,9 +2646,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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue