summaryrefslogtreecommitdiff
path: root/kernel/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/module.c')
-rw-r--r--kernel/module.c171
1 files changed, 52 insertions, 119 deletions
diff --git a/kernel/module.c b/kernel/module.c
index 00d8b07c4fd1..bf6859b3cd73 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -76,6 +76,22 @@ int init_module(void)
}
EXPORT_SYMBOL(init_module);
+/* Find a module section: 0 means not found. */
+static unsigned int find_sec(Elf_Ehdr *hdr,
+ Elf_Shdr *sechdrs,
+ const char *secstrings,
+ const char *name)
+{
+ unsigned int i;
+
+ for (i = 1; i < hdr->e_shnum; i++)
+ /* Alloc bit cleared means "ignore it." */
+ if ((sechdrs[i].sh_flags & SHF_ALLOC)
+ && strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
+ return i;
+ return 0;
+}
+
/* Find a symbol, return value and the symbol group */
static unsigned long __find_symbol(const char *name,
struct kernel_symbol_group **group,
@@ -173,16 +189,19 @@ static int use_module(struct module *a, struct module *b)
struct module_use *use;
if (b == NULL || already_uses(a, b)) return 1;
+ if (!strong_try_module_get(b))
+ return 0;
+
DEBUGP("Allocating new usage for %s.\n", a->name);
use = kmalloc(sizeof(*use), GFP_ATOMIC);
if (!use) {
printk("%s: out of memory loading\n", a->name);
+ module_put(b);
return 0;
}
use->module_which_uses = a;
list_add(&use->list, &b->modules_which_use_me);
- try_module_get(b); /* Can't fail */
return 1;
}
@@ -875,45 +894,6 @@ void *__symbol_get(const char *symbol)
}
EXPORT_SYMBOL_GPL(__symbol_get);
-/* Deal with the given section */
-static int handle_section(const char *name,
- Elf_Shdr *sechdrs,
- unsigned int strindex,
- unsigned int symindex,
- unsigned int i,
- struct module *mod)
-{
- int ret;
- const char *strtab = (char *)sechdrs[strindex].sh_addr;
-
- switch (sechdrs[i].sh_type) {
- case SHT_REL:
- ret = apply_relocate(sechdrs, strtab, symindex, i, mod);
- break;
- case SHT_RELA:
- ret = apply_relocate_add(sechdrs, strtab, symindex, i, mod);
- break;
- default:
- DEBUGP("Ignoring section %u: %s\n", i,
- sechdrs[i].sh_type==SHT_NULL ? "NULL":
- sechdrs[i].sh_type==SHT_PROGBITS ? "PROGBITS":
- sechdrs[i].sh_type==SHT_SYMTAB ? "SYMTAB":
- sechdrs[i].sh_type==SHT_STRTAB ? "STRTAB":
- sechdrs[i].sh_type==SHT_RELA ? "RELA":
- sechdrs[i].sh_type==SHT_HASH ? "HASH":
- sechdrs[i].sh_type==SHT_DYNAMIC ? "DYNAMIC":
- sechdrs[i].sh_type==SHT_NOTE ? "NOTE":
- sechdrs[i].sh_type==SHT_NOBITS ? "NOBITS":
- sechdrs[i].sh_type==SHT_REL ? "REL":
- sechdrs[i].sh_type==SHT_SHLIB ? "SHLIB":
- sechdrs[i].sh_type==SHT_DYNSYM ? "DYNSYM":
- sechdrs[i].sh_type==SHT_NUM ? "NUM":
- "UNKNOWN");
- ret = 0;
- }
- return ret;
-}
-
/* Change all symbols so that sh_value encodes the pointer directly. */
static int simplify_symbols(Elf_Shdr *sechdrs,
unsigned int symindex,
@@ -1103,93 +1083,19 @@ static struct module *load_module(void *umod,
sechdrs = (void *)hdr + hdr->e_shoff;
secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
- /* May not export symbols, or have setup params, so these may
- not exist */
- exportindex = setupindex = obsparmindex = gplindex = licenseindex
- = crcindex = gplcrcindex = versindex = 0;
-
/* And these should exist, but gcc whinges if we don't init them */
- symindex = strindex = exindex = modindex = vmagindex = 0;
+ symindex = strindex = 0;
- /* Find where important sections are */
for (i = 1; i < hdr->e_shnum; i++) {
/* Mark all sections sh_addr with their address in the
temporary image. */
sechdrs[i].sh_addr = (size_t)hdr + sechdrs[i].sh_offset;
+ /* Internal symbols and strings. */
if (sechdrs[i].sh_type == SHT_SYMTAB) {
- /* Internal symbols */
- DEBUGP("Symbol table in section %u\n", i);
symindex = i;
- /* Strings */
strindex = sechdrs[i].sh_link;
- DEBUGP("String table found in section %u\n", strindex);
- } else if (strcmp(secstrings+sechdrs[i].sh_name,
- ".gnu.linkonce.this_module") == 0) {
- /* The module struct */
- DEBUGP("Module in section %u\n", i);
- modindex = i;
- } else if (strcmp(secstrings+sechdrs[i].sh_name, "__ksymtab")
- == 0) {
- /* 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, "__kcrctab")
- == 0) {
- /* Exported symbols CRCs. */
- DEBUGP("CRC table in section %u\n", i);
- crcindex = i;
- } else if (strcmp(secstrings+sechdrs[i].sh_name, "__kcrctab_gpl")
- == 0) {
- /* Exported symbols CRCs. (GPL)*/
- DEBUGP("CRC table in section %u\n", i);
- gplcrcindex = i;
- } else if (strcmp(secstrings+sechdrs[i].sh_name, "__param")
- == 0) {
- /* Setup parameter info */
- DEBUGP("Setup table found in section %u\n", i);
- setupindex = i;
- } else if (strcmp(secstrings+sechdrs[i].sh_name, "__ex_table")
- == 0) {
- /* Exception table */
- DEBUGP("Exception table found in section %u\n", i);
- exindex = i;
- } else if (strcmp(secstrings+sechdrs[i].sh_name, "__obsparm")
- == 0) {
- /* Obsolete MODULE_PARM() table */
- DEBUGP("Obsolete param found in section %u\n", i);
- obsparmindex = i;
- } else if (strcmp(secstrings+sechdrs[i].sh_name,".init.license")
- == 0) {
- /* MODULE_LICENSE() */
- DEBUGP("Licence found in section %u\n", i);
- licenseindex = i;
- sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
- } else if (strcmp(secstrings+sechdrs[i].sh_name,
- "__vermagic") == 0 &&
- (sechdrs[i].sh_flags & SHF_ALLOC)) {
- /* Version magic. */
- DEBUGP("Version magic found in section %u\n", i);
- vmagindex = i;
- sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
- } else if (strcmp(secstrings+sechdrs[i].sh_name,
- "__versions") == 0 &&
- (sechdrs[i].sh_flags & SHF_ALLOC)) {
- /* Module version info (both exported and needed) */
- DEBUGP("Versions found in section %u\n", i);
- versindex = i;
- sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
}
-#ifdef CONFIG_KALLSYMS
- /* symbol and string tables for decoding later. */
- if (sechdrs[i].sh_type == SHT_SYMTAB || i == strindex)
- sechdrs[i].sh_flags |= SHF_ALLOC;
-#endif
#ifndef CONFIG_MODULE_UNLOAD
/* Don't load .exit sections */
if (strstr(secstrings+sechdrs[i].sh_name, ".exit"))
@@ -1197,6 +1103,14 @@ static struct module *load_module(void *umod,
#endif
}
+#ifdef CONFIG_KALLSYMS
+ /* Keep symbol and string tables for decoding later. */
+ sechdrs[symindex].sh_flags |= SHF_ALLOC;
+ sechdrs[strindex].sh_flags |= SHF_ALLOC;
+#endif
+
+ modindex = find_sec(hdr, sechdrs, secstrings,
+ ".gnu.linkonce.this_module");
if (!modindex) {
printk(KERN_WARNING "No module found in object\n");
err = -ENOEXEC;
@@ -1204,6 +1118,18 @@ static struct module *load_module(void *umod,
}
mod = (void *)sechdrs[modindex].sh_addr;
+ /* Optional sections */
+ exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
+ gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
+ crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
+ gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
+ setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
+ exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
+ obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
+ licenseindex = find_sec(hdr, sechdrs, secstrings, ".init.license");
+ vmagindex = find_sec(hdr, sechdrs, secstrings, "__vermagic");
+ versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
+
/* Check module struct version now, before we try to use module. */
if (!check_modstruct_version(sechdrs, versindex, mod)) {
err = -ENOEXEC;
@@ -1336,10 +1262,15 @@ static struct module *load_module(void *umod,
mod->extable.entry = (void *)sechdrs[exindex].sh_addr;
}
- /* Now handle each section. */
+ /* Now do relocations. */
for (i = 1; i < hdr->e_shnum; i++) {
- err = handle_section(secstrings + sechdrs[i].sh_name,
- sechdrs, strindex, symindex, i, mod);
+ const char *strtab = (char *)sechdrs[strindex].sh_addr;
+ if (sechdrs[i].sh_type == SHT_REL)
+ err = apply_relocate(sechdrs, strtab, symindex, i,
+ mod);
+ else if (sechdrs[i].sh_type == SHT_RELA)
+ err = apply_relocate_add(sechdrs, strtab, symindex, i,
+ mod);
if (err < 0)
goto cleanup;
}
@@ -1456,10 +1387,12 @@ sys_init_module(void *umod,
}
/* Now it's a first class citizen! */
+ down(&module_mutex);
mod->state = MODULE_STATE_LIVE;
module_free(mod, mod->module_init);
mod->module_init = NULL;
mod->init_size = 0;
+ up(&module_mutex);
return 0;
}