Skip to content

Commit

Permalink
[PATCH] Add EXPORT_UNUSED_SYMBOL and EXPORT_UNUSED_SYMBOL_GPL
Browse files Browse the repository at this point in the history
Temporarily add EXPORT_UNUSED_SYMBOL and EXPORT_UNUSED_SYMBOL_GPL.  These
will be used as a transition measure for symbols that aren't used in the
kernel and are on the way out.  When a module uses such a symbol, a warning
is printk'd at modprobe time.

The main reason for removing unused exports is size: eacho export takes
roughly between 100 and 150 bytes of kernel space in the binary.  This
patch gives users the option to immediately get this size gain via a config
option.

Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Arjan van de Ven authored and Linus Torvalds committed Jun 28, 2006
1 parent f5e54d6 commit f71d20e
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 2 deletions.
10 changes: 10 additions & 0 deletions Documentation/feature-removal-schedule.txt
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,16 @@ Who: Jean Delvare <khali@linux-fr.org>

---------------------------

What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
(temporary transition config option provided until then)
The transition config option will also be removed at the same time.
When: before 2.6.19
Why: Unused symbols are both increasing the size of the kernel binary
and are often a sign of "wrong API"
Who: Arjan van de Ven <arjan@linux.intel.com>

---------------------------

What: remove EXPORT_SYMBOL(tasklist_lock)
When: August 2006
Files: kernel/fork.c
Expand Down
28 changes: 28 additions & 0 deletions include/asm-generic/vmlinux.lds.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@
VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \
} \
\
/* Kernel symbol table: Normal unused symbols */ \
__ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \
*(__ksymtab_unused) \
VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \
} \
\
/* Kernel symbol table: GPL-only unused symbols */ \
__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \
*(__ksymtab_unused_gpl) \
VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \
} \
\
/* Kernel symbol table: GPL-future-only symbols */ \
__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \
Expand All @@ -79,6 +93,20 @@
VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \
} \
\
/* Kernel symbol table: Normal unused symbols */ \
__kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_unused) = .; \
*(__kcrctab_unused) \
VMLINUX_SYMBOL(__stop___kcrctab_unused) = .; \
} \
\
/* Kernel symbol table: GPL-only unused symbols */ \
__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \
*(__kcrctab_unused_gpl) \
VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \
} \
\
/* Kernel symbol table: GPL-future-only symbols */ \
__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \
Expand Down
20 changes: 20 additions & 0 deletions include/linux/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,15 @@ void *__symbol_get_gpl(const char *symbol);
#define EXPORT_SYMBOL_GPL_FUTURE(sym) \
__EXPORT_SYMBOL(sym, "_gpl_future")


#ifdef CONFIG_UNUSED_SYMBOLS
#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl")
#else
#define EXPORT_UNUSED_SYMBOL(sym)
#define EXPORT_UNUSED_SYMBOL_GPL(sym)
#endif

#endif

struct module_ref
Expand Down Expand Up @@ -261,6 +270,15 @@ struct module
unsigned int num_gpl_syms;
const unsigned long *gpl_crcs;

/* unused exported symbols. */
const struct kernel_symbol *unused_syms;
unsigned int num_unused_syms;
const unsigned long *unused_crcs;
/* GPL-only, unused exported symbols. */
const struct kernel_symbol *unused_gpl_syms;
unsigned int num_unused_gpl_syms;
const unsigned long *unused_gpl_crcs;

/* symbols that will be GPL-only in the near future. */
const struct kernel_symbol *gpl_future_syms;
unsigned int num_gpl_future_syms;
Expand Down Expand Up @@ -456,6 +474,8 @@ void module_remove_driver(struct device_driver *);
#define EXPORT_SYMBOL(sym)
#define EXPORT_SYMBOL_GPL(sym)
#define EXPORT_SYMBOL_GPL_FUTURE(sym)
#define EXPORT_UNUSED_SYMBOL(sym)
#define EXPORT_UNUSED_SYMBOL_GPL(sym)

