X-Git-Url: http://ftp.safe.ca/?p=safe%2Fjmp%2Flinux-2.6;a=blobdiff_plain;f=scripts%2Fmod%2Fmodpost.c;h=801a16a1754532cee8f647ef178772209973120d;hp=695b5d657cf59cc89ba1a4989d7052085e942abf;hb=f653398c86a1c104f0992bd788dd4bb065449be4;hpb=b1d2675a6466090b68d4ef63f9237b4d70a18857 diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 695b5d6..801a16a 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -384,11 +384,19 @@ static int parse_elf(struct elf_info *info, const char *filename) return 0; } /* Fix endianness in ELF header */ - hdr->e_shoff = TO_NATIVE(hdr->e_shoff); - hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); - hdr->e_shnum = TO_NATIVE(hdr->e_shnum); - hdr->e_machine = TO_NATIVE(hdr->e_machine); - hdr->e_type = TO_NATIVE(hdr->e_type); + hdr->e_type = TO_NATIVE(hdr->e_type); + hdr->e_machine = TO_NATIVE(hdr->e_machine); + hdr->e_version = TO_NATIVE(hdr->e_version); + hdr->e_entry = TO_NATIVE(hdr->e_entry); + hdr->e_phoff = TO_NATIVE(hdr->e_phoff); + hdr->e_shoff = TO_NATIVE(hdr->e_shoff); + hdr->e_flags = TO_NATIVE(hdr->e_flags); + hdr->e_ehsize = TO_NATIVE(hdr->e_ehsize); + hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize); + hdr->e_phnum = TO_NATIVE(hdr->e_phnum); + hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize); + hdr->e_shnum = TO_NATIVE(hdr->e_shnum); + hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); sechdrs = (void *)hdr + hdr->e_shoff; info->sechdrs = sechdrs; @@ -402,21 +410,25 @@ static int parse_elf(struct elf_info *info, const char *filename) /* Fix endianness in section headers */ for (i = 0; i < hdr->e_shnum; i++) { - sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type); - sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset); - sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); - sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); - sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); - sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info); - sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr); + sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); + sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type); + sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags); + sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr); + sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset); + sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); + sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); + sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info); + sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign); + sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize); } /* Find symbol table. */ for (i = 1; i < hdr->e_shnum; i++) { const char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; const char *secname; + int nobits = sechdrs[i].sh_type == SHT_NOBITS; - if (sechdrs[i].sh_offset > info->size) { + if (!nobits && sechdrs[i].sh_offset > info->size) { fatal("%s is truncated. sechdrs[i].sh_offset=%lu > " "sizeof(*hrd)=%zu\n", filename, (unsigned long)sechdrs[i].sh_offset, @@ -425,6 +437,8 @@ static int parse_elf(struct elf_info *info, const char *filename) } secname = secstrings + sechdrs[i].sh_name; if (strcmp(secname, ".modinfo") == 0) { + if (nobits) + fatal("%s has NOBITS .modinfo\n", filename); info->modinfo = (void *)hdr + sechdrs[i].sh_offset; info->modinfo_len = sechdrs[i].sh_size; } else if (strcmp(secname, "__ksymtab") == 0) @@ -467,6 +481,25 @@ static void parse_elf_finish(struct elf_info *info) release_file(info->hdr, info->size); } +static int ignore_undef_symbol(struct elf_info *info, const char *symname) +{ + /* ignore __this_module, it will be resolved shortly */ + if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0) + return 1; + /* ignore global offset table */ + if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) + return 1; + if (info->hdr->e_machine == EM_PPC) + /* Special register function linked on all modules during final link of .ko */ + if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 || + strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 || + strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 || + strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0) + return 1; + /* Do not ignore this symbol */ + return 0; +} + #define CRC_PFX MODULE_SYMBOL_PREFIX "__crc_" #define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_" @@ -493,11 +526,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL && ELF_ST_BIND(sym->st_info) != STB_WEAK) break; - /* ignore global offset table */ - if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) - break; - /* ignore __this_module, it will be resolved shortly */ - if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0) + if (ignore_undef_symbol(info, symname)) break; /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */ #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER) @@ -662,7 +691,7 @@ static int number_prefix(const char *sym) * The $ syntax is for sections where ld append a dot number * to make section name unique. */ -int match(const char *sym, const char * const pat[]) +static int match(const char *sym, const char * const pat[]) { const char *p; while (*pat) { @@ -698,46 +727,44 @@ int match(const char *sym, const char * const pat[]) /* sections that we do not want to do full section mismatch check on */ static const char *section_white_list[] = - { ".debug*", ".stab*", ".note*", ".got*", ".toc*", NULL }; +{ + ".comment*", + ".debug*", + ".mdebug*", /* alpha, score, mips etc. */ + ".pdr", /* alpha, score, mips etc. */ + ".stab*", + ".note*", + ".got*", + ".toc*", + NULL +}; /* - * Is this section one we do not want to check? - * This is often debug sections. - * If we are going to check this section then - * test if section name ends with a dot and a number. - * This is used to find sections where the linker have - * appended a dot-number to make the name unique. + * This is used to find sections missing the SHF_ALLOC flag. * The cause of this is often a section specified in assembler - * without "ax" / "aw" and the same section used in .c - * code where gcc add these. + * without "ax" / "aw". */ -static int check_section(const char *modname, const char *sec) -{ - const char *e = sec + strlen(sec) - 1; - if (match(sec, section_white_list)) - return 1; - - if (*e && isdigit(*e)) { - /* consume all digits */ - while (*e && e != sec && isdigit(*e)) - e--; - if (*e == '.') { - warn("%s (%s): unexpected section name.\n" - "The (.[number]+) following section name are " - "ld generated and not expected.\n" - "Did you forget to use \"ax\"/\"aw\" " - "in a .S file?\n" - "Note that for example contains\n" - "section definitions for use in .S files.\n\n", - modname, sec); - } +static void check_section(const char *modname, struct elf_info *elf, + Elf_Shdr *sechdr) +{ + const char *sec = sech_name(elf, sechdr); + + if (sechdr->sh_type == SHT_PROGBITS && + !(sechdr->sh_flags & SHF_ALLOC) && + !match(sec, section_white_list)) { + warn("%s (%s): unexpected non-allocatable section.\n" + "Did you forget to use \"ax\"/\"aw\" in a .S file?\n" + "Note that for example contains\n" + "section definitions for use in .S files.\n\n", + modname, sec); } - return 0; } #define ALL_INIT_DATA_SECTIONS \ + ".init.setup$", ".init.rodata$", \ + ".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$" \ ".init.data$", ".devinit.data$", ".cpuinit.data$", ".meminit.data$" #define ALL_EXIT_DATA_SECTIONS \ ".exit.data$", ".devexit.data$", ".cpuexit.data$", ".memexit.data$" @@ -747,21 +774,23 @@ static int check_section(const char *modname, const char *sec) #define ALL_EXIT_TEXT_SECTIONS \ ".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$" -#define ALL_INIT_SECTIONS ALL_INIT_DATA_SECTIONS, ALL_INIT_TEXT_SECTIONS -#define ALL_EXIT_SECTIONS ALL_EXIT_DATA_SECTIONS, ALL_EXIT_TEXT_SECTIONS +#define ALL_INIT_SECTIONS INIT_SECTIONS, DEV_INIT_SECTIONS, \ + CPU_INIT_SECTIONS, MEM_INIT_SECTIONS +#define ALL_EXIT_SECTIONS EXIT_SECTIONS, DEV_EXIT_SECTIONS, \ + CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS #define DATA_SECTIONS ".data$", ".data.rel$" #define TEXT_SECTIONS ".text$" -#define INIT_SECTIONS ".init.data$", ".init.text$" -#define DEV_INIT_SECTIONS ".devinit.data$", ".devinit.text$" -#define CPU_INIT_SECTIONS ".cpuinit.data$", ".cpuinit.text$" -#define MEM_INIT_SECTIONS ".meminit.data$", ".meminit.text$" +#define INIT_SECTIONS ".init.*" +#define DEV_INIT_SECTIONS ".devinit.*" +#define CPU_INIT_SECTIONS ".cpuinit.*" +#define MEM_INIT_SECTIONS ".meminit.*" -#define EXIT_SECTIONS ".exit.data$", ".exit.text$" -#define DEV_EXIT_SECTIONS ".devexit.data$", ".devexit.text$" -#define CPU_EXIT_SECTIONS ".cpuexit.data$", ".cpuexit.text$" -#define MEM_EXIT_SECTIONS ".memexit.data$", ".memexit.text$" +#define EXIT_SECTIONS ".exit.*" +#define DEV_EXIT_SECTIONS ".devexit.*" +#define CPU_EXIT_SECTIONS ".cpuexit.*" +#define MEM_EXIT_SECTIONS ".memexit.*" /* init data sections */ static const char *init_data_sections[] = { ALL_INIT_DATA_SECTIONS, NULL }; @@ -776,15 +805,6 @@ static const char *init_exit_sections[] = /* data section */ static const char *data_sections[] = { DATA_SECTIONS, NULL }; -/* sections that may refer to an init/exit section with no warning */ -static const char *initref_sections[] = -{ - ".text.init.refok*", - ".exit.text.refok*", - ".data.init.refok*", - NULL -}; - /* symbols in .data that may refer to init/exit sections */ static const char *symbol_white_list[] = @@ -853,12 +873,36 @@ const struct sectioncheck sectioncheck[] = { .tosec = { INIT_SECTIONS, NULL }, .mismatch = XXXINIT_TO_INIT, }, +/* Do not reference cpuinit code/data from meminit code/data */ +{ + .fromsec = { MEM_INIT_SECTIONS, NULL }, + .tosec = { CPU_INIT_SECTIONS, NULL }, + .mismatch = XXXINIT_TO_INIT, +}, +/* Do not reference meminit code/data from cpuinit code/data */ +{ + .fromsec = { CPU_INIT_SECTIONS, NULL }, + .tosec = { MEM_INIT_SECTIONS, NULL }, + .mismatch = XXXINIT_TO_INIT, +}, /* Do not reference exit code/data from devexit/cpuexit/memexit code/data */ { .fromsec = { DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS, NULL }, .tosec = { EXIT_SECTIONS, NULL }, .mismatch = XXXEXIT_TO_EXIT, }, +/* Do not reference cpuexit code/data from memexit code/data */ +{ + .fromsec = { MEM_EXIT_SECTIONS, NULL }, + .tosec = { CPU_EXIT_SECTIONS, NULL }, + .mismatch = XXXEXIT_TO_EXIT, +}, +/* Do not reference memexit code/data from cpuexit code/data */ +{ + .fromsec = { CPU_EXIT_SECTIONS, NULL }, + .tosec = { MEM_EXIT_SECTIONS, NULL }, + .mismatch = XXXEXIT_TO_EXIT, +}, /* Do not use exit code/data from init code */ { .fromsec = { ALL_INIT_SECTIONS, NULL }, @@ -897,11 +941,6 @@ static int section_mismatch(const char *fromsec, const char *tosec) /** * Whitelist to allow certain references to pass with no warning. * - * Pattern 0: - * Do not warn if funtion/data are marked with __init_refok/__initdata_refok. - * The pattern is identified by: - * fromsec = .text.init.refok* | .data.init.refok* - * * Pattern 1: * If a module parameter is declared __initdata and permissions=0 * then this is legal despite the warning generated. @@ -924,8 +963,7 @@ static int section_mismatch(const char *fromsec, const char *tosec) * *probe_one, *_console, *_timer * * Pattern 3: - * Whitelist all refereces from .text.head to .init.data - * Whitelist all refereces from .text.head to .init.text + * Whitelist all references from .head.text to any init section * * Pattern 4: * Some symbols belong to init section but still it is ok to reference @@ -940,10 +978,6 @@ static int section_mismatch(const char *fromsec, const char *tosec) static int secref_whitelist(const char *fromsec, const char *fromsym, const char *tosec, const char *tosym) { - /* Check for pattern 0 */ - if (match(fromsec, initref_sections)) - return 0; - /* Check for pattern 1 */ if (match(tosec, init_data_sections) && match(fromsec, data_sections) && @@ -1162,7 +1196,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch, "The variable %s references\n" "the %s %s%s%s\n" "If the reference is valid then annotate the\n" - "variable with __init* (see linux/init.h) " + "variable with __init* or __refdata (see linux/init.h) " "or name the variable:\n", fromsym, to, sec2annotation(tosec), tosym, to_p); while (*s) @@ -1359,7 +1393,7 @@ static void section_rela(const char *modname, struct elf_info *elf, fromsec = sech_name(elf, sechdr); fromsec += strlen(".rela"); /* if from section (name) is know good then skip it */ - if (check_section(modname, fromsec)) + if (match(fromsec, section_white_list)) return; for (rela = start; rela < stop; rela++) { @@ -1403,7 +1437,7 @@ static void section_rel(const char *modname, struct elf_info *elf, fromsec = sech_name(elf, sechdr); fromsec += strlen(".rel"); /* if from section (name) is know good then skip it */ - if (check_section(modname, fromsec)) + if (match(fromsec, section_white_list)) return; for (rel = start; rel < stop; rel++) { @@ -1453,7 +1487,7 @@ static void section_rel(const char *modname, struct elf_info *elf, * marked __initdata will be discarded when the module has been intialized. * Likewise for modules used built-in the sections marked __exit * are discarded because __exit marked function are supposed to be called - * only when a moduel is unloaded which never happes for built-in modules. + * only when a module is unloaded which never happens for built-in modules. * The check_sec_ref() function traverses all relocation records * to find all references to a section that reference a section that will * be discarded and warns about it. @@ -1466,6 +1500,7 @@ static void check_sec_ref(struct module *mod, const char *modname, /* Walk through all sections */ for (i = 0; i < elf->hdr->e_shnum; i++) { + check_section(modname, elf, &elf->sechdrs[i]); /* We want to process only relocation sections and not .init */ if (sechdrs[i].sh_type == SHT_RELA) section_rela(modname, elf, &elf->sechdrs[i]); @@ -1552,6 +1587,10 @@ static void read_symbols(char *modname) } license = get_modinfo(info.modinfo, info.modinfo_len, "license"); + if (info.modinfo && !license && !is_vmlinux(modname)) + warn("modpost: missing MODULE_LICENSE() in %s\n" + "see include/linux/module.h for " + "more information\n", modname); while (license) { if (license_is_gpl_compatible(license)) mod->gpl_compatible = 1; @@ -1585,12 +1624,12 @@ static void read_symbols(char *modname) parse_elf_finish(&info); - /* Our trick to get versioning for struct_module - it's + /* Our trick to get versioning for module struct etc. - it's * never passed as an argument to an exported function, so * the automatic versioning doesn't pick it up, but it's really * important anyhow */ if (modversions) - mod->unres = alloc_symbol("struct_module", 0, mod->unres); + mod->unres = alloc_symbol("module_layout", 0, mod->unres); } #define SZ 500 @@ -1707,6 +1746,14 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "};\n"); } +static void add_staging_flag(struct buffer *b, const char *name) +{ + static const char *staging_dir = "drivers/staging"; + + if (strncmp(staging_dir, name, strlen(staging_dir)) == 0) + buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); +} + /** * Record CRCs for unresolved symbols **/ @@ -1883,7 +1930,7 @@ static void read_dump(const char *fname, unsigned int kernel) if (!mod) { if (is_vmlinux(modname)) have_vmlinux = 1; - mod = new_module(NOFAIL(strdup(modname))); + mod = new_module(modname); mod->skip = 1; } s = sym_add_exported(symname, mod, export_no(export)); @@ -1967,14 +2014,18 @@ static void read_markers(const char *fname) mod = find_module(modname); if (!mod) { - if (is_vmlinux(modname)) - have_vmlinux = 1; - mod = new_module(NOFAIL(strdup(modname))); + mod = new_module(modname); mod->skip = 1; } + if (is_vmlinux(modname)) { + have_vmlinux = 1; + mod->skip = 0; + } - add_marker(mod, marker, fmt); + if (!mod->skip) + add_marker(mod, marker, fmt); } + release_file(file, size); return; fail: fatal("parse error in markers list file\n"); @@ -2015,6 +2066,11 @@ static void write_markers(const char *fname) write_if_changed(&buf, fname); } +struct ext_sym_list { + struct ext_sym_list *next; + const char *file; +}; + int main(int argc, char **argv) { struct module *mod; @@ -2025,8 +2081,10 @@ int main(int argc, char **argv) char *markers_write = NULL; int opt; int err; + struct ext_sym_list *extsym_iter; + struct ext_sym_list *extsym_start = NULL; - while ((opt = getopt(argc, argv, "i:I:msSo:awM:K:")) != -1) { + while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:")) != -1) { switch (opt) { case 'i': kernel_read = optarg; @@ -2035,6 +2093,17 @@ int main(int argc, char **argv) module_read = optarg; external_module = 1; break; + case 'c': + cross_build = 1; + break; + case 'e': + external_module = 1; + extsym_iter = + NOFAIL(malloc(sizeof(*extsym_iter))); + extsym_iter->next = extsym_start; + extsym_iter->file = optarg; + extsym_start = extsym_iter; + break; case 'm': modversions = 1; break; @@ -2068,6 +2137,12 @@ int main(int argc, char **argv) read_dump(kernel_read, 1); if (module_read) read_dump(module_read, 0); + while (extsym_start) { + read_dump(extsym_start->file, 0); + extsym_iter = extsym_start->next; + free(extsym_start); + extsym_start = extsym_iter; + } while (optind < argc) read_symbols(argv[optind++]); @@ -2089,6 +2164,7 @@ int main(int argc, char **argv) buf.pos = 0; add_header(&buf, mod); + add_staging_flag(&buf, mod->name); err |= add_versions(&buf, mod); add_depends(&buf, mod, modules); add_moddevtable(&buf, mod);