diff options
Diffstat (limited to 'scripts/mod/modpost.c')
-rw-r--r-- | scripts/mod/modpost.c | 242 |
1 files changed, 137 insertions, 105 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 902ee55f327f..e4630135979c 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
@@ -937,19 +937,19 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec, | |||
937 | } | 937 | } |
938 | 938 | ||
939 | static unsigned int *reloc_location(struct elf_info *elf, | 939 | static unsigned int *reloc_location(struct elf_info *elf, |
940 | int rsection, Elf_Rela *r) | 940 | Elf_Shdr *sechdr, Elf_Rela *r) |
941 | { | 941 | { |
942 | Elf_Shdr *sechdrs = elf->sechdrs; | 942 | Elf_Shdr *sechdrs = elf->sechdrs; |
943 | int section = sechdrs[rsection].sh_info; | 943 | int section = sechdr->sh_info; |
944 | 944 | ||
945 | return (void *)elf->hdr + sechdrs[section].sh_offset + | 945 | return (void *)elf->hdr + sechdrs[section].sh_offset + |
946 | (r->r_offset - sechdrs[section].sh_addr); | 946 | (r->r_offset - sechdrs[section].sh_addr); |
947 | } | 947 | } |
948 | 948 | ||
949 | static int addend_386_rel(struct elf_info *elf, int rsection, Elf_Rela *r) | 949 | static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) |
950 | { | 950 | { |
951 | unsigned int r_typ = ELF_R_TYPE(r->r_info); | 951 | unsigned int r_typ = ELF_R_TYPE(r->r_info); |
952 | unsigned int *location = reloc_location(elf, rsection, r); | 952 | unsigned int *location = reloc_location(elf, sechdr, r); |
953 | 953 | ||
954 | switch (r_typ) { | 954 | switch (r_typ) { |
955 | case R_386_32: | 955 | case R_386_32: |
@@ -965,7 +965,7 @@ static int addend_386_rel(struct elf_info *elf, int rsection, Elf_Rela *r) | |||
965 | return 0; | 965 | return 0; |
966 | } | 966 | } |
967 | 967 | ||
968 | static int addend_arm_rel(struct elf_info *elf, int rsection, Elf_Rela *r) | 968 | static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) |
969 | { | 969 | { |
970 | unsigned int r_typ = ELF_R_TYPE(r->r_info); | 970 | unsigned int r_typ = ELF_R_TYPE(r->r_info); |
971 | 971 | ||
@@ -978,8 +978,8 @@ static int addend_arm_rel(struct elf_info *elf, int rsection, Elf_Rela *r) | |||
978 | case R_ARM_PC24: | 978 | case R_ARM_PC24: |
979 | /* From ARM ABI: ((S + A) | T) - P */ | 979 | /* From ARM ABI: ((S + A) | T) - P */ |
980 | r->r_addend = (int)(long)(elf->hdr + | 980 | r->r_addend = (int)(long)(elf->hdr + |
981 | elf->sechdrs[rsection].sh_offset + | 981 | sechdr->sh_offset + |
982 | (r->r_offset - elf->sechdrs[rsection].sh_addr)); | 982 | (r->r_offset - sechdr->sh_addr)); |
983 | break; | 983 | break; |
984 | default: | 984 | default: |
985 | return 1; | 985 | return 1; |
@@ -987,10 +987,10 @@ static int addend_arm_rel(struct elf_info *elf, int rsection, Elf_Rela *r) | |||
987 | return 0; | 987 | return 0; |
988 | } | 988 | } |
989 | 989 | ||
990 | static int addend_mips_rel(struct elf_info *elf, int rsection, Elf_Rela *r) | 990 | static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) |
991 | { | 991 | { |
992 | unsigned int r_typ = ELF_R_TYPE(r->r_info); | 992 | unsigned int r_typ = ELF_R_TYPE(r->r_info); |
993 | unsigned int *location = reloc_location(elf, rsection, r); | 993 | unsigned int *location = reloc_location(elf, sechdr, r); |
994 | unsigned int inst; | 994 | unsigned int inst; |
995 | 995 | ||
996 | if (r_typ == R_MIPS_HI16) | 996 | if (r_typ == R_MIPS_HI16) |
@@ -1010,6 +1010,128 @@ static int addend_mips_rel(struct elf_info *elf, int rsection, Elf_Rela *r) | |||
1010 | return 0; | 1010 | return 0; |
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | static void section_rela(const char *modname, struct elf_info *elf, | ||
1014 | Elf_Shdr *sechdr, int section(const char *), | ||
1015 | int section_ref_ok(const char *)) | ||
1016 | { | ||
1017 | Elf_Sym *sym; | ||
1018 | Elf_Rela *rela; | ||
1019 | Elf_Rela r; | ||
1020 | unsigned int r_sym; | ||
1021 | const char *fromsec; | ||
1022 | const char * tosec; | ||
1023 | |||
1024 | Elf_Ehdr *hdr = elf->hdr; | ||
1025 | Elf_Rela *start = (void *)hdr + sechdr->sh_offset; | ||
1026 | Elf_Rela *stop = (void *)start + sechdr->sh_size; | ||
1027 | |||
1028 | const char *secstrings = (void *)hdr + | ||
1029 | elf->sechdrs[hdr->e_shstrndx].sh_offset; | ||
1030 | |||
1031 | fromsec = secstrings + sechdr->sh_name; | ||
1032 | fromsec += strlen(".rela"); | ||
1033 | /* if from section (name) is know good then skip it */ | ||
1034 | if (section_ref_ok(fromsec)) | ||
1035 | return; | ||
1036 | |||
1037 | for (rela = start; rela < stop; rela++) { | ||
1038 | r.r_offset = TO_NATIVE(rela->r_offset); | ||
1039 | #if KERNEL_ELFCLASS == ELFCLASS64 | ||
1040 | if (hdr->e_machine == EM_MIPS) { | ||
1041 | unsigned int r_typ; | ||
1042 | r_sym = ELF64_MIPS_R_SYM(rela->r_info); | ||
1043 | r_sym = TO_NATIVE(r_sym); | ||
1044 | r_typ = ELF64_MIPS_R_TYPE(rela->r_info); | ||
1045 | r.r_info = ELF64_R_INFO(r_sym, r_typ); | ||
1046 | } else { | ||
1047 | r.r_info = TO_NATIVE(rela->r_info); | ||
1048 | r_sym = ELF_R_SYM(r.r_info); | ||
1049 | } | ||
1050 | #else | ||
1051 | r.r_info = TO_NATIVE(rela->r_info); | ||
1052 | r_sym = ELF_R_SYM(r.r_info); | ||
1053 | #endif | ||
1054 | r.r_addend = TO_NATIVE(rela->r_addend); | ||
1055 | sym = elf->symtab_start + r_sym; | ||
1056 | /* Skip special sections */ | ||
1057 | if (sym->st_shndx >= SHN_LORESERVE) | ||
1058 | continue; | ||
1059 | |||
1060 | tosec = secstrings + | ||
1061 | elf->sechdrs[sym->st_shndx].sh_name; | ||
1062 | if (section(tosec)) | ||
1063 | warn_sec_mismatch(modname, fromsec, elf, sym, r); | ||
1064 | } | ||
1065 | } | ||
1066 | |||
1067 | static void section_rel(const char *modname, struct elf_info *elf, | ||
1068 | Elf_Shdr *sechdr, int section(const char *), | ||
1069 | int section_ref_ok(const char *)) | ||
1070 | { | ||
1071 | Elf_Sym *sym; | ||
1072 | Elf_Rel *rel; | ||
1073 | Elf_Rela r; | ||
1074 | unsigned int r_sym; | ||
1075 | const char *fromsec; | ||
1076 | const char * tosec; | ||
1077 | |||
1078 | Elf_Ehdr *hdr = elf->hdr; | ||
1079 | Elf_Rel *start = (void *)hdr + sechdr->sh_offset; | ||
1080 | Elf_Rel *stop = (void *)start + sechdr->sh_size; | ||
1081 | |||
1082 | const char *secstrings = (void *)hdr + | ||
1083 | elf->sechdrs[hdr->e_shstrndx].sh_offset; | ||
1084 | |||
1085 | fromsec = secstrings + sechdr->sh_name; | ||
1086 | fromsec += strlen(".rel"); | ||
1087 | /* if from section (name) is know good then skip it */ | ||
1088 | if (section_ref_ok(fromsec)) | ||
1089 | return; | ||
1090 | |||
1091 | for (rel = start; rel < stop; rel++) { | ||
1092 | r.r_offset = TO_NATIVE(rel->r_offset); | ||
1093 | #if KERNEL_ELFCLASS == ELFCLASS64 | ||
1094 | if (hdr->e_machine == EM_MIPS) { | ||
1095 | unsigned int r_typ; | ||
1096 | r_sym = ELF64_MIPS_R_SYM(rel->r_info); | ||
1097 | r_sym = TO_NATIVE(r_sym); | ||
1098 | r_typ = ELF64_MIPS_R_TYPE(rel->r_info); | ||
1099 | r.r_info = ELF64_R_INFO(r_sym, r_typ); | ||
1100 | } else { | ||
1101 | r.r_info = TO_NATIVE(rel->r_info); | ||
1102 | r_sym = ELF_R_SYM(r.r_info); | ||
1103 | } | ||
1104 | #else | ||
1105 | r.r_info = TO_NATIVE(rel->r_info); | ||
1106 | r_sym = ELF_R_SYM(r.r_info); | ||
1107 | #endif | ||
1108 | r.r_addend = 0; | ||
1109 | switch (hdr->e_machine) { | ||
1110 | case EM_386: | ||
1111 | if (addend_386_rel(elf, sechdr, &r)) | ||
1112 | continue; | ||
1113 | break; | ||
1114 | case EM_ARM: | ||
1115 | if (addend_arm_rel(elf, sechdr, &r)) | ||
1116 | continue; | ||
1117 | break; | ||
1118 | case EM_MIPS: | ||
1119 | if (addend_mips_rel(elf, sechdr, &r)) | ||
1120 | continue; | ||
1121 | break; | ||
1122 | } | ||
1123 | sym = elf->symtab_start + r_sym; | ||
1124 | /* Skip special sections */ | ||
1125 | if (sym->st_shndx >= SHN_LORESERVE) | ||
1126 | continue; | ||
1127 | |||
1128 | tosec = secstrings + | ||
1129 | elf->sechdrs[sym->st_shndx].sh_name; | ||
1130 | if (section(tosec)) | ||
1131 | warn_sec_mismatch(modname, fromsec, elf, sym, r); | ||
1132 | } | ||
1133 | } | ||
1134 | |||
1013 | /** | 1135 | /** |
1014 | * A module includes a number of sections that are discarded | 1136 | * A module includes a number of sections that are discarded |
1015 | * either when loaded or when used as built-in. | 1137 | * either when loaded or when used as built-in. |
@@ -1028,108 +1150,18 @@ static void check_sec_ref(struct module *mod, const char *modname, | |||
1028 | int section_ref_ok(const char *)) | 1150 | int section_ref_ok(const char *)) |
1029 | { | 1151 | { |
1030 | int i; | 1152 | int i; |
1031 | Elf_Sym *sym; | ||
1032 | Elf_Ehdr *hdr = elf->hdr; | 1153 | Elf_Ehdr *hdr = elf->hdr; |
1033 | Elf_Shdr *sechdrs = elf->sechdrs; | 1154 | Elf_Shdr *sechdrs = elf->sechdrs; |
1034 | const char *secstrings = (void *)hdr + | ||
1035 | sechdrs[hdr->e_shstrndx].sh_offset; | ||
1036 | 1155 | ||
1037 | /* Walk through all sections */ | 1156 | /* Walk through all sections */ |
1038 | for (i = 0; i < hdr->e_shnum; i++) { | 1157 | for (i = 0; i < hdr->e_shnum; i++) { |
1039 | const char *name = secstrings + sechdrs[i].sh_name; | ||
1040 | const char *secname; | ||
1041 | Elf_Rela r; | ||
1042 | unsigned int r_sym; | ||
1043 | /* We want to process only relocation sections and not .init */ | 1158 | /* We want to process only relocation sections and not .init */ |
1044 | if (sechdrs[i].sh_type == SHT_RELA) { | 1159 | if (sechdrs[i].sh_type == SHT_RELA) |
1045 | Elf_Rela *rela; | 1160 | section_rela(modname, elf, &elf->sechdrs[i], |
1046 | Elf_Rela *start = (void *)hdr + sechdrs[i].sh_offset; | 1161 | section, section_ref_ok); |
1047 | Elf_Rela *stop = (void *)start + sechdrs[i].sh_size; | 1162 | else if (sechdrs[i].sh_type == SHT_REL) |
1048 | name += strlen(".rela"); | 1163 | section_rel(modname, elf, &elf->sechdrs[i], |
1049 | if (section_ref_ok(name)) | 1164 | section, section_ref_ok); |
1050 | continue; | ||
1051 | |||
1052 | for (rela = start; rela < stop; rela++) { | ||
1053 | r.r_offset = TO_NATIVE(rela->r_offset); | ||
1054 | #if KERNEL_ELFCLASS == ELFCLASS64 | ||
1055 | if (hdr->e_machine == EM_MIPS) { | ||
1056 | unsigned int r_typ; | ||
1057 | r_sym = ELF64_MIPS_R_SYM(rela->r_info); | ||
1058 | r_sym = TO_NATIVE(r_sym); | ||
1059 | r_typ = ELF64_MIPS_R_TYPE(rela->r_info); | ||
1060 | r.r_info = ELF64_R_INFO(r_sym, r_typ); | ||
1061 | } else { | ||
1062 | r.r_info = TO_NATIVE(rela->r_info); | ||
1063 | r_sym = ELF_R_SYM(r.r_info); | ||
1064 | } | ||
1065 | #else | ||
1066 | r.r_info = TO_NATIVE(rela->r_info); | ||
1067 | r_sym = ELF_R_SYM(r.r_info); | ||
1068 | #endif | ||
1069 | r.r_addend = TO_NATIVE(rela->r_addend); | ||
1070 | sym = elf->symtab_start + r_sym; | ||
1071 | /* Skip special sections */ | ||
1072 | if (sym->st_shndx >= SHN_LORESERVE) | ||
1073 | continue; | ||
1074 | |||
1075 | secname = secstrings + | ||
1076 | sechdrs[sym->st_shndx].sh_name; | ||
1077 | if (section(secname)) | ||
1078 | warn_sec_mismatch(modname, name, | ||
1079 | elf, sym, r); | ||
1080 | } | ||
1081 | } else if (sechdrs[i].sh_type == SHT_REL) { | ||
1082 | Elf_Rel *rel; | ||
1083 | Elf_Rel *start = (void *)hdr + sechdrs[i].sh_offset; | ||
1084 | Elf_Rel *stop = (void *)start + sechdrs[i].sh_size; | ||
1085 | name += strlen(".rel"); | ||
1086 | if (section_ref_ok(name)) | ||
1087 | continue; | ||
1088 | |||
1089 | for (rel = start; rel < stop; rel++) { | ||
1090 | r.r_offset = TO_NATIVE(rel->r_offset); | ||
1091 | #if KERNEL_ELFCLASS == ELFCLASS64 | ||
1092 | if (hdr->e_machine == EM_MIPS) { | ||
1093 | unsigned int r_typ; | ||
1094 | r_sym = ELF64_MIPS_R_SYM(rel->r_info); | ||
1095 | r_sym = TO_NATIVE(r_sym); | ||
1096 | r_typ = ELF64_MIPS_R_TYPE(rel->r_info); | ||
1097 | r.r_info = ELF64_R_INFO(r_sym, r_typ); | ||
1098 | } else { | ||
1099 | r.r_info = TO_NATIVE(rel->r_info); | ||
1100 | r_sym = ELF_R_SYM(r.r_info); | ||
1101 | } | ||
1102 | #else | ||
1103 | r.r_info = TO_NATIVE(rel->r_info); | ||
1104 | r_sym = ELF_R_SYM(r.r_info); | ||
1105 | #endif | ||
1106 | r.r_addend = 0; | ||
1107 | switch (hdr->e_machine) { | ||
1108 | case EM_386: | ||
1109 | if (addend_386_rel(elf, i, &r)) | ||
1110 | continue; | ||
1111 | break; | ||
1112 | case EM_ARM: | ||
1113 | if (addend_arm_rel(elf, i, &r)) | ||
1114 | continue; | ||
1115 | break; | ||
1116 | case EM_MIPS: | ||
1117 | if (addend_mips_rel(elf, i, &r)) | ||
1118 | continue; | ||
1119 | break; | ||
1120 | } | ||
1121 | sym = elf->symtab_start + r_sym; | ||
1122 | /* Skip special sections */ | ||
1123 | if (sym->st_shndx >= SHN_LORESERVE) | ||
1124 | continue; | ||
1125 | |||
1126 | secname = secstrings + | ||
1127 | sechdrs[sym->st_shndx].sh_name; | ||
1128 | if (section(secname)) | ||
1129 | warn_sec_mismatch(modname, name, | ||
1130 | elf, sym, r); | ||
1131 | } | ||
1132 | } | ||
1133 | } | 1165 | } |
1134 | } | 1166 | } |
1135 | 1167 | ||