Commit a6b99776 authored by Kai Germaschewski's avatar Kai Germaschewski

kbuild: Add CONFIG_MODVERSIONING and __kcrctab

This patch adds the new config option CONFIG_MODVERSIONING which will
be the new way of checking for ABI changes between kernel and module
code.

This and the following patches are in part based on an initial
implementation by Rusty Russell and I believe some of the ideas go back
to discussions on linux-kbuild, Keith Owens and Rusty.

though I'm not sure I think credit for the basic idea of
storing version info in sections goes to Keith Owens and Rusty.

o Rename __gpl_ksymtab to __ksymtab_gpl since that looks more consistent
  and appending _gpl instead of putting it into the middle simplifies
  sharing code for EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL()
o Add CONFIG_MODVERSIONING
o If CONFIG_MODVERSIONING is set, add a section __kcrctab{,_gpl}, which
  contains the ABI checksums for the exported symbols listed in 
  __ksymtab{,_crc} Since we don't know the checksums yet at compilation
  time, just make them an unresolved symbol which gets filled in by the
  linker later.
parent 81106eac
...@@ -20,10 +20,24 @@ ...@@ -20,10 +20,24 @@
} \ } \
\ \
/* Kernel symbol table: GPL-only symbols */ \ /* Kernel symbol table: GPL-only symbols */ \
__gpl_ksymtab : AT(ADDR(__gpl_ksymtab) - LOAD_OFFSET) { \ __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
__start___gpl_ksymtab = .; \ __start___ksymtab_gpl = .; \
*(__gpl_ksymtab) \ *(__ksymtab_gpl) \
__stop___gpl_ksymtab = .; \ __stop___ksymtab_gpl = .; \
} \
\
/* Kernel symbol table: Normal symbols */ \
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
__start___kcrctab = .; \
*(__kcrctab) \
__stop___kcrctab = .; \
} \
\
/* Kernel symbol table: GPL-only symbols */ \
__kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \
__start___kcrctab_gpl = .; \
*(__kcrctab_gpl) \
__stop___kcrctab_gpl = .; \
} \ } \
\ \
/* Kernel symbol table: strings */ \ /* Kernel symbol table: strings */ \
......
...@@ -134,29 +134,40 @@ struct exception_table ...@@ -134,29 +134,40 @@ struct exception_table
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
/* Get/put a kernel symbol (calls must be symmetric) */ /* Get/put a kernel symbol (calls must be symmetric) */
void *__symbol_get(const char *symbol); void *__symbol_get(const char *symbol);
void *__symbol_get_gpl(const char *symbol); void *__symbol_get_gpl(const char *symbol);
#define symbol_get(x) ((typeof(&x))(__symbol_get(MODULE_SYMBOL_PREFIX #x))) #define symbol_get(x) ((typeof(&x))(__symbol_get(MODULE_SYMBOL_PREFIX #x)))
#ifdef CONFIG_MODVERSIONING
/* Mark the CRC weak since genksyms apparently decides not to
* generate a checksums for some symbols */
#define __CRC_SYMBOL(sym, sec) \
extern void *__crc_##sym __attribute__((weak)); \
static const unsigned long __kcrctab_##sym \
__attribute__((section("__kcrctab" sec))) \
= (unsigned long) &__crc_##sym;
#else
#define __CRC_SYMBOL(sym, sec)
#endif
/* For every exported symbol, place a struct in the __ksymtab section */ /* For every exported symbol, place a struct in the __ksymtab section */
#define EXPORT_SYMBOL(sym) \ #define __EXPORT_SYMBOL(sym, sec) \
__CRC_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] \ static const char __kstrtab_##sym[] \
__attribute__((section("__ksymtab_strings"))) \ __attribute__((section("__ksymtab_strings"))) \
= MODULE_SYMBOL_PREFIX #sym; \ = MODULE_SYMBOL_PREFIX #sym; \
static const struct kernel_symbol __ksymtab_##sym \ static const struct kernel_symbol __ksymtab_##sym \
__attribute__((section("__ksymtab"))) \ __attribute__((section("__ksymtab" sec))) \
= { (unsigned long)&sym, __kstrtab_##sym } = { (unsigned long)&sym, __kstrtab_##sym }
#define EXPORT_SYMBOL_NOVERS(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) \ /* We don't mangle the actual symbol anymore, so no need for
static const char __kstrtab_##sym[] \ * special casing EXPORT_SYMBOL_NOVERS */
__attribute__((section("__ksymtab_strings"))) \ #define EXPORT_SYMBOL_NOVERS(sym) EXPORT_SYMBOL(sym)
= MODULE_SYMBOL_PREFIX #sym; \
static const struct kernel_symbol __ksymtab_##sym \
__attribute__((section("__gpl_ksymtab"))) \
= { (unsigned long)&sym, __kstrtab_##sym }
struct module_ref struct module_ref
{ {
......
...@@ -144,6 +144,19 @@ config OBSOLETE_MODPARM ...@@ -144,6 +144,19 @@ config OBSOLETE_MODPARM
have not been converted to the new module parameter system yet. have not been converted to the new module parameter system yet.
If unsure, say Y. If unsure, say Y.
config MODVERSIONING
bool "Module versioning support (EXPERIMENTAL)"
depends on MODULES && EXPERIMENTAL
help
---help---
Usually, you have to use modules compiled with your kernel.
Saying Y here makes it sometimes possible to use modules
compiled for different kernels, by adding enough information
to the modules to (hopefully) spot any changes which would
make them incompatible with the kernel you are running. If
you say Y here, you will need a copy of genksyms. If
unsure, say N.
config KMOD config KMOD
bool "Kernel module loader" bool "Kernel module loader"
depends on MODULES depends on MODULES
......
...@@ -1040,6 +1040,11 @@ static struct module *load_module(void *umod, ...@@ -1040,6 +1040,11 @@ static struct module *load_module(void *umod,
/* Exported symbols. */ /* Exported symbols. */
DEBUGP("EXPORT table in section %u\n", i); DEBUGP("EXPORT table in section %u\n", i);
exportindex = i; exportindex = i;
} else if (strcmp(secstrings+sechdrs[i].sh_name,
"__ksymtab_gpl") == 0) {
/* Exported symbols. (GPL) */
DEBUGP("GPL symbols found in section %u\n", i);
gplindex = i;
} else if (strcmp(secstrings+sechdrs[i].sh_name, "__param") } else if (strcmp(secstrings+sechdrs[i].sh_name, "__param")
== 0) { == 0) {
/* Setup parameter info */ /* Setup parameter info */
...@@ -1060,11 +1065,6 @@ static struct module *load_module(void *umod, ...@@ -1060,11 +1065,6 @@ static struct module *load_module(void *umod,
/* MODULE_LICENSE() */ /* MODULE_LICENSE() */
DEBUGP("Licence found in section %u\n", i); DEBUGP("Licence found in section %u\n", i);
licenseindex = i; licenseindex = i;
} else if (strcmp(secstrings+sechdrs[i].sh_name,
"__gpl_ksymtab") == 0) {
/* EXPORT_SYMBOL_GPL() */
DEBUGP("GPL symbols found in section %u\n", i);
gplindex = i;
} else if (strcmp(secstrings+sechdrs[i].sh_name, } else if (strcmp(secstrings+sechdrs[i].sh_name,
"__vermagic") == 0) { "__vermagic") == 0) {
/* Version magic. */ /* Version magic. */
...@@ -1492,8 +1492,8 @@ int module_text_address(unsigned long addr) ...@@ -1492,8 +1492,8 @@ int module_text_address(unsigned long addr)
/* Provided by the linker */ /* Provided by the linker */
extern const struct kernel_symbol __start___ksymtab[]; extern const struct kernel_symbol __start___ksymtab[];
extern const struct kernel_symbol __stop___ksymtab[]; extern const struct kernel_symbol __stop___ksymtab[];
extern const struct kernel_symbol __start___gpl_ksymtab[]; extern const struct kernel_symbol __start___ksymtab_gpl[];
extern const struct kernel_symbol __stop___gpl_ksymtab[]; extern const struct kernel_symbol __stop___ksymtab_gpl[];
static struct kernel_symbol_group kernel_symbols, kernel_gpl_symbols; static struct kernel_symbol_group kernel_symbols, kernel_gpl_symbols;
...@@ -1504,9 +1504,10 @@ static int __init symbols_init(void) ...@@ -1504,9 +1504,10 @@ static int __init symbols_init(void)
kernel_symbols.syms = __start___ksymtab; kernel_symbols.syms = __start___ksymtab;
kernel_symbols.gplonly = 0; kernel_symbols.gplonly = 0;
list_add(&kernel_symbols.list, &symbols); list_add(&kernel_symbols.list, &symbols);
kernel_gpl_symbols.num_syms = (__stop___gpl_ksymtab
- __start___gpl_ksymtab); kernel_gpl_symbols.num_syms = (__stop___ksymtab_gpl
kernel_gpl_symbols.syms = __start___gpl_ksymtab; - __start___ksymtab_gpl);
kernel_gpl_symbols.syms = __start___ksymtab_gpl;
kernel_gpl_symbols.gplonly = 1; kernel_gpl_symbols.gplonly = 1;
list_add(&kernel_gpl_symbols.list, &symbols); list_add(&kernel_gpl_symbols.list, &symbols);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
IN_PER_CPU=0 IN_PER_CPU=0
} }
/__per_cpu$$/ && ! ( / __ksymtab_/ || / __kstrtab_/ ) { /__per_cpu$$/ && ! ( / __ksymtab_/ || / __kstrtab_/ || / __kcrctab_/ ) {
if (!IN_PER_CPU) { if (!IN_PER_CPU) {
print $$3 " not in per-cpu section" > "/dev/stderr"; print $$3 " not in per-cpu section" > "/dev/stderr";
FOUND=1; FOUND=1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment