aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/mod/modpost.c
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/mod/modpost.c')
-rw-r--r--scripts/mod/modpost.c169
1 files changed, 116 insertions, 53 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 113dc77b9f60..8424d1f53bbe 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -384,6 +384,7 @@ static int parse_elf(struct elf_info *info, const char *filename)
384 sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); 384 sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
385 sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); 385 sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
386 sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); 386 sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
387 sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info);
387 } 388 }
388 /* Find symbol table. */ 389 /* Find symbol table. */
389 for (i = 1; i < hdr->e_shnum; i++) { 390 for (i = 1; i < hdr->e_shnum; i++) {
@@ -582,6 +583,12 @@ static int strrcmp(const char *s, const char *sub)
582 583
583/** 584/**
584 * Whitelist to allow certain references to pass with no warning. 585 * Whitelist to allow certain references to pass with no warning.
586 *
587 * Pattern 0:
588 * Do not warn if funtion/data are marked with __init_refok/__initdata_refok.
589 * The pattern is identified by:
590 * fromsec = .text.init.refok | .data.init.refok
591 *
585 * Pattern 1: 592 * Pattern 1:
586 * If a module parameter is declared __initdata and permissions=0 593 * If a module parameter is declared __initdata and permissions=0
587 * then this is legal despite the warning generated. 594 * then this is legal despite the warning generated.
@@ -619,14 +626,6 @@ static int strrcmp(const char *s, const char *sub)
619 * This pattern is identified by 626 * This pattern is identified by
620 * refsymname = __init_begin, _sinittext, _einittext 627 * refsymname = __init_begin, _sinittext, _einittext
621 * 628 *
622 * Pattern 6:
623 * During the early init phase we have references from .init.text to
624 * .text we have an intended section mismatch - do not warn about it.
625 * See kernel_init() in init/main.c
626 * tosec = .init.text
627 * fromsec = .text
628 * atsym = kernel_init
629 *
630 * Pattern 7: 629 * Pattern 7:
631 * Logos used in drivers/video/logo reside in __initdata but the 630 * Logos used in drivers/video/logo reside in __initdata but the
632 * funtion that references them are EXPORT_SYMBOL() so cannot be 631 * funtion that references them are EXPORT_SYMBOL() so cannot be
@@ -642,16 +641,11 @@ static int strrcmp(const char *s, const char *sub)
642 * tosec = .init.text 641 * tosec = .init.text
643 * fromsec = .paravirtprobe 642 * fromsec = .paravirtprobe
644 * 643 *
645 * Pattern 9:
646 * Some of functions are common code between boot time and hotplug
647 * time. The bootmem allocater is called only boot time in its
648 * functions. So it's ok to reference.
649 * tosec = .init.text
650 *
651 * Pattern 10: 644 * Pattern 10:
652 * ia64 has machvec table for each platform. It is mixture of function 645 * ia64 has machvec table for each platform and
653 * pointer of .init.text and .text. 646 * powerpc has a machine desc table for each platform.
654 * fromsec = .machvec 647 * It is mixture of function pointers of .init.text and .text.
648 * fromsec = .machvec | .machine.desc
655 **/ 649 **/
656static int secref_whitelist(const char *modname, const char *tosec, 650static int secref_whitelist(const char *modname, const char *tosec,
657 const char *fromsec, const char *atsym, 651 const char *fromsec, const char *atsym,
@@ -678,11 +672,10 @@ static int secref_whitelist(const char *modname, const char *tosec,
678 NULL 672 NULL
679 }; 673 };
680 674
681 const char *pat4sym[] = { 675 /* Check for pattern 0 */
682 "sparse_index_alloc", 676 if ((strcmp(fromsec, ".text.init.refok") == 0) ||
683 "zone_wait_table_init", 677 (strcmp(fromsec, ".data.init.refok") == 0))
684 NULL 678 return 1;
685 };
686 679
687 /* Check for pattern 1 */ 680 /* Check for pattern 1 */
688 if (strcmp(tosec, ".init.data") != 0) 681 if (strcmp(tosec, ".init.data") != 0)
@@ -725,12 +718,6 @@ static int secref_whitelist(const char *modname, const char *tosec,
725 if (strcmp(refsymname, *s) == 0) 718 if (strcmp(refsymname, *s) == 0)
726 return 1; 719 return 1;
727 720
728 /* Check for pattern 6 */
729 if ((strcmp(tosec, ".init.text") == 0) &&
730 (strcmp(fromsec, ".text") == 0) &&
731 (strcmp(refsymname, "kernel_init") == 0))
732 return 1;
733
734 /* Check for pattern 7 */ 721 /* Check for pattern 7 */
735 if ((strcmp(tosec, ".init.data") == 0) && 722 if ((strcmp(tosec, ".init.data") == 0) &&
736 (strncmp(fromsec, ".text", strlen(".text")) == 0) && 723 (strncmp(fromsec, ".text", strlen(".text")) == 0) &&
@@ -742,15 +729,9 @@ static int secref_whitelist(const char *modname, const char *tosec,
742 (strcmp(fromsec, ".paravirtprobe") == 0)) 729 (strcmp(fromsec, ".paravirtprobe") == 0))
743 return 1; 730 return 1;
744 731
745 /* Check for pattern 9 */
746 if ((strcmp(tosec, ".init.text") == 0) &&
747 (strcmp(fromsec, ".text") == 0))
748 for (s = pat4sym; *s; s++)
749 if (strcmp(atsym, *s) == 0)
750 return 1;
751
752 /* Check for pattern 10 */ 732 /* Check for pattern 10 */
753 if (strcmp(fromsec, ".machvec") == 0) 733 if ((strcmp(fromsec, ".machvec") == 0) ||
734 (strcmp(fromsec, ".machine.desc") == 0))
754 return 1; 735 return 1;
755 736
756 return 0; 737 return 0;
@@ -773,6 +754,8 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr,
773 for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { 754 for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
774 if (sym->st_shndx != relsym->st_shndx) 755 if (sym->st_shndx != relsym->st_shndx)
775 continue; 756 continue;
757 if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
758 continue;
776 if (sym->st_value == addr) 759 if (sym->st_value == addr)
777 return sym; 760 return sym;
778 } 761 }
@@ -884,33 +867,99 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
884 elf->strtab + before->st_name, refsymname)) 867 elf->strtab + before->st_name, refsymname))
885 return; 868 return;
886 869
870 /* fromsec whitelist - without a valid 'before'
871 * powerpc has a GOT table in .got2 section */
872 if (strcmp(fromsec, ".got2") == 0)
873 return;
874
887 if (before && after) { 875 if (before && after) {
888 warn("%s - Section mismatch: reference to %s:%s from %s " 876 warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s "
889 "between '%s' (at offset 0x%llx) and '%s'\n", 877 "(between '%s' and '%s')\n",
890 modname, secname, refsymname, fromsec, 878 modname, fromsec, (unsigned long long)r.r_offset,
879 secname, refsymname,
891 elf->strtab + before->st_name, 880 elf->strtab + before->st_name,
892 (long long)r.r_offset,
893 elf->strtab + after->st_name); 881 elf->strtab + after->st_name);
894 } else if (before) { 882 } else if (before) {
895 warn("%s - Section mismatch: reference to %s:%s from %s " 883 warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s "
896 "after '%s' (at offset 0x%llx)\n", 884 "(after '%s')\n",
897 modname, secname, refsymname, fromsec, 885 modname, fromsec, (unsigned long long)r.r_offset,
898 elf->strtab + before->st_name, 886 secname, refsymname,
899 (long long)r.r_offset); 887 elf->strtab + before->st_name);
900 } else if (after) { 888 } else if (after) {
901 warn("%s - Section mismatch: reference to %s:%s from %s " 889 warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s "
902 "before '%s' (at offset -0x%llx)\n", 890 "before '%s' (at offset -0x%llx)\n",
903 modname, secname, refsymname, fromsec, 891 modname, fromsec, (unsigned long long)r.r_offset,
904 elf->strtab + after->st_name, 892 secname, refsymname,
905 (long long)r.r_offset); 893 elf->strtab + after->st_name);
906 } else { 894 } else {
907 warn("%s - Section mismatch: reference to %s:%s from %s " 895 warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s\n",
908 "(offset 0x%llx)\n", 896 modname, fromsec, (unsigned long long)r.r_offset,
909 modname, secname, fromsec, refsymname, 897 secname, refsymname);
910 (long long)r.r_offset);
911 } 898 }
912} 899}
913 900
901static void addend_386_rel(struct elf_info *elf, int section, Elf_Rela *r)
902{
903 Elf_Shdr *sechdrs = elf->sechdrs;
904 unsigned int r_typ;
905 unsigned int *location;
906
907 r_typ = ELF_R_TYPE(r->r_info);
908 location = (void *)elf->hdr +
909 sechdrs[sechdrs[section].sh_info].sh_offset + r->r_offset;
910 switch (r_typ) {
911 case R_386_32:
912 r->r_addend = TO_NATIVE(*location);
913 break;
914 case R_386_PC32:
915 r->r_addend = TO_NATIVE(*location) + 4;
916 break;
917 }
918}
919
920static void addend_arm_rel(struct elf_info *elf, int section, Elf_Rela *r)
921{
922 Elf_Shdr *sechdrs = elf->sechdrs;
923 unsigned int r_typ;
924 unsigned int *location;
925
926 r_typ = ELF_R_TYPE(r->r_info);
927 location = (void *)elf->hdr +
928 sechdrs[sechdrs[section].sh_info].sh_offset + r->r_offset;
929 switch (r_typ) {
930 case R_ARM_ABS32:
931 r->r_addend = TO_NATIVE(*location);
932 break;
933 case R_ARM_PC24:
934 r->r_addend = ((TO_NATIVE(*location) & 0x00ffffff) << 2) + 8;
935 break;
936 }
937}
938
939static int addend_mips_rel(struct elf_info *elf, int section, Elf_Rela *r)
940{
941 Elf_Shdr *sechdrs = elf->sechdrs;
942 unsigned int r_typ;
943 unsigned int *location;
944 unsigned int inst;
945
946 r_typ = ELF_R_TYPE(r->r_info);
947 if (r_typ == R_MIPS_HI16)
948 return 1; /* skip this */
949 location = (void *)elf->hdr +
950 sechdrs[sechdrs[section].sh_info].sh_offset + r->r_offset;
951 inst = TO_NATIVE(*location);
952 switch (r_typ) {
953 case R_MIPS_LO16:
954 r->r_addend = ((inst & 0xffff) ^ 0x8000) - 0x8000;
955 break;
956 case R_MIPS_26:
957 r->r_addend = (inst & 0x03ffffff) << 2;
958 break;
959 }
960 return 0;
961}
962
914/** 963/**
915 * A module includes a number of sections that are discarded 964 * A module includes a number of sections that are discarded
916 * either when loaded or when used as built-in. 965 * either when loaded or when used as built-in.
@@ -954,8 +1003,11 @@ static void check_sec_ref(struct module *mod, const char *modname,
954 r.r_offset = TO_NATIVE(rela->r_offset); 1003 r.r_offset = TO_NATIVE(rela->r_offset);
955#if KERNEL_ELFCLASS == ELFCLASS64 1004#if KERNEL_ELFCLASS == ELFCLASS64
956 if (hdr->e_machine == EM_MIPS) { 1005 if (hdr->e_machine == EM_MIPS) {
1006 unsigned int r_typ;
957 r_sym = ELF64_MIPS_R_SYM(rela->r_info); 1007 r_sym = ELF64_MIPS_R_SYM(rela->r_info);
958 r_sym = TO_NATIVE(r_sym); 1008 r_sym = TO_NATIVE(r_sym);
1009 r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
1010 r.r_info = ELF64_R_INFO(r_sym, r_typ);
959 } else { 1011 } else {
960 r.r_info = TO_NATIVE(rela->r_info); 1012 r.r_info = TO_NATIVE(rela->r_info);
961 r_sym = ELF_R_SYM(r.r_info); 1013 r_sym = ELF_R_SYM(r.r_info);
@@ -988,8 +1040,11 @@ static void check_sec_ref(struct module *mod, const char *modname,
988 r.r_offset = TO_NATIVE(rel->r_offset); 1040 r.r_offset = TO_NATIVE(rel->r_offset);
989#if KERNEL_ELFCLASS == ELFCLASS64 1041#if KERNEL_ELFCLASS == ELFCLASS64
990 if (hdr->e_machine == EM_MIPS) { 1042 if (hdr->e_machine == EM_MIPS) {
1043 unsigned int r_typ;
991 r_sym = ELF64_MIPS_R_SYM(rel->r_info); 1044 r_sym = ELF64_MIPS_R_SYM(rel->r_info);
992 r_sym = TO_NATIVE(r_sym); 1045 r_sym = TO_NATIVE(r_sym);
1046 r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
1047 r.r_info = ELF64_R_INFO(r_sym, r_typ);
993 } else { 1048 } else {
994 r.r_info = TO_NATIVE(rel->r_info); 1049 r.r_info = TO_NATIVE(rel->r_info);
995 r_sym = ELF_R_SYM(r.r_info); 1050 r_sym = ELF_R_SYM(r.r_info);
@@ -999,6 +1054,14 @@ static void check_sec_ref(struct module *mod, const char *modname,
999 r_sym = ELF_R_SYM(r.r_info); 1054 r_sym = ELF_R_SYM(r.r_info);
1000#endif 1055#endif
1001 r.r_addend = 0; 1056 r.r_addend = 0;
1057 if (hdr->e_machine == EM_386)
1058 addend_386_rel(elf, i, &r);
1059 else if (hdr->e_machine == EM_ARM)
1060 addend_arm_rel(elf, i, &r);
1061 else if (hdr->e_machine == EM_MIPS) {
1062 if (addend_mips_rel(elf, i, &r))
1063 continue;
1064 }
1002 sym = elf->symtab_start + r_sym; 1065 sym = elf->symtab_start + r_sym;
1003 /* Skip special sections */ 1066 /* Skip special sections */
1004 if (sym->st_shndx >= SHN_LORESERVE) 1067 if (sym->st_shndx >= SHN_LORESERVE)