summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>2003-01-24 02:27:06 -0600
committerKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>2003-01-24 02:27:06 -0600
commita6b9977667ca069f18ad85fab1c2445a0f2f4e78 (patch)
tree63a252e93b7fb00cda1b30dd0ae616c322b05940
parent81106eaca86e21dfaa3b3c5f0432bd92f9a15661 (diff)
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.
-rw-r--r--include/asm-generic/vmlinux.lds.h22
-rw-r--r--include/linux/module.h31
-rw-r--r--init/Kconfig13
-rw-r--r--kernel/module.c21
-rw-r--r--scripts/per-cpu-check.awk2
5 files changed, 64 insertions, 25 deletions
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 7563b5730aaa..0f09f5b73a69 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -20,10 +20,24 @@
} \
\
/* Kernel symbol table: GPL-only symbols */ \
- __gpl_ksymtab : AT(ADDR(__gpl_ksymtab) - LOAD_OFFSET) { \
- __start___gpl_ksymtab = .; \
- *(__gpl_ksymtab) \
- __stop___gpl_ksymtab = .; \
+ __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
+ __start___ksymtab_gpl = .; \
+ *(__ksymtab_gpl) \
+ __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 */ \
diff --git a/include/linux/module.h b/include/linux/module.h
index 6dad1479105f..d017a67210c6 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -134,29 +134,40 @@ struct exception_table
#ifdef CONFIG_MODULES
+
/* Get/put a kernel symbol (calls must be symmetric) */
void *__symbol_get(const char *symbol);
void *__symbol_get_gpl(const char *symbol);
#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 */
-#define EXPORT_SYMBOL(sym) \
+#define __EXPORT_SYMBOL(sym, sec) \
+ __CRC_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] \
__attribute__((section("__ksymtab_strings"))) \
= MODULE_SYMBOL_PREFIX #sym; \
static const struct kernel_symbol __ksymtab_##sym \
- __attribute__((section("__ksymtab"))) \
+ __attribute__((section("__ksymtab" sec))) \
= { (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) \
- static const char __kstrtab_##sym[] \
- __attribute__((section("__ksymtab_strings"))) \
- = MODULE_SYMBOL_PREFIX #sym; \
- static const struct kernel_symbol __ksymtab_##sym \
- __attribute__((section("__gpl_ksymtab"))) \
- = { (unsigned long)&sym, __kstrtab_##sym }
+/* We don't mangle the actual symbol anymore, so no need for
+ * special casing EXPORT_SYMBOL_NOVERS */
+#define EXPORT_SYMBOL_NOVERS(sym) EXPORT_SYMBOL(sym)
struct module_ref
{
diff --git a/init/Kconfig b/init/Kconfig
index fcdd9fdb7896..5541908be8c0 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -144,6 +144,19 @@ config OBSOLETE_MODPARM
have not been converted to the new module parameter system yet.
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
bool "Kernel module loader"
depends on MODULES
diff --git a/kernel/module.c b/kernel/module.c
index 864828099b36..b798fd62ad2f 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1040,6 +1040,11 @@ static struct module *load_module(void *umod,
/* Exported symbols. */
DEBUGP("EXPORT table in section %u\n", 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")
== 0) {
/* Setup parameter info */
@@ -1061,11 +1066,6 @@ static struct module *load_module(void *umod,
DEBUGP("Licence found in section %u\n", 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,
"__vermagic") == 0) {
/* Version magic. */
DEBUGP("Version magic found in section %u\n", i);
@@ -1492,8 +1492,8 @@ int module_text_address(unsigned long addr)
/* Provided by the linker */
extern const struct kernel_symbol __start___ksymtab[];
extern const struct kernel_symbol __stop___ksymtab[];
-extern const struct kernel_symbol __start___gpl_ksymtab[];
-extern const struct kernel_symbol __stop___gpl_ksymtab[];
+extern const struct kernel_symbol __start___ksymtab_gpl[];
+extern const struct kernel_symbol __stop___ksymtab_gpl[];
static struct kernel_symbol_group kernel_symbols, kernel_gpl_symbols;
@@ -1504,9 +1504,10 @@ static int __init symbols_init(void)
kernel_symbols.syms = __start___ksymtab;
kernel_symbols.gplonly = 0;
list_add(&kernel_symbols.list, &symbols);
- kernel_gpl_symbols.num_syms = (__stop___gpl_ksymtab
- - __start___gpl_ksymtab);
- kernel_gpl_symbols.syms = __start___gpl_ksymtab;
+
+ kernel_gpl_symbols.num_syms = (__stop___ksymtab_gpl
+ - __start___ksymtab_gpl);
+ kernel_gpl_symbols.syms = __start___ksymtab_gpl;
kernel_gpl_symbols.gplonly = 1;
list_add(&kernel_gpl_symbols.list, &symbols);
diff --git a/scripts/per-cpu-check.awk b/scripts/per-cpu-check.awk
index f1b34c42df4b..3be9f0d25ebd 100644
--- a/scripts/per-cpu-check.awk
+++ b/scripts/per-cpu-check.awk
@@ -6,7 +6,7 @@
IN_PER_CPU=0
}
-/__per_cpu$$/ && ! ( / __ksymtab_/ || / __kstrtab_/ ) {
+/__per_cpu$$/ && ! ( / __ksymtab_/ || / __kstrtab_/ || / __kcrctab_/ ) {
if (!IN_PER_CPU) {
print $$3 " not in per-cpu section" > "/dev/stderr";
FOUND=1;