diff options
Diffstat (limited to 'scripts/mod/modpost.c')
| -rw-r--r-- | scripts/mod/modpost.c | 117 | 
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;  | 
