forked from mirrors/linux
		
	kbuild: generate KSYMTAB entries by modpost
Commit7b4537199a("kbuild: link symbol CRCs at final link, removing CONFIG_MODULE_REL_CRCS") made modpost output CRCs in the same way whether the EXPORT_SYMBOL() is placed in *.c or *.S. For further cleanups, this commit applies a similar approach to the entire data structure of EXPORT_SYMBOL(). The EXPORT_SYMBOL() compilation is split into two stages. When a source file is compiled, EXPORT_SYMBOL() will be converted into a dummy symbol in the .export_symbol section. For example, EXPORT_SYMBOL(foo); EXPORT_SYMBOL_NS_GPL(bar, BAR_NAMESPACE); will be encoded into the following assembly code: .section ".export_symbol","a" __export_symbol_foo: .asciz "" /* license */ .asciz "" /* name space */ .balign 8 .quad foo /* symbol reference */ .previous .section ".export_symbol","a" __export_symbol_bar: .asciz "GPL" /* license */ .asciz "BAR_NAMESPACE" /* name space */ .balign 8 .quad bar /* symbol reference */ .previous They are mere markers to tell modpost the name, license, and namespace of the symbols. They will be dropped from the final vmlinux and modules because the *(.export_symbol) will go into /DISCARD/ in the linker script. Then, modpost extracts all the information about EXPORT_SYMBOL() from the .export_symbol section, and generates the final C code: KSYMTAB_FUNC(foo, "", ""); KSYMTAB_FUNC(bar, "_gpl", "BAR_NAMESPACE"); KSYMTAB_FUNC() (or KSYMTAB_DATA() if it is data) is expanded to struct kernel_symbol that will be linked to the vmlinux or a module. With this change, EXPORT_SYMBOL() works in the same way for *.c and *.S files, providing the following benefits. [1] Deprecate EXPORT_DATA_SYMBOL() In the old days, EXPORT_SYMBOL() was only available in C files. To export a symbol in *.S, EXPORT_SYMBOL() was placed in a separate *.c file. arch/arm/kernel/armksyms.c is one example written in the classic manner. Commit22823ab419("EXPORT_SYMBOL() for asm") removed this limitation. Since then, EXPORT_SYMBOL() can be placed close to the symbol definition in *.S files. It was a nice improvement. However, as that commit mentioned, you need to use EXPORT_DATA_SYMBOL() for data objects on some architectures. In the new approach, modpost checks symbol's type (STT_FUNC or not), and outputs KSYMTAB_FUNC() or KSYMTAB_DATA() accordingly. There are only two users of EXPORT_DATA_SYMBOL: EXPORT_DATA_SYMBOL_GPL(empty_zero_page) (arch/ia64/kernel/head.S) EXPORT_DATA_SYMBOL(ia64_ivt) (arch/ia64/kernel/ivt.S) They are transformed as follows and output into .vmlinux.export.c KSYMTAB_DATA(empty_zero_page, "_gpl", ""); KSYMTAB_DATA(ia64_ivt, "", ""); The other EXPORT_SYMBOL users in ia64 assembly are output as KSYMTAB_FUNC(). EXPORT_DATA_SYMBOL() is now deprecated. [2] merge <linux/export.h> and <asm-generic/export.h> There are two similar header implementations: include/linux/export.h for .c files include/asm-generic/export.h for .S files Ideally, the functionality should be consistent between them, but they tend to diverge. Commit8651ec01da("module: add support for symbol namespaces.") did not support the namespace for *.S files. This commit shifts the essential implementation part to C, which supports EXPORT_SYMBOL_NS() for *.S files. <asm/export.h> and <asm-generic/export.h> will remain as a wrapper of <linux/export.h> for a while. They will be removed after #include <asm/export.h> directives are all replaced with #include <linux/export.h>. [3] Implement CONFIG_TRIM_UNUSED_KSYMS in one-pass algorithm (by a later commit) 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. We can do this better now; modpost can selectively emit KSYMTAB entries that are really used by modules. Signed-off-by: Masahiro Yamada <masahiroy@kernel.org> Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
This commit is contained in:
		
							parent
							
								
									94d6cb6812
								
							
						
					
					
						commit
						ddb5cdbafa
					
				
					 12 changed files with 190 additions and 184 deletions
				
			
		|  | @ -1,6 +1,7 @@ | |||
