diff options
Diffstat (limited to 'scripts/mod/modpost.c')
-rw-r--r-- | scripts/mod/modpost.c | 169 |
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 | **/ |
656 | static int secref_whitelist(const char *modname, const char *tosec, | 650 | static 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 | ||
901 | static 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 | |||
920 | static 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 | |||
939 | static 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) |