aboutsummaryrefslogtreecommitdiff
path: root/scripts/mod/modpost.c
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/mod/modpost.c')
-rw-r--r--scripts/mod/modpost.c117
1 files changed, 85 insertions, 32 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 8247979e8f6..9d9c5b905b3 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -17,6 +17,7 @@
#include <string.h>
#include <limits.h>
#include <stdbool.h>
+#include <errno.h>
#include "modpost.h"
#include "../../include/generated/autoconf.h"
#include "../../include/linux/license.h"
@@ -37,6 +38,8 @@ static int warn_unresolved = 0;
/* How a symbol is exported */
static int sec_mismatch_count = 0;
static int sec_mismatch_verbose = 1;
+/* ignore missing files */
+static int ignore_missing_files;
enum export {
export_plain, export_unused, export_gpl,
@@ -161,7 +164,7 @@ struct symbol {
unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */
unsigned int kernel:1; /* 1 if symbol is from kernel
* (only for external modules) **/
- unsigned int preloaded:1; /* 1 if symbol from Module.symvers */
+ unsigned int preloaded:1; /* 1 if symbol from Module.symvers, or crc */
enum export export; /* Type of export */
char name[0];
};
@@ -313,7 +316,7 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod,
s->module->name,
is_vmlinux(s->module->name) ?"":".ko");
} else {
- /* In case Modules.symvers was out of date */
+ /* In case Module.symvers was out of date */
s->module = mod;
}
}
@@ -329,8 +332,11 @@ static void sym_update_crc(const char *name, struct module *mod,
{
struct symbol *s = find_symbol(name);
- if (!s)
+ if (!s) {
s = new_symbol(name, mod, export);
+ /* Don't complain when we find it later. */
+ s->preloaded = 1;
+ }
s->crc = crc;
s->crc_valid = 1;
}
@@ -407,6 +413,11 @@ static int parse_elf(struct elf_info *info, const char *filename)
hdr = grab_file(filename, &info->size);
if (!hdr) {
+ if (ignore_missing_files) {
+ fprintf(stderr, "%s: %s (ignored)\n", filename,
+ strerror(errno));
+ return 0;
+ }
perror(filename);
exit(1);
}
@@ -573,12 +584,16 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
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)
+ strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 ||
+ strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
+ strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
return 1;
if (info->hdr->e_machine == EM_PPC64)
/* Special register function linked on all modules during final link of .ko */
if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 ||
- strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0)
+ strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 ||
+ strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
+ strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
return 1;
/* Do not ignore this symbol */
return 0;
@@ -599,17 +614,19 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
else
export = export_from_sec(info, get_secindex(info, sym));
+ /* CRC'd symbol */
+ if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
+ crc = (unsigned int) sym->st_value;
+ sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
+ export);
+ }
+
switch (sym->st_shndx) {
case SHN_COMMON:
- warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
- break;
- case SHN_ABS:
- /* CRC'd symbol */
- if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
- crc = (unsigned int) sym->st_value;
- sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
- export);
- }
+ if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) {
+ /* Should warn here, but modpost runs before the linker */
+ } else
+ warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);
break;
case SHN_UNDEF:
/* undefined symbol */
@@ -835,6 +852,7 @@ static const char *section_white_list[] =
".xt.lit", /* xtensa */
".arcextmap*", /* arc */
".gnu.linkonce.arcext*", /* arc : modules */
+ ".gnu.lto*",
NULL
};
@@ -844,7 +862,7 @@ static const char *section_white_list[] =
* without "ax" / "aw".
*/
static void check_section(const char *modname, struct elf_info *elf,
- Elf_Shdr *sechdr)
+ Elf_Shdr *sechdr)
{
const char *sec = sech_name(elf, sechdr);
@@ -1278,12 +1296,12 @@ static void print_section_list(const char * const list[20])
*/
static void report_sec_mismatch(const char *modname,
const struct sectioncheck *mismatch,
- const char *fromsec,
- unsigned long long fromaddr,
- const char *fromsym,
- int from_is_func,
- const char *tosec, const char *tosym,
- int to_is_func)
+ const char *fromsec,
+ unsigned long long fromaddr,
+ const char *fromsym,
+ int from_is_func,
+ const char *tosec, const char *tosym,
+ int to_is_func)
{
const char *from, *from_p;
const char *to, *to_p;
@@ -1423,7 +1441,7 @@ static void report_sec_mismatch(const char *modname,
}
static void check_section_mismatch(const char *modname, struct elf_info *elf,
- Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
+ Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
{
const char *tosec;
const struct sectioncheck *mismatch;
@@ -1441,6 +1459,10 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf,
to = find_elf_symbol(elf, r->r_addend, sym);
tosym = sym_name(elf, to);
+ if (!strncmp(fromsym, "reference___initcall",
+ sizeof("reference___initcall")-1))
+ return;
+
/* check whitelist - we may ignore it */
if (secref_whitelist(mismatch,
fromsec, fromsym, tosec, tosym)) {
@@ -1488,6 +1510,16 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
#define R_ARM_JUMP24 29
#endif
+#ifndef R_ARM_THM_CALL
+#define R_ARM_THM_CALL 10
+#endif
+#ifndef R_ARM_THM_JUMP24
+#define R_ARM_THM_JUMP24 30
+#endif
+#ifndef R_ARM_THM_JUMP19
+#define R_ARM_THM_JUMP19 51
+#endif
+
static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
{
unsigned int r_typ = ELF_R_TYPE(r->r_info);
@@ -1496,15 +1528,18 @@ static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
case R_ARM_ABS32:
/* From ARM ABI: (S + A) | T */
r->r_addend = (int)(long)
- (elf->symtab_start + ELF_R_SYM(r->r_info));
+ (elf->symtab_start + ELF_R_SYM(r->r_info));
break;
case R_ARM_PC24:
case R_ARM_CALL:
case R_ARM_JUMP24:
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_JUMP19:
/* From ARM ABI: ((S + A) | T) - P */
r->r_addend = (int)(long)(elf->hdr +
- sechdr->sh_offset +
- (r->r_offset - sechdr->sh_addr));
+ sechdr->sh_offset +
+ (r->r_offset - sechdr->sh_addr));
break;
default:
return 1;
@@ -1536,7 +1571,7 @@ static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
}
static void section_rela(const char *modname, struct elf_info *elf,
- Elf_Shdr *sechdr)
+ Elf_Shdr *sechdr)
{
Elf_Sym *sym;
Elf_Rela *rela;
@@ -1580,7 +1615,7 @@ static void section_rela(const char *modname, struct elf_info *elf,
}
static void section_rel(const char *modname, struct elf_info *elf,
- Elf_Shdr *sechdr)
+ Elf_Shdr *sechdr)
{
Elf_Sym *sym;
Elf_Rel *rel;
@@ -1650,7 +1685,7 @@ static void section_rel(const char *modname, struct elf_info *elf,
* be discarded and warns about it.
**/
static void check_sec_ref(struct module *mod, const char *modname,
- struct elf_info *elf)
+ struct elf_info *elf)
{
int i;
Elf_Shdr *sechdrs = elf->sechdrs;
@@ -1666,6 +1701,19 @@ static void check_sec_ref(struct module *mod, const char *modname,
}
}
+static char *remove_dot(char *s)
+{
+ char *end;
+ int n = strcspn(s, ".");
+
+ if (n > 0 && s[n] != 0) {
+ strtoul(s + n + 1, &end, 10);
+ if (end > s + n + 1 && (*end == '.' || *end == 0))
+ s[n] = 0;
+ }
+ return s;
+}
+
static void read_symbols(char *modname)
{
const char *symname;
@@ -1704,7 +1752,7 @@ static void read_symbols(char *modname)
}
for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
- symname = info.strtab + sym->st_name;
+ symname = remove_dot(info.strtab + sym->st_name);
handle_modversions(mod, &info, sym, symname);
handle_moddevtable(mod, &info, sym, symname);
@@ -1853,7 +1901,7 @@ static void add_header(struct buffer *b, struct module *mod)
buf_printf(b, "\n");
buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
buf_printf(b, "\n");
- buf_printf(b, "struct module __this_module\n");
+ buf_printf(b, "__visible struct module __this_module\n");
buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
if (mod->has_init)
@@ -1897,7 +1945,7 @@ static int add_versions(struct buffer *b, struct module *mod)
s->name, mod->name);
} else {
merror("\"%s\" [%s.ko] undefined!\n",
- s->name, mod->name);
+ s->name, mod->name);
err = 1;
}
}
@@ -2065,8 +2113,10 @@ static void read_dump(const char *fname, unsigned int kernel)
s->preloaded = 1;
sym_update_crc(symname, mod, crc, export_no(export));
}
+ release_file(file, size);
return;
fail:
+ release_file(file, size);
fatal("parse error in symbol dump file\n");
}
@@ -2119,7 +2169,7 @@ int main(int argc, char **argv)
struct ext_sym_list *extsym_iter;
struct ext_sym_list *extsym_start = NULL;
- while ((opt = getopt(argc, argv, "i:I:e:msST:o:awM:K:")) != -1) {
+ while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:")) != -1) {
switch (opt) {
case 'i':
kernel_read = optarg;
@@ -2139,6 +2189,9 @@ int main(int argc, char **argv)
case 'm':
modversions = 1;
break;
+ case 'n':
+ ignore_missing_files = 1;
+ break;
case 'o':
dump_write = optarg;
break;