diff options
Diffstat (limited to 'scripts/mod')
| -rw-r--r-- | scripts/mod/modpost.c | 312 | ||||
| -rw-r--r-- | scripts/mod/modpost.h | 3 | 
2 files changed, 188 insertions, 127 deletions
| diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 3645e980da7..04579a51790 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -75,7 +75,8 @@ static int is_vmlinux(const char *modname)  	else  		myname = modname; -	return strcmp(myname, "vmlinux") == 0; +	return (strcmp(myname, "vmlinux") == 0) || +	       (strcmp(myname, "vmlinux.o") == 0);  }  void *do_nofail(void *ptr, const char *expr) @@ -374,6 +375,7 @@ static int parse_elf(struct elf_info *info, const char *filename)  	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);  	sechdrs = (void *)hdr + hdr->e_shoff;  	info->sechdrs = sechdrs; @@ -384,6 +386,8 @@ static int parse_elf(struct elf_info *info, const char *filename)  		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);  	}  	/* Find symbol table. */  	for (i = 1; i < hdr->e_shnum; i++) { @@ -605,18 +609,14 @@ static int strrcmp(const char *s, const char *sub)   *   warn here.   *   the pattern is identified by:   *   tosec   = .init.text | .exit.text | .init.data - *   fromsec = .data - *   atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console + *   fromsec = .data | .data.rel | .data.rel.* + *   atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console, *_timer   *   * Pattern 3: - *   Whitelist all references from .pci_fixup* section to .init.text - *   This is part of the PCI init when built-in - * - * Pattern 4:   *   Whitelist all refereces from .text.head to .init.data   *   Whitelist all refereces from .text.head to .init.text   * - * Pattern 5: + * Pattern 4:   *   Some symbols belong to init section but still it is ok to reference   *   these from non-init sections as these symbols don't have any memory   *   allocated for them and symbol address and value are same. So even @@ -625,26 +625,6 @@ static int strrcmp(const char *s, const char *sub)   *   This pattern is identified by   *   refsymname = __init_begin, _sinittext, _einittext   * - * Pattern 7: - *  Logos used in drivers/video/logo reside in __initdata but the - *  funtion that references them are EXPORT_SYMBOL() so cannot be - *  marker __init. So we whitelist them here. - *  The pattern is: - *  tosec      = .init.data - *  fromsec    = .text* - *  refsymname = logo_ - * - * Pattern 8: - *  Symbols contained in .paravirtprobe may safely reference .init.text. - *  The pattern is: - *  tosec   = .init.text - *  fromsec  = .paravirtprobe - * - * Pattern 10: - *  ia64 has machvec table for each platform and - *  powerpc has a machine desc table for each platform. - *  It is mixture of function pointers of .init.text and .text. - *  fromsec  = .machvec | .machine.desc   **/  static int secref_whitelist(const char *modname, const char *tosec,  			    const char *fromsec, const char *atsym, @@ -655,12 +635,12 @@ static int secref_whitelist(const char *modname, const char *tosec,  	const char *pat2sym[] = {  		"driver",  		"_template", /* scsi uses *_template a lot */ +		"_timer",    /* arm uses ops structures named _timer a lot */  		"_sht",      /* scsi also used *_sht to some extent */  		"_ops",  		"_probe",  		"_probe_one",  		"_console", -		"apic_es7000",  		NULL  	}; @@ -692,7 +672,9 @@ static int secref_whitelist(const char *modname, const char *tosec,  	    (strcmp(tosec, ".exit.text") != 0) &&  	    (strcmp(tosec, ".init.data") != 0))  		f2 = 0; -	if (strcmp(fromsec, ".data") != 0) +	if ((strcmp(fromsec, ".data") != 0) && +	    (strcmp(fromsec, ".data.rel") != 0) && +	    (strncmp(fromsec, ".data.rel.", strlen(".data.rel.")) != 0))  		f2 = 0;  	for (s = pat2sym; *s; s++) @@ -702,37 +684,16 @@ static int secref_whitelist(const char *modname, const char *tosec,  		return 1;  	/* Check for pattern 3 */ -	if ((strncmp(fromsec, ".pci_fixup", strlen(".pci_fixup")) == 0) && -	    (strcmp(tosec, ".init.text") == 0)) -	return 1; - -	/* Check for pattern 4 */  	if ((strcmp(fromsec, ".text.head") == 0) &&  		((strcmp(tosec, ".init.data") == 0) ||  		(strcmp(tosec, ".init.text") == 0)))  	return 1; -	/* Check for pattern 5 */ +	/* Check for pattern 4 */  	for (s = pat3refsym; *s; s++)  		if (strcmp(refsymname, *s) == 0)  			return 1; -	/* Check for pattern 7 */ -	if ((strcmp(tosec, ".init.data") == 0) && -	    (strncmp(fromsec, ".text", strlen(".text")) == 0) && -	    (strncmp(refsymname, "logo_", strlen("logo_")) == 0)) -		return 1; - -	/* Check for pattern 8 */ -	if ((strcmp(tosec, ".init.text") == 0) && -	    (strcmp(fromsec, ".paravirtprobe") == 0)) -		return 1; - -	/* Check for pattern 10 */ -	if ((strcmp(fromsec, ".machvec") == 0) || -	    (strcmp(fromsec, ".machine.desc") == 0)) -		return 1; -  	return 0;  } @@ -753,6 +714,8 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr,  	for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {  		if (sym->st_shndx != relsym->st_shndx)  			continue; +		if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) +			continue;  		if (sym->st_value == addr)  			return sym;  	} @@ -864,11 +827,6 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,  			     elf->strtab + before->st_name, refsymname))  		return; -	/* fromsec whitelist - without a valid 'before' -	 * powerpc has a GOT table in .got2 section */ -	if (strcmp(fromsec, ".got2") == 0) -		return; -  	if (before && after) {  		warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s "  		     "(between '%s' and '%s')\n", @@ -895,6 +853,78 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,  	}  } +static unsigned int *reloc_location(struct elf_info *elf, +					   int rsection, Elf_Rela *r) +{ +	Elf_Shdr *sechdrs = elf->sechdrs; +	int section = sechdrs[rsection].sh_info; + +	return (void *)elf->hdr + sechdrs[section].sh_offset + +		(r->r_offset - sechdrs[section].sh_addr); +} + +static int addend_386_rel(struct elf_info *elf, int rsection, Elf_Rela *r) +{ +	unsigned int r_typ = ELF_R_TYPE(r->r_info); +	unsigned int *location = reloc_location(elf, rsection, r); + +	switch (r_typ) { +	case R_386_32: +		r->r_addend = TO_NATIVE(*location); +		break; +	case R_386_PC32: +		r->r_addend = TO_NATIVE(*location) + 4; +		/* For CONFIG_RELOCATABLE=y */ +		if (elf->hdr->e_type == ET_EXEC) +			r->r_addend += r->r_offset; +		break; +	} +	return 0; +} + +static int addend_arm_rel(struct elf_info *elf, int rsection, Elf_Rela *r) +{ +	unsigned int r_typ = ELF_R_TYPE(r->r_info); + +	switch (r_typ) { +	case R_ARM_ABS32: +		/* From ARM ABI: (S + A) | T */ +		r->r_addend = (int)(long)(elf->symtab_start + ELF_R_SYM(r->r_info)); +		break; +	case R_ARM_PC24: +		/* From ARM ABI: ((S + A) | T) - P */ +		r->r_addend = (int)(long)(elf->hdr + elf->sechdrs[rsection].sh_offset + +		                          (r->r_offset - elf->sechdrs[rsection].sh_addr)); +		break; +	default: +		return 1; +	} +	return 0; +} + +static int addend_mips_rel(struct elf_info *elf, int rsection, Elf_Rela *r) +{ +	unsigned int r_typ = ELF_R_TYPE(r->r_info); +	unsigned int *location = reloc_location(elf, rsection, r); +	unsigned int inst; + +	if (r_typ == R_MIPS_HI16) +		return 1;	/* skip this */ +	inst = TO_NATIVE(*location); +	switch (r_typ) { +	case R_MIPS_LO16: +		r->r_addend = inst & 0xffff; +		break; +	case R_MIPS_26: +		r->r_addend = (inst & 0x03ffffff) << 2; +		break; +	case R_MIPS_32: +		r->r_addend = inst; +		break; +	} +	return 0; +} +  /**   * A module includes a number of sections that are discarded   * either when loaded or when used as built-in. @@ -938,8 +968,11 @@ static void check_sec_ref(struct module *mod, const char *modname,  				r.r_offset = TO_NATIVE(rela->r_offset);  #if KERNEL_ELFCLASS == ELFCLASS64  				if (hdr->e_machine == EM_MIPS) { +					unsigned int r_typ;  					r_sym = ELF64_MIPS_R_SYM(rela->r_info);  					r_sym = TO_NATIVE(r_sym); +					r_typ = ELF64_MIPS_R_TYPE(rela->r_info); +					r.r_info = ELF64_R_INFO(r_sym, r_typ);  				} else {  					r.r_info = TO_NATIVE(rela->r_info);  					r_sym = ELF_R_SYM(r.r_info); @@ -972,8 +1005,11 @@ static void check_sec_ref(struct module *mod, const char *modname,  				r.r_offset = TO_NATIVE(rel->r_offset);  #if KERNEL_ELFCLASS == ELFCLASS64  				if (hdr->e_machine == EM_MIPS) { +					unsigned int r_typ;  					r_sym = ELF64_MIPS_R_SYM(rel->r_info);  					r_sym = TO_NATIVE(r_sym); +					r_typ = ELF64_MIPS_R_TYPE(rel->r_info); +					r.r_info = ELF64_R_INFO(r_sym, r_typ);  				} else {  					r.r_info = TO_NATIVE(rel->r_info);  					r_sym = ELF_R_SYM(r.r_info); @@ -983,6 +1019,20 @@ static void check_sec_ref(struct module *mod, const char *modname,  				r_sym = ELF_R_SYM(r.r_info);  #endif  				r.r_addend = 0; +				switch (hdr->e_machine) { +				case EM_386: +					if (addend_386_rel(elf, i, &r)) +						continue; +					break; +				case EM_ARM: +					if(addend_arm_rel(elf, i, &r)) +						continue; +					break; +				case EM_MIPS: +					if (addend_mips_rel(elf, i, &r)) +						continue; +					break; +				}  				sym = elf->symtab_start + r_sym;  				/* Skip special sections */  				if (sym->st_shndx >= SHN_LORESERVE) @@ -998,6 +1048,63 @@ static void check_sec_ref(struct module *mod, const char *modname,  	}  } +/* + * Identify sections from which references to either a + * .init or a .exit section is OK. + * + * [OPD] Keith Ownes <kaos@sgi.com> commented: + * For our future {in}sanity, add a comment that this is the ppc .opd + * section, not the ia64 .opd section. + * ia64 .opd should not point to discarded sections. + * [.rodata] like for .init.text we ignore .rodata references -same reason + */ +static int initexit_section_ref_ok(const char *name) +{ +	const char **s; +	/* Absolute section names */ +	const char *namelist1[] = { +		"__bug_table",		/* used by powerpc for BUG() */ +		"__ex_table", +		".altinstructions", +		".cranges",		/* used by sh64 */ +		".fixup", +		".machvec",		/* ia64 + powerpc uses these */ +		".machine.desc", +		".opd",			/* See comment [OPD] */ +		".parainstructions", +		".pdr", +		".plt",			/* seen on ARCH=um build on x86_64. Harmless */ +		".smp_locks", +		".stab", +		NULL +	}; +	/* Start of section names */ +	const char *namelist2[] = { +		".debug", +		".eh_frame", +		".note",		/* ignore ELF notes - may contain anything */ +		".got",			/* powerpc - global offset table */ +		".toc",			/* powerpc - table of contents */ +		NULL +	}; +	/* part of section name */ +	const char *namelist3 [] = { +		".unwind",  /* Sample: IA_64.unwind.exit.text */ +		NULL +	}; + +	for (s = namelist1; *s; s++) +		if (strcmp(*s, name) == 0) +			return 1; +	for (s = namelist2; *s; s++) +		if (strncmp(*s, name, strlen(*s)) == 0) +			return 1; +	for (s = namelist3; *s; s++) +		if (strstr(name, *s) != NULL) +			return 1; +	return 0; +} +  /**   * Functions used only during module init is marked __init and is stored in   * a .init.text section. Likewise data is marked __initdata and stored in @@ -1014,7 +1121,7 @@ static int init_section(const char *name)  	return 0;  } -/** +/*   * Identify sections from which references to a .init section is OK.   *   * Unfortunately references to read only data that referenced .init @@ -1028,48 +1135,31 @@ static int init_section(const char *name)   *   * where vgacon_startup is __init.  If you want to wade through the false   * positives, take out the check for rodata. - **/ + */  static int init_section_ref_ok(const char *name)  {  	const char **s;  	/* Absolute section names */  	const char *namelist1[] = { -		".init", -		".opd",   /* see comment [OPD] at exit_section_ref_ok() */ -		".toc1",  /* used by ppc64 */ -		".stab", -		".data.rel.ro", /* used by parisc64 */ -		".parainstructions", -		".text.lock", -		"__bug_table", /* used by powerpc for BUG() */ -		".pci_fixup_header", -		".pci_fixup_final", -		".pdr", -		"__param", -		"__ex_table", -		".fixup", -		".smp_locks", -		".plt",  /* seen on ARCH=um build on x86_64. Harmless */ +		"__dbe_table",		/* MIPS generate these */  		"__ftr_fixup",		/* powerpc cpu feature fixup */  		"__fw_ftr_fixup",	/* powerpc firmware feature fixup */ -		".cranges",	/* used by sh64 */ +		"__param", +		".data.rel.ro",		/* used by parisc64 */ +		".init", +		".text.lock",  		NULL  	};  	/* Start of section names */  	const char *namelist2[] = {  		".init.", -		".altinstructions", -		".eh_frame", -		".debug", -		".parainstructions", +		".pci_fixup",  		".rodata",  		NULL  	}; -	/* part of section name */ -	const char *namelist3 [] = { -		".unwind",  /* sample: IA_64.unwind.init.text */ -		NULL -	}; + +	if (initexit_section_ref_ok(name)) +		return 1;  	for (s = namelist1; *s; s++)  		if (strcmp(*s, name) == 0) @@ -1077,9 +1167,10 @@ static int init_section_ref_ok(const char *name)  	for (s = namelist2; *s; s++)  		if (strncmp(*s, name, strlen(*s)) == 0)  			return 1; -	for (s = namelist3; *s; s++) -		if (strstr(name, *s) != NULL) -			return 1; + +	/* If section name ends with ".init" we allow references +	 * as is the case with .initcallN.init, .early_param.init, .taglist.init etc +	 */  	if (strrcmp(name, ".init") == 0)  		return 1;  	return 0; @@ -1104,58 +1195,25 @@ static int exit_section(const char *name)  /*   * Identify sections from which references to a .exit section is OK. - * - * [OPD] Keith Ownes <kaos@sgi.com> commented: - * For our future {in}sanity, add a comment that this is the ppc .opd - * section, not the ia64 .opd section. - * ia64 .opd should not point to discarded sections. - * [.rodata] like for .init.text we ignore .rodata references -same reason - **/ + */  static int exit_section_ref_ok(const char *name)  {  	const char **s;  	/* Absolute section names */  	const char *namelist1[] = { -		".exit.text",  		".exit.data", -		".init.text", -		".rodata", -		".opd", /* See comment [OPD] */ -		".toc1",  /* used by ppc64 */ -		".altinstructions", -		".pdr", -		"__bug_table", /* used by powerpc for BUG() */ +		".exit.text",  		".exitcall.exit", -		".eh_frame", -		".parainstructions", -		".stab", -		"__ex_table", -		".fixup", -		".smp_locks", -		".plt",  /* seen on ARCH=um build on x86_64. Harmless */ -		".cranges",	/* used by sh64 */ -		NULL -	}; -	/* Start of section names */ -	const char *namelist2[] = { -		".debug", -		NULL -	}; -	/* part of section name */ -	const char *namelist3 [] = { -		".unwind",  /* Sample: IA_64.unwind.exit.text */ +		".rodata",  		NULL  	}; +	if (initexit_section_ref_ok(name)) +		return 1; +  	for (s = namelist1; *s; s++)  		if (strcmp(*s, name) == 0)  			return 1; -	for (s = namelist2; *s; s++) -		if (strncmp(*s, name, strlen(*s)) == 0) -			return 1; -	for (s = namelist3; *s; s++) -		if (strstr(name, *s) != NULL) -			return 1;  	return 0;  } diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 0858caa9c03..4156dd34c5d 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -60,6 +60,9 @@ typedef union  #define ELF64_MIPS_R_SYM(i) \    ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym) +#define ELF64_MIPS_R_TYPE(i) \ +  ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_type1) +  #if KERNEL_ELFDATA != HOST_ELFDATA  static inline void __endian(const void *src, void *dest, unsigned int size) | 