/* Given an address, look for it in the exception tables. */
static inline const struct exception_table_entry *
Expand Down
78 changes: 76 additions & 2 deletions kernel/module.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Rewritten by Rusty Russell, on the backs of many others...
/*
Copyright (C) 2002 Richard Henderson
Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
Expand Down Expand Up @@ -122,9 +122,17 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
extern const struct kernel_symbol __stop___ksymtab_gpl[];
extern const struct kernel_symbol __start___ksymtab_gpl_future[];
extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
extern const struct kernel_symbol __start___ksymtab_unused[];
extern const struct kernel_symbol __stop___ksymtab_unused[];
extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
extern const struct kernel_symbol __start___ksymtab_gpl_future[];
extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
extern const unsigned long __start___kcrctab[];
extern const unsigned long __start___kcrctab_gpl[];
extern const unsigned long __start___kcrctab_gpl_future[];
extern const unsigned long __start___kcrctab_unused[];
extern const unsigned long __start___kcrctab_unused_gpl[];

#ifndef CONFIG_MODVERSIONS
#define symversion(base, idx) NULL
Expand All @@ -144,6 +152,17 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
return NULL;
}

static void printk_unused_warning(const char *name)
{
printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
"however this module is using it.\n", name);
printk(KERN_WARNING "This symbol will go away in the future.\n");
printk(KERN_WARNING "Please evalute if this is the right api to use, "
"and if it really is, submit a report the linux kernel "
"mailinglist together with submitting your code for "
"inclusion.\n");
}

/* Find a symbol, return value, crc and module which owns it */
static unsigned long __find_symbol(const char *name,
struct module **owner,
Expand Down Expand Up @@ -186,6 +205,25 @@ static unsigned long __find_symbol(const char *name,
return ks->value;
}

ks = lookup_symbol(name, __start___ksymtab_unused,
__stop___ksymtab_unused);
if (ks) {
printk_unused_warning(name);
*crc = symversion(__start___kcrctab_unused,
(ks - __start___ksymtab_unused));
return ks->value;
}

if (gplok)
ks = lookup_symbol(name, __start___ksymtab_unused_gpl,
__stop___ksymtab_unused_gpl);
if (ks) {
printk_unused_warning(name);
*crc = symversion(__start___kcrctab_unused_gpl,
(ks - __start___ksymtab_unused_gpl));
return ks->value;
}

/* Now try modules. */
list_for_each_entry(mod, &modules, list) {
*owner = mod;
Expand All @@ -204,6 +242,23 @@ static unsigned long __find_symbol(const char *name,
return ks->value;
}
}
ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms);
if (ks) {
printk_unused_warning(name);
*crc = symversion(mod->unused_crcs, (ks - mod->unused_syms));
return ks->value;
}

if (gplok) {
ks = lookup_symbol(name, mod->unused_gpl_syms,
mod->unused_gpl_syms + mod->num_unused_gpl_syms);
if (ks) {
printk_unused_warning(name);
*crc = symversion(mod->unused_gpl_crcs,
(ks - mod->unused_gpl_syms));
return ks->value;
}
}
ks = lookup_symbol(name, mod->gpl_future_syms,
(mod->gpl_future_syms +
mod->num_gpl_future_syms));
Expand Down Expand Up @@ -1407,6 +1462,8 @@ static struct module *load_module(void __user *umod,
exportindex, modindex, obsparmindex, infoindex, gplindex,
crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
gplfuturecrcindex, unwindex = 0;
unsigned int unusedindex, unusedcrcindex, unusedgplindex,
unusedgplcrcindex;
struct module *mod;
long err = 0;
void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
Expand Down Expand Up @@ -1487,9 +1544,13 @@ static struct module *load_module(void __user *umod,
exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused");
unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl");
crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused");
unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl");
setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
Expand Down Expand Up @@ -1638,14 +1699,27 @@ static struct module *load_module(void __user *umod,
mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
sizeof(*mod->gpl_future_syms);
mod->num_unused_syms = sechdrs[unusedindex].sh_size /
sizeof(*mod->unused_syms);
mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size /
sizeof(*mod->unused_gpl_syms);
mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
if (gplfuturecrcindex)
mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;

mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
if (unusedcrcindex)
mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr;
mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr;
if (unusedgplcrcindex)
mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr;

#ifdef CONFIG_MODVERSIONS
if ((mod->num_syms && !crcindex) ||
(mod->num_gpl_syms && !gplcrcindex) ||
(mod->num_gpl_future_syms && !gplfuturecrcindex)) {
(mod->num_gpl_future_syms && !gplfuturecrcindex) ||
(mod->num_unused_syms && !unusedcrcindex) ||
(mod->num_unused_gpl_syms && !unusedgplcrcindex)) {
printk(KERN_WARNING "%s: No versions for exported symbols."
" Tainting kernel.\n", mod->name);
add_taint(TAINT_FORCED_MODULE);
Expand Down
16 changes: 16 additions & 0 deletions lib/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ config MAGIC_SYSRQ
keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
unless you really know what this hack does.

config UNUSED_SYMBOLS
bool "Enable unused/obsolete exported symbols"
default y if X86
help
Unused but exported symbols make the kernel needlessly bigger. For
that reason most of these unused exports will soon be removed. This
option is provided temporarily to provide a transition period in case
some external kernel module needs one of these symbols anyway. If you
encounter such a case in your module, consider if you are actually
using the right API. (rationale: since nobody in the kernel is using
this in a module, there is a pretty good chance it's actually the
wrong interface to use). If you really need the symbol, please send a
mail to the linux kernel mailing list mentioning the symbol and why
you really need it, and what the merge plan to the mainline kernel for
your module is.

config DEBUG_KERNEL
bool "Kernel debugging"
help
Expand Down

0 comments on commit f71d20e

Please sign in to comment.