| # SPDX-License-Identifier: GPL-2.0 | ||||
| generated-y += syscall_table.h | ||||
| generic-y += agp.h | ||||
| generic-y += export.h | ||||
| generic-y += kvm_para.h | ||||
| generic-y += mcs_spinlock.h | ||||
| generic-y += vtime.h | ||||
|  |  | |||
|  | @ -1,3 +0,0 @@ | |||
| /* EXPORT_DATA_SYMBOL != EXPORT_SYMBOL here */ | ||||
| #define KSYM_FUNC(name) @fptr(name) | ||||
| #include <asm-generic/export.h> | ||||
|  | @ -3,86 +3,12 @@ | |||
| #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. | ||||
|  * <asm/export.h> and <asm-generic/export.h> are deprecated. | ||||
|  * Please include <linux/export.h> directly. | ||||
|  */ | ||||
| #include <linux/export.h> | ||||
| 
 | ||||
| #ifndef KSYM_FUNC | ||||
| #define KSYM_FUNC(x) x | ||||
| #endif | ||||
| #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS | ||||
| #define KSYM_ALIGN 4 | ||||
| #elif defined(CONFIG_64BIT) | ||||
| #define KSYM_ALIGN 8 | ||||
| #else | ||||
| #define KSYM_ALIGN 4 | ||||
| #endif | ||||
| 
 | ||||
| .macro __put, val, name | ||||
| #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS | ||||
| 	.long	\val - ., \name - ., 0 | ||||
| #elif defined(CONFIG_64BIT) | ||||
| 	.quad	\val, \name, 0 | ||||
| #else | ||||
| 	.long	\val, \name, 0 | ||||
| #endif | ||||
| .endm | ||||
| 
 | ||||
| /*
 | ||||
|  * note on .section use: we specify progbits since usage of the "M" (SHF_MERGE) | ||||
|  * section flag requires it. Use '%progbits' instead of '@progbits' since the | ||||
|  * former apparently works on all arches according to the binutils source. | ||||
|  */ | ||||
| 
 | ||||
| .macro ___EXPORT_SYMBOL name,val,sec | ||||
| #if defined(CONFIG_MODULES) && !defined(__DISABLE_EXPORTS) | ||||
| 	.section ___ksymtab\sec+\name,"a" | ||||
| 	.balign KSYM_ALIGN | ||||
| __ksymtab_\name: | ||||
| 	__put \val, __kstrtab_\name | ||||
| 	.previous | ||||
| 	.section __ksymtab_strings,"aMS",%progbits,1 | ||||
| __kstrtab_\name: | ||||
| 	.asciz "\name" | ||||
| 	.previous | ||||
| #endif | ||||
| .endm | ||||
| 
 | ||||
| #if defined(CONFIG_TRIM_UNUSED_KSYMS) | ||||
| 
 | ||||
| #include <linux/kconfig.h> | ||||
| #include <generated/autoksyms.h> | ||||
| 
 | ||||
| .macro __ksym_marker sym | ||||
| 	.section ".discard.ksym","a" | ||||
| __ksym_marker_\sym: | ||||
| 	 .previous | ||||
| .endm | ||||
| 
 | ||||
