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
@ -1,6 +1,7 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
generated-y += syscall_table.h
|
generated-y += syscall_table.h
|
||||||
generic-y += agp.h
|
generic-y += agp.h
|
||||||
|
generic-y += export.h
|
||||||
generic-y += kvm_para.h
|
generic-y += kvm_para.h
|
||||||
generic-y += mcs_spinlock.h
|
generic-y += mcs_spinlock.h
|
||||||
generic-y += vtime.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
|
#define __ASM_GENERIC_EXPORT_H
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This comment block is used by fixdep. Please do not remove.
|
* <asm/export.h> and <asm-generic/export.h> are deprecated.
|
||||||
*
|
* Please include <linux/export.h> directly.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
|
#include <linux/export.h>
|
||||||
|
|
||||||
#ifndef KSYM_FUNC
|
#define EXPORT_DATA_SYMBOL(name) EXPORT_SYMBOL(name)
|
||||||
#define KSYM_FUNC(x) x
|
#define EXPORT_DATA_SYMBOL_GPL(name) EXPORT_SYMBOL_GPL(name)
|
||||||
#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)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1006,6 +1006,7 @@
|
|||||||
PATCHABLE_DISCARDS \
|
PATCHABLE_DISCARDS \
|
||||||
*(.discard) \
|
*(.discard) \
|
||||||
*(.discard.*) \
|
*(.discard.*) \
|
||||||
|
*(.export_symbol) \
|
||||||
*(.modinfo) \
|
*(.modinfo) \
|
||||||
/* ld.bfd warns about .gnu.version* even when not emitted */ \
|
/* ld.bfd warns about .gnu.version* even when not emitted */ \
|
||||||
*(.gnu.version*) \
|
*(.gnu.version*) \
|
||||||
|
@ -10,6 +10,55 @@
|
|||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <linux/types.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) \
|
#define SYMBOL_CRC(sym, crc, sec) \
|
||||||
asm(".section \"___kcrctab" sec "+" #sym "\",\"a\"" "\n" \
|
asm(".section \"___kcrctab" sec "+" #sym "\",\"a\"" "\n" \
|
||||||
"__crc_" #sym ":" "\n" \
|
"__crc_" #sym ":" "\n" \
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#ifndef _LINUX_EXPORT_H
|
#ifndef _LINUX_EXPORT_H
|
||||||
#define _LINUX_EXPORT_H
|
#define _LINUX_EXPORT_H
|
||||||
|
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/linkage.h>
|
||||||
#include <linux/stringify.h>
|
#include <linux/stringify.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -28,72 +30,41 @@ extern struct module __this_module;
|
|||||||
#else
|
#else
|
||||||
#define THIS_MODULE ((struct module *)0)
|
#define THIS_MODULE ((struct module *)0)
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
|
#ifdef CONFIG_64BIT
|
||||||
#include <linux/compiler.h>
|
#define __EXPORT_SYMBOL_REF(sym) \
|
||||||
/*
|
.balign 8 ASM_NL \
|
||||||
* Emit the ksymtab entry as a pair of relative references: this reduces
|
.quad sym
|
||||||
* 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;
|
|
||||||
};
|
|
||||||
#else
|
#else
|
||||||
#define __KSYMTAB_ENTRY(sym, sec) \
|
#define __EXPORT_SYMBOL_REF(sym) \
|
||||||
static const struct kernel_symbol __ksymtab_##sym \
|
.balign 4 ASM_NL \
|
||||||
__attribute__((section("___ksymtab" sec "+" #sym), used)) \
|
.long sym
|
||||||
__aligned(sizeof(void *)) \
|
|
||||||
= { (unsigned long)&sym, __kstrtab_##sym, __kstrtabns_##sym }
|
|
||||||
|
|
||||||
struct kernel_symbol {
|
|
||||||
unsigned long value;
|
|
||||||
const char *name;
|
|
||||||
const char *namespace;
|
|
||||||
};
|
|
||||||
#endif
|
#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__
|
#ifdef __GENKSYMS__
|
||||||
|
|
||||||
#define ___EXPORT_SYMBOL(sym, sec, ns) __GENKSYMS_EXPORT_SYMBOL(sym)
|
#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
|
#else
|
||||||
|
|
||||||
/*
|
#define ___EXPORT_SYMBOL(sym, license, ns) \
|
||||||
* 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) \
|
|
||||||
extern typeof(sym) sym; \
|
extern typeof(sym) sym; \
|
||||||
extern const char __kstrtab_##sym[]; \
|
__ADDRESSABLE(sym) \
|
||||||
extern const char __kstrtabns_##sym[]; \
|
asm(__stringify(____EXPORT_SYMBOL(sym, license, ns)))
|
||||||
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)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -117,9 +88,21 @@ struct kernel_symbol {
|
|||||||
* from the $(NM) output (see scripts/gen_ksymdeps.sh). These symbols are
|
* from the $(NM) output (see scripts/gen_ksymdeps.sh). These symbols are
|
||||||
* discarded in the final link stage.
|
* 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) \
|
#define __ksym_marker(sym) \
|
||||||
static int __ksym_marker_##sym[0] __section(".discard.ksym") __used
|
static int __ksym_marker_##sym[0] __section(".discard.ksym") __used
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#define __EXPORT_SYMBOL(sym, sec, ns) \
|
#define __EXPORT_SYMBOL(sym, sec, ns) \
|
||||||
__ksym_marker(sym); \
|
__ksym_marker(sym); \
|
||||||
__cond_export_sym(sym, sec, ns, __is_defined(__KSYM_##sym))
|
__cond_export_sym(sym, sec, ns, __is_defined(__KSYM_##sym))
|
||||||
@ -148,10 +131,8 @@ struct kernel_symbol {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EXPORT_SYMBOL(sym) _EXPORT_SYMBOL(sym, "")
|
#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(sym, ns) __EXPORT_SYMBOL(sym, "", __stringify(ns))
|
||||||
#define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "_gpl", __stringify(ns))
|
#define EXPORT_SYMBOL_NS_GPL(sym, ns) __EXPORT_SYMBOL(sym, "GPL", __stringify(ns))
|
||||||
|
|
||||||
#endif /* !__ASSEMBLY__ */
|
|
||||||
|
|
||||||
#endif /* _LINUX_EXPORT_H */
|
#endif /* _LINUX_EXPORT_H */
|
||||||
|
@ -389,9 +389,9 @@ const struct dev_pm_ops name = { \
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EXPORT_DEV_PM_OPS(name) _EXPORT_DEV_PM_OPS(name, "", "")
|
#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_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
|
* 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() */
|
/* Maximum number of characters written by module_flags() */
|
||||||
#define MODULE_FLAGS_BUF_SIZE (TAINT_FLAGS_COUNT + 4)
|
#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 mutex module_mutex;
|
||||||
extern struct list_head modules;
|
extern struct list_head modules;
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
|
|||||||
ifdef CONFIG_MODVERSIONS
|
ifdef CONFIG_MODVERSIONS
|
||||||
# When module versioning is enabled the following steps are executed:
|
# When module versioning is enabled the following steps are executed:
|
||||||
# o compile a <file>.o from <file>.c
|
# 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.
|
# not export symbols, it's done.
|
||||||
# o otherwise, we calculate symbol versions using the good old
|
# o otherwise, we calculate symbol versions using the good old
|
||||||
# genksyms on the preprocessed source and dump them into the .cmd file.
|
# 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.
|
# be compiled and linked to the kernel and/or modules.
|
||||||
|
|
||||||
gen_symversions = \
|
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)) \
|
$(call cmd_gensymtypes_$(1),$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
|
||||||
>> $(dot-target).cmd; \
|
>> $(dot-target).cmd; \
|
||||||
fi
|
fi
|
||||||
@ -342,9 +342,7 @@ $(obj)/%.ll: $(src)/%.rs FORCE
|
|||||||
cmd_gensymtypes_S = \
|
cmd_gensymtypes_S = \
|
||||||
{ echo "\#include <linux/kernel.h>" ; \
|
{ echo "\#include <linux/kernel.h>" ; \
|
||||||
echo "\#include <asm/asm-prototypes.h>" ; \
|
echo "\#include <asm/asm-prototypes.h>" ; \
|
||||||
$(CPP) $(a_flags) $< | \
|
$(NM) $@ | sed -n 's/.* __export_symbol_\(.*\)/EXPORT_SYMBOL(\1);/p' ; } | \
|
||||||
grep "\<___EXPORT_SYMBOL\>" | \
|
|
||||||
sed 's/.*___EXPORT_SYMBOL[[:space:]]*\([a-zA-Z0-9_]*\)[[:space:]]*,.*/EXPORT_SYMBOL(\1);/' ; } | \
|
|
||||||
$(CPP) -D__GENKSYMS__ $(c_flags) -xc - | $(genksyms)
|
$(CPP) -D__GENKSYMS__ $(c_flags) -xc - | $(genksyms)
|
||||||
|
|
||||||
quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@
|
quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@
|
||||||
|
@ -46,9 +46,9 @@ BEGIN {
|
|||||||
{ symbol_types[$3]=$2 }
|
{ symbol_types[$3]=$2 }
|
||||||
|
|
||||||
# append the exported symbol to the array
|
# append the exported symbol to the array
|
||||||
($3 ~ /^__ksymtab_/) {
|
($3 ~ /^__export_symbol_.*/) {
|
||||||
export_symbols[i] = $3
|
export_symbols[i] = $3
|
||||||
sub(/^__ksymtab_/, "", export_symbols[i])
|
sub(/^__export_symbol_/, "", export_symbols[i])
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,6 +217,7 @@ struct symbol {
|
|||||||
unsigned int crc;
|
unsigned int crc;
|
||||||
bool crc_valid;
|
bool crc_valid;
|
||||||
bool weak;
|
bool weak;
|
||||||
|
bool is_func;
|
||||||
bool is_gpl_only; /* exported by EXPORT_SYMBOL_GPL */
|
bool is_gpl_only; /* exported by EXPORT_SYMBOL_GPL */
|
||||||
char name[];
|
char name[];
|
||||||
};
|
};
|
||||||
@ -533,6 +534,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
|
|||||||
fatal("%s has NOBITS .modinfo\n", filename);
|
fatal("%s has NOBITS .modinfo\n", filename);
|
||||||
info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
|
info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
|
||||||
info->modinfo_len = sechdrs[i].sh_size;
|
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) {
|
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);
|
ELF_ST_BIND(sym->st_info) == STB_WEAK);
|
||||||
break;
|
break;
|
||||||
default:
|
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)
|
if (strcmp(symname, "init_module") == 0)
|
||||||
mod->has_init = true;
|
mod->has_init = true;
|
||||||
if (strcmp(symname, "cleanup_module") == 0)
|
if (strcmp(symname, "cleanup_module") == 0)
|
||||||
@ -848,7 +839,6 @@ enum mismatch {
|
|||||||
XXXEXIT_TO_SOME_EXIT,
|
XXXEXIT_TO_SOME_EXIT,
|
||||||
ANY_INIT_TO_ANY_EXIT,
|
ANY_INIT_TO_ANY_EXIT,
|
||||||
ANY_EXIT_TO_ANY_INIT,
|
ANY_EXIT_TO_ANY_INIT,
|
||||||
EXPORT_TO_INIT_EXIT,
|
|
||||||
EXTABLE_TO_NON_TEXT,
|
EXTABLE_TO_NON_TEXT,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -920,12 +910,6 @@ static const struct sectioncheck sectioncheck[] = {
|
|||||||
.bad_tosec = { INIT_SECTIONS, NULL },
|
.bad_tosec = { INIT_SECTIONS, NULL },
|
||||||
.mismatch = ANY_INIT_TO_ANY_EXIT,
|
.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 },
|
.fromsec = { "__ex_table", NULL },
|
||||||
/* If you're adding any new black-listed sections in here, consider
|
/* 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",
|
warn("%s: section mismatch in reference: %s (section: %s) -> %s (section: %s)\n",
|
||||||
modname, fromsym, fromsec, tosym, tosec);
|
modname, fromsym, fromsec, tosym, tosec);
|
||||||
break;
|
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:
|
case EXTABLE_TO_NON_TEXT:
|
||||||
warn("%s(%s+0x%lx): Section mismatch in reference to the %s:%s\n",
|
warn("%s(%s+0x%lx): Section mismatch in reference to the %s:%s\n",
|
||||||
modname, fromsec, (long)faddr, tosec, tosym);
|
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,
|
static void check_section_mismatch(struct module *mod, struct elf_info *elf,
|
||||||
Elf_Sym *sym,
|
Elf_Sym *sym,
|
||||||
unsigned int fsecndx, const char *fromsec,
|
unsigned int fsecndx, const char *fromsec,
|
||||||
Elf_Addr faddr, Elf_Addr taddr)
|
Elf_Addr faddr, Elf_Addr taddr)
|
||||||
{
|
{
|
||||||
const char *tosec = sec_name(elf, get_secindex(elf, sym));
|
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)
|
if (!mismatch)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1698,15 +1739,6 @@ static void read_symbols(const char *modname)
|
|||||||
handle_moddevtable(mod, &info, sym, symname);
|
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);
|
check_sec_ref(mod, &info);
|
||||||
|
|
||||||
if (!mod->is_vmlinux) {
|
if (!mod->is_vmlinux) {
|
||||||
@ -1890,6 +1922,14 @@ static void add_exported_symbols(struct buffer *buf, struct module *mod)
|
|||||||
{
|
{
|
||||||
struct symbol *sym;
|
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)
|
if (!modversions)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -137,6 +137,7 @@ struct elf_info {
|
|||||||
Elf_Shdr *sechdrs;
|
Elf_Shdr *sechdrs;
|
||||||
Elf_Sym *symtab_start;
|
Elf_Sym *symtab_start;
|
||||||
Elf_Sym *symtab_stop;
|
Elf_Sym *symtab_stop;
|
||||||
|
unsigned int export_symbol_secndx; /* .export_symbol section */
|
||||||
char *strtab;
|
char *strtab;
|
||||||
char *modinfo;
|
char *modinfo;
|
||||||
unsigned int modinfo_len;
|
unsigned int modinfo_len;
|
||||||
|
Loading…
Reference in New Issue
Block a user