diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 171 |
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; } |