| #define __EXPORT_SYMBOL(sym, val, sec)				\ | ||||
| 	__ksym_marker sym;					\ | ||||
| 	__cond_export_sym(sym, val, sec, __is_defined(__KSYM_##sym)) | ||||
| #define __cond_export_sym(sym, val, sec, conf)			\ | ||||
| 	___cond_export_sym(sym, val, sec, conf) | ||||
| #define ___cond_export_sym(sym, val, sec, enabled)		\ | ||||
| 	__cond_export_sym_##enabled(sym, val, sec) | ||||
| #define __cond_export_sym_1(sym, val, sec) ___EXPORT_SYMBOL sym, val, sec | ||||
| #define __cond_export_sym_0(sym, val, sec) /* nothing */ | ||||
| 
 | ||||
| #else | ||||
| #define __EXPORT_SYMBOL(sym, val, sec) ___EXPORT_SYMBOL sym, val, sec | ||||
| #endif | ||||
| 
 | ||||
| #define EXPORT_SYMBOL(name)					\ | ||||
| 	__EXPORT_SYMBOL(name, KSYM_FUNC(name),) | ||||
| #define EXPORT_SYMBOL_GPL(name) 				\ | ||||
| 	__EXPORT_SYMBOL(name, KSYM_FUNC(name), _gpl) | ||||
| #define EXPORT_DATA_SYMBOL(name)				\ | ||||
| 	__EXPORT_SYMBOL(name, name,) | ||||
| #define EXPORT_DATA_SYMBOL_GPL(name)				\ | ||||
| 	__EXPORT_SYMBOL(name, name,_gpl) | ||||
| #define EXPORT_DATA_SYMBOL(name)	EXPORT_SYMBOL(name) | ||||
| #define EXPORT_DATA_SYMBOL_GPL(name)	EXPORT_SYMBOL_GPL(name) | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -1006,6 +1006,7 @@ | |||
| 	PATCHABLE_DISCARDS						\ | ||||
| 	*(.discard)							\ | ||||
| 	*(.discard.*)							\ | ||||
| 	*(.export_symbol)						\ | ||||
| 	*(.modinfo)							\ | ||||
| 	/* ld.bfd warns about .gnu.version* even when not emitted */	\ | ||||
| 	*(.gnu.version*)						\ | ||||
|  |  | |||
|  | @ -10,6 +10,55 @@ | |||
| #include <linux/compiler.h> | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| #if defined(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS) | ||||
| /*
 | ||||
|  * relative reference: this reduces the size by half on 64-bit architectures, | ||||
|  * and eliminates the need for absolute relocations that require runtime | ||||
|  * processing on relocatable kernels. | ||||
|  */ | ||||
| #define __KSYM_REF(sym)		".long " #sym "- ." | ||||
| #elif defined(CONFIG_64BIT) | ||||
| #define __KSYM_REF(sym)		".quad " #sym | ||||
| #else | ||||
| #define __KSYM_REF(sym)		".long " #sym | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * For every exported symbol, do the following: | ||||
|  * | ||||
|  * - 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. | ||||
|  * | ||||
|  * Note on .section use: we specify progbits since usage of the "M" (SHF_MERGE) | ||||
|  * section flag requires it. Use '%progbits' instead of '@progbits' since the | ||||
|  * former apparently works on all arches according to the binutils source. | ||||
|  */ | ||||
| #define __KSYMTAB(name, sym, sec, ns)						\ | ||||
| 	asm("	.section \"__ksymtab_strings\",\"aMS\",%progbits,1"	"\n"	\ | ||||
| 	    "__kstrtab_" #name ":"					"\n"	\ | ||||
| 	    "	.asciz \"" #name "\""					"\n"	\ | ||||
| 	    "__kstrtabns_" #name ":"					"\n"	\ | ||||
| 	    "	.asciz \"" ns "\""					"\n"	\ | ||||
| 	    "	.previous"						"\n"	\ | ||||
| 	    "	.section \"___ksymtab" sec "+" #name "\", \"a\""	"\n"	\ | ||||
| 	    "	.balign	4"						"\n"	\ | ||||
| 	    "__ksymtab_" #name ":"					"\n"	\ | ||||
| 		__KSYM_REF(sym)						"\n"	\ | ||||
| 		__KSYM_REF(__kstrtab_ ##name)				"\n"	\ | ||||
| 		__KSYM_REF(__kstrtabns_ ##name)				"\n"	\ | ||||
| 	    "	.previous"						"\n"	\ | ||||
| 	) | ||||
| 
 | ||||
| #ifdef CONFIG_IA64 | ||||
| #define KSYM_FUNC(name)		@fptr(name) | ||||
| #else | ||||
| #define KSYM_FUNC(name)		name | ||||
| #endif | ||||
| 
 | ||||
| #define KSYMTAB_FUNC(name, sec, ns)	__KSYMTAB(name, KSYM_FUNC(name), sec, ns) | ||||
| #define KSYMTAB_DATA(name, sec, ns)	__KSYMTAB(name, name, sec, ns) | ||||
| 
 | ||||
| #define SYMBOL_CRC(sym, crc, sec)   \ | ||||
| 	asm(".section \"___kcrctab" sec "+" #sym "\",\"a\""	"\n" \ | ||||
| 	    "__crc_" #sym ":"					"\n" \ | ||||
|  |  | |||
|  | @ -2,6 +2,8 @@ | |||
| #ifndef _LINUX_EXPORT_H | ||||
| #define _LINUX_EXPORT_H | ||||
| 
 | ||||
| #include <linux/compiler.h> | ||||
| #include <linux/linkage.h> | ||||
| #include <linux/stringify.h> | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -28,72 +30,41 @@ extern struct module __this_module; | |||
| #else | ||||
| #define THIS_MODULE ((struct module *)0) | ||||
| #endif | ||||
| #endif /* __ASSEMBLY__ */ | ||||
| 
 | ||||
| #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS | ||||
| #include <linux/compiler.h> | ||||
| /*
 | ||||
|  * Emit the ksymtab entry as a pair of relative references: this reduces | ||||
|  * the size by half on 64-bit architectures, and eliminates the need for | ||||
|  * absolute relocations that require runtime processing on relocatable | ||||
|  * kernels. | ||||
|  */ | ||||
| #define __KSYMTAB_ENTRY(sym, sec)					\ | ||||
| 	__ADDRESSABLE(sym)						\ | ||||
| 	asm("	.section \"___ksymtab" sec "+" #sym "\", \"a\"	\n"	\ | ||||
| 	    "	.balign	4					\n"	\ | ||||
| 	    "__ksymtab_" #sym ":				\n"	\ | ||||
| 	    "	.long	" #sym "- .				\n"	\ | ||||
| 	    "	.long	__kstrtab_" #sym "- .			\n"	\ | ||||
| 	    "	.long	__kstrtabns_" #sym "- .			\n"	\ | ||||
| 	    "	.previous					\n") | ||||
| 
 | ||||
| struct kernel_symbol { | ||||
| 	int value_offset; | ||||
| 	int name_offset; | ||||
| 	int namespace_offset; | ||||
| }; | ||||
| #ifdef CONFIG_64BIT | ||||
| #define __EXPORT_SYMBOL_REF(sym)			\ | ||||
| 	.balign 8				ASM_NL	\ | ||||
| 	.quad sym | ||||
| #else | ||||
| #define __KSYMTAB_ENTRY(sym, sec)					\ | ||||
| 	static const struct kernel_symbol __ksymtab_##sym		\ | ||||
| 	__attribute__((section("___ksymtab" sec "+" #sym), used))	\ | ||||
| 	__aligned(sizeof(void *))					\ | ||||
| 	= { (unsigned long)&sym, __kstrtab_##sym, __kstrtabns_##sym } | ||||
| 
 | ||||
| struct kernel_symbol { | ||||
| 	unsigned long value; | ||||
| 	const char *name; | ||||
| 	const char *namespace; | ||||
| }; | ||||
| #define __EXPORT_SYMBOL_REF(sym)			\ | ||||
| 	.balign 4				ASM_NL	\ | ||||
| 	.long sym | ||||
| #endif | ||||
| 
 | ||||
| #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 | ||||
| 
 | ||||
| /*
 | ||||
|  * For every exported symbol, do the following: | ||||
|  * | ||||
|  * - 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. | ||||
|  * | ||||
|  * note on .section use: we specify progbits since usage of the "M" (SHF_MERGE) | ||||
|  * section flag requires it. Use '%progbits' instead of '@progbits' since the | ||||
|  * former apparently works on all arches according to the binutils source. | ||||
|  */ | ||||
| #define ___EXPORT_SYMBOL(sym, sec, ns)						\ | ||||
| #define ___EXPORT_SYMBOL(sym, license, ns)			\ | ||||
| 	extern typeof(sym) sym;					\ | ||||
| 	extern const char __kstrtab_##sym[];					\ | ||||
| 	extern const char __kstrtabns_##sym[];					\ | ||||
| 	asm("	.section \"__ksymtab_strings\",\"aMS\",%progbits,1	\n"	\ | ||||
| 	    "__kstrtab_" #sym ":					\n"	\ | ||||
| 	    "	.asciz 	\"" #sym "\"					\n"	\ | ||||
| 	    "__kstrtabns_" #sym ":					\n"	\ | ||||
| 	    "	.asciz 	\"" ns "\"					\n"	\ | ||||
| 	    "	.previous						\n");	\ | ||||
| 	__KSYMTAB_ENTRY(sym, sec) | ||||
| 	__ADDRESSABLE(sym)					\ | ||||
| 	asm(__stringify(____EXPORT_SYMBOL(sym, license, ns))) | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
|  | @ -117,9 +88,21 @@ struct kernel_symbol { | |||
|  * 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 | ||||
| 
 | ||||
| #define __EXPORT_SYMBOL(sym, sec, ns)					\ | ||||
| 	__ksym_marker(sym);						\ | ||||
| 	__cond_export_sym(sym, sec, ns, __is_defined(__KSYM_##sym)) | ||||
|  | @ -148,10 +131,8 @@ struct kernel_symbol { | |||
| #endif | ||||
| 
 | ||||
| #define EXPORT_SYMBOL(sym)		_EXPORT_SYMBOL(sym, "") | ||||
| #define EXPORT_SYMBOL_GPL(sym)		_EXPORT_SYMBOL(sym, "_gpl") | ||||
| #define EXPORT_SYMBOL_GPL(sym)		_EXPORT_SYMBOL(sym, "GPL") | ||||
| #define EXPORT_SYMBOL_NS(sym, ns)	__EXPORT_SYMBOL(sym, "", __stringify(ns)) | ||||
| #define EXPORT_SYMBOL_NS_GPL(sym, ns)	__EXPORT_SYMBOL(sym, "_gpl", __stringify(ns)) | ||||
| 
 | ||||
| #endif /* !__ASSEMBLY__ */ | ||||
| #define EXPORT_SYMBOL_NS_GPL(sym, ns)	__EXPORT_SYMBOL(sym, "GPL", __stringify(ns)) | ||||
| 
 | ||||
| #endif /* _LINUX_EXPORT_H */ | ||||
|  |  | |||
|  | @ -389,9 +389,9 @@ const struct dev_pm_ops name = { \ | |||
| #endif | ||||
| 
 | ||||
| #define EXPORT_DEV_PM_OPS(name) _EXPORT_DEV_PM_OPS(name, "", "") | ||||
| #define EXPORT_GPL_DEV_PM_OPS(name) _EXPORT_DEV_PM_OPS(name, "_gpl", "") | ||||
| #define EXPORT_GPL_DEV_PM_OPS(name) _EXPORT_DEV_PM_OPS(name, "GPL", "") | ||||
| #define EXPORT_NS_DEV_PM_OPS(name, ns) _EXPORT_DEV_PM_OPS(name, "", #ns) | ||||
| #define EXPORT_NS_GPL_DEV_PM_OPS(name, ns) _EXPORT_DEV_PM_OPS(name, "_gpl", #ns) | ||||
| #define EXPORT_NS_GPL_DEV_PM_OPS(name, ns) _EXPORT_DEV_PM_OPS(name, "GPL", #ns) | ||||
| 
 | ||||
| /*
 | ||||
|  * Use this if you want to use the same suspend and resume callbacks for suspend | ||||
|  |  | |||
|  | @ -32,6 +32,18 @@ | |||
| /* Maximum number of characters written by module_flags() */ | ||||
| #define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4) | ||||
| 
 | ||||
| struct kernel_symbol { | ||||
| #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS | ||||
| 	int value_offset; | ||||
| 	int name_offset; | ||||
| 	int namespace_offset; | ||||
| #else | ||||
| 	unsigned long value; | ||||
| 	const char *name; | ||||
| 	const char *namespace; | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| extern struct mutex module_mutex; | ||||
| extern struct list_head modules; | ||||
| 
 | ||||
|  |  | |||
|  | @ -163,7 +163,7 @@ quiet_cmd_cc_o_c = CC $(quiet_modtag)  $@ | |||
| ifdef CONFIG_MODVERSIONS | ||||
| # When module versioning is enabled the following steps are executed: | ||||
| # o compile a <file>.o from <file>.c | ||||
| # o if <file>.o doesn't contain a __ksymtab version, i.e. does | ||||
| # o if <file>.o doesn't contain a __export_symbol_*, 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 dump them into the .cmd file. | ||||
|  | @ -171,7 +171,7 @@ ifdef CONFIG_MODVERSIONS | |||
| #   be compiled and linked to the kernel and/or modules. | ||||
| 
 | ||||
| gen_symversions =								\ | ||||
| 	if $(NM) $@ 2>/dev/null | grep -q __ksymtab; then			\ | ||||
| 	if $(NM) $@ 2>/dev/null | grep -q ' __export_symbol_'; then		\ | ||||
| 		$(call cmd_gensymtypes_$(1),$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ | ||||
| 			>> $(dot-target).cmd;					\ | ||||
| 	fi | ||||
|  | @ -342,9 +342,7 @@ $(obj)/%.ll: $(src)/%.rs FORCE | |||
| cmd_gensymtypes_S =                                                         \ | ||||
|    { echo "\#include <linux/kernel.h>" ;                                    \ | ||||
|      echo "\#include <asm/asm-prototypes.h>" ;                              \ | ||||
|     $(CPP) $(a_flags) $< |                                                  \ | ||||
|      grep "\<___EXPORT_SYMBOL\>" |                                          \ | ||||
|      sed 's/.*___EXPORT_SYMBOL[[:space:]]*\([a-zA-Z0-9_]*\)[[:space:]]*,.*/EXPORT_SYMBOL(\1);/' ; } | \ | ||||
|      $(NM) $@ | sed -n 's/.* __export_symbol_\(.*\)/EXPORT_SYMBOL(\1);/p' ; } | \ | ||||
|     $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | $(genksyms) | ||||
| 
 | ||||
| quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@ | ||||
|  |  | |||
|  | @ -46,9 +46,9 @@ BEGIN { | |||
| { symbol_types[$3]=$2 } | ||||
| 
 | ||||
| # append the exported symbol to the array | ||||
| ($3 ~ /^__ksymtab_/) { | ||||
| ($3 ~ /^__export_symbol_.*/) { | ||||
| 	export_symbols[i] = $3 | ||||
| 	sub(/^__ksymtab_/, "", export_symbols[i]) | ||||
| 	sub(/^__export_symbol_/, "", export_symbols[i]) | ||||
| 	i++ | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -217,6 +217,7 @@ struct symbol { | |||
| 	unsigned int crc; | ||||
| 	bool crc_valid; | ||||
| 	bool weak; | ||||
| 	bool is_func; | ||||
| 	bool is_gpl_only;	/* exported by EXPORT_SYMBOL_GPL */ | ||||
| 	char name[]; | ||||
| }; | ||||
|  | @ -533,6 +534,8 @@ static int parse_elf(struct elf_info *info, const char *filename) | |||
| 				fatal("%s has NOBITS .modinfo\n", filename); | ||||
| 			info->modinfo = (void *)hdr + sechdrs[i].sh_offset; | ||||
| 			info->modinfo_len = sechdrs[i].sh_size; | ||||
| 		} else if (!strcmp(secname, ".export_symbol")) { | ||||
| 			info->export_symbol_secndx = i; | ||||
| 		} | ||||
| 
 | ||||
| 		if (sechdrs[i].sh_type == SHT_SYMTAB) { | ||||
|  | @ -655,18 +658,6 @@ static void handle_symbol(struct module *mod, struct elf_info *info, | |||
| 				   ELF_ST_BIND(sym->st_info) == STB_WEAK); | ||||
| 		break; | ||||
| 	default: | ||||
| 		/* All exported symbols */ | ||||
| 		if (strstarts(symname, "__ksymtab_")) { | ||||
| 			const char *name, *secname; | ||||
| 
 | ||||
| 			name = symname + strlen("__ksymtab_"); | ||||
| 			secname = sec_name(info, get_secindex(info, sym)); | ||||
| 
 | ||||
| 			if (strstarts(secname, "___ksymtab_gpl+")) | ||||
| 				sym_add_exported(name, mod, true); | ||||
| 			else if (strstarts(secname, "___ksymtab+")) | ||||
| 				sym_add_exported(name, mod, false); | ||||
| 		} | ||||
| 		if (strcmp(symname, "init_module") == 0) | ||||
| 			mod->has_init = true; | ||||
| 		if (strcmp(symname, "cleanup_module") == 0) | ||||
|  | @ -848,7 +839,6 @@ enum mismatch { | |||
| 	XXXEXIT_TO_SOME_EXIT, | ||||
| 	ANY_INIT_TO_ANY_EXIT, | ||||
| 	ANY_EXIT_TO_ANY_INIT, | ||||
| 	EXPORT_TO_INIT_EXIT, | ||||
| 	EXTABLE_TO_NON_TEXT, | ||||
| }; | ||||
| 
 | ||||
|  | @ -920,12 +910,6 @@ static const struct sectioncheck sectioncheck[] = { | |||
| 	.bad_tosec = { INIT_SECTIONS, NULL }, | ||||
| 	.mismatch = ANY_INIT_TO_ANY_EXIT, | ||||
| }, | ||||
| /* Do not export init/exit functions or data */ | ||||
| { | ||||
| 	.fromsec = { "___ksymtab*", NULL }, | ||||
| 	.bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, | ||||
| 	.mismatch = EXPORT_TO_INIT_EXIT, | ||||
| }, | ||||
| { | ||||
| 	.fromsec = { "__ex_table", NULL }, | ||||
| 	/* If you're adding any new black-listed sections in here, consider
 | ||||
|  | @ -1180,10 +1164,6 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, | |||
| 		warn("%s: section mismatch in reference: %s (section: %s) -> %s (section: %s)\n", | ||||
| 		     modname, fromsym, fromsec, tosym, tosec); | ||||
| 		break; | ||||
| 	case EXPORT_TO_INIT_EXIT: | ||||
| 		warn("%s: EXPORT_SYMBOL used for init/exit symbol: %s (section: %s)\n", | ||||
| 		     modname, tosym, tosec); | ||||
| 		break; | ||||
| 	case EXTABLE_TO_NON_TEXT: | ||||
| 		warn("%s(%s+0x%lx): Section mismatch in reference to the %s:%s\n", | ||||
| 		     modname, fromsec, (long)faddr, tosec, tosym); | ||||
|  | @ -1211,14 +1191,75 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf, | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void check_export_symbol(struct module *mod, struct elf_info *elf, | ||||
| 				Elf_Addr faddr, const char *secname, | ||||
| 				Elf_Sym *sym) | ||||
| { | ||||
| 	static const char *prefix = "__export_symbol_"; | ||||
| 	const char *label_name, *name, *data; | ||||
| 	Elf_Sym *label; | ||||
| 	struct symbol *s; | ||||
| 	bool is_gpl; | ||||
| 
 | ||||
| 	label = find_fromsym(elf, faddr, elf->export_symbol_secndx); | ||||
| 	label_name = sym_name(elf, label); | ||||
| 
 | ||||
| 	if (!strstarts(label_name, prefix)) { | ||||
| 		error("%s: .export_symbol section contains strange symbol '%s'\n", | ||||
| 		      mod->name, label_name); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	name = sym_name(elf, sym); | ||||
| 	if (strcmp(label_name + strlen(prefix), name)) { | ||||
| 		error("%s: .export_symbol section references '%s', but it does not seem to be an export symbol\n", | ||||
| 		      mod->name, name); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	data = sym_get_data(elf, label);	/* license */ | ||||
| 	if (!strcmp(data, "GPL")) { | ||||
| 		is_gpl = true; | ||||
| 	} else if (!strcmp(data, "")) { | ||||
| 		is_gpl = false; | ||||
| 	} else { | ||||
| 		error("%s: unknown license '%s' was specified for '%s'\n", | ||||
| 		      mod->name, data, name); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	data += strlen(data) + 1;	/* namespace */ | ||||
| 	s = sym_add_exported(name, mod, is_gpl); | ||||
| 	sym_update_namespace(name, data); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We need to be aware whether we are exporting a function or | ||||
| 	 * a data on some architectures. | ||||
| 	 */ | ||||
| 	s->is_func = (ELF_ST_TYPE(sym->st_info) == STT_FUNC); | ||||
| 
 | ||||
| 	if (match(secname, PATTERNS(INIT_SECTIONS))) | ||||
| 		warn("%s: %s: EXPORT_SYMBOL used for init symbol. Remove __init or EXPORT_SYMBOL.\n", | ||||
| 		     mod->name, name); | ||||
| 	else if (match(secname, PATTERNS(EXIT_SECTIONS))) | ||||
| 		warn("%s: %s: EXPORT_SYMBOL used for exit symbol. Remove __exit or EXPORT_SYMBOL.\n", | ||||
| 		     mod->name, name); | ||||
| } | ||||
| 
 | ||||
| static void check_section_mismatch(struct module *mod, struct elf_info *elf, | ||||
| 				   Elf_Sym *sym, | ||||
| 				   unsigned int fsecndx, const char *fromsec, | ||||
| 				   Elf_Addr faddr, Elf_Addr taddr) | ||||
| { | ||||
| 	const char *tosec = sec_name(elf, get_secindex(elf, sym)); | ||||
| 	const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec); | ||||
| 	const struct sectioncheck *mismatch; | ||||
| 
 | ||||
| 	if (elf->export_symbol_secndx == fsecndx) { | ||||
| 		check_export_symbol(mod, elf, faddr, tosec, sym); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	mismatch = section_mismatch(fromsec, tosec); | ||||
| 	if (!mismatch) | ||||
| 		return; | ||||
| 
 | ||||
|  | @ -1698,15 +1739,6 @@ static void read_symbols(const char *modname) | |||
| 		handle_moddevtable(mod, &info, sym, symname); | ||||
| 	} | ||||
| 
 | ||||
| 	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { | ||||
| 		symname = remove_dot(info.strtab + sym->st_name); | ||||
| 
 | ||||
| 		/* Apply symbol namespaces from __kstrtabns_<symbol> entries. */ | ||||
| 		if (strstarts(symname, "__kstrtabns_")) | ||||
| 			sym_update_namespace(symname + strlen("__kstrtabns_"), | ||||
| 					     sym_get_data(&info, sym)); | ||||
| 	} | ||||
| 
 | ||||
| 	check_sec_ref(mod, &info); | ||||
| 
 | ||||
| 	if (!mod->is_vmlinux) { | ||||
|  | @ -1890,6 +1922,14 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod) | |||
| { | ||||
| 	struct symbol *sym; | ||||
| 
 | ||||
| 	/* generate struct for exported symbols */ | ||||
| 	buf_printf(buf, "\n"); | ||||
| 	list_for_each_entry(sym, &mod->exported_symbols, list) | ||||
| 		buf_printf(buf, "KSYMTAB_%s(%s, \"%s\", \"%s\");\n", | ||||
| 			   sym->is_func ? "FUNC" : "DATA", sym->name, | ||||
| 			   sym->is_gpl_only ? "_gpl" : "", | ||||
| 			   sym->namespace ?: ""); | ||||
| 
 | ||||
| 	if (!modversions) | ||||
| 		return; | ||||
| 
 | ||||
|  |  | |||
|  | @ -137,6 +137,7 @@ struct elf_info { | |||
| 	Elf_Shdr     *sechdrs; | ||||
| 	Elf_Sym      *symtab_start; | ||||
| 	Elf_Sym      *symtab_stop; | ||||
| 	unsigned int export_symbol_secndx;	/* .export_symbol section */ | ||||
| 	char         *strtab; | ||||
| 	char	     *modinfo; | ||||
| 	unsigned int modinfo_len; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Masahiro Yamada
						Masahiro Yamada