Skip to content

Commit

Permalink
kbuild: link symbol CRCs at final link, removing CONFIG_MODULE_REL_CRCS
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
masahir0y committed May 24, 2022
1 parent f292d87 commit 7b45371
Show file tree
Hide file tree
Showing 15 changed files with 108 additions and 96 deletions.
1 change: 1 addition & 0 deletions arch/m68k/include/asm/Kbuild
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 0 additions & 2 deletions arch/m68k/include/asm/export.h

This file was deleted.

1 change: 0 additions & 1 deletion arch/powerpc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion arch/s390/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion arch/um/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 8 additions & 14 deletions include/asm-generic/export.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down
17 changes: 17 additions & 0 deletions include/linux/export-internal.h
Original file line number Diff line number Diff line change
@@ -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__ */
30 changes: 8 additions & 22 deletions include/linux/export.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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>
/*
Expand Down Expand Up @@ -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.
Expand All @@ -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" \
Expand Down
4 changes: 0 additions & 4 deletions init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 1 addition & 9 deletions kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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",
Expand Down
27 changes: 4 additions & 23 deletions scripts/Makefile.build
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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 \
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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)

Expand Down
32 changes: 32 additions & 0 deletions scripts/Makefile.vmlinux
Original file line number Diff line number Diff line change
@@ -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)
18 changes: 4 additions & 14 deletions scripts/genksyms/genksyms.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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"
Expand All @@ -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);
}
Expand All @@ -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':
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 9 additions & 1 deletion scripts/link-vmlinux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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}"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 7b45371

Please sign in to comment.