diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/mod/modpost.c | 73 | ||||
-rw-r--r-- | scripts/mod/modpost.h | 3 |
2 files changed, 76 insertions, 0 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 3645e980da71..b83cddb8dca9 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
@@ -374,6 +374,7 @@ static int parse_elf(struct elf_info *info, const char *filename) | |||
374 | hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); | 374 | hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); |
375 | hdr->e_shnum = TO_NATIVE(hdr->e_shnum); | 375 | hdr->e_shnum = TO_NATIVE(hdr->e_shnum); |
376 | hdr->e_machine = TO_NATIVE(hdr->e_machine); | 376 | hdr->e_machine = TO_NATIVE(hdr->e_machine); |
377 | hdr->e_type = TO_NATIVE(hdr->e_type); | ||
377 | sechdrs = (void *)hdr + hdr->e_shoff; | 378 | sechdrs = (void *)hdr + hdr->e_shoff; |
378 | info->sechdrs = sechdrs; | 379 | info->sechdrs = sechdrs; |
379 | 380 | ||
@@ -384,6 +385,8 @@ static int parse_elf(struct elf_info *info, const char *filename) | |||
384 | sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); | 385 | sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); |
385 | sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); | 386 | sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); |
386 | sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); | 387 | sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); |
388 | sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info); | ||
389 | sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr); | ||
387 | } | 390 | } |
388 | /* Find symbol table. */ | 391 | /* Find symbol table. */ |
389 | for (i = 1; i < hdr->e_shnum; i++) { | 392 | for (i = 1; i < hdr->e_shnum; i++) { |
@@ -753,6 +756,8 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr, | |||
753 | for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { | 756 | for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { |
754 | if (sym->st_shndx != relsym->st_shndx) | 757 | if (sym->st_shndx != relsym->st_shndx) |
755 | continue; | 758 | continue; |
759 | if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) | ||
760 | continue; | ||
756 | if (sym->st_value == addr) | 761 | if (sym->st_value == addr) |
757 | return sym; | 762 | return sym; |
758 | } | 763 | } |
@@ -895,6 +900,58 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec, | |||
895 | } | 900 | } |
896 | } | 901 | } |
897 | 902 | ||
903 | static unsigned int *reloc_location(struct elf_info *elf, | ||
904 | int rsection, Elf_Rela *r) | ||
905 | { | ||
906 | Elf_Shdr *sechdrs = elf->sechdrs; | ||
907 | int section = sechdrs[rsection].sh_info; | ||
908 | |||
909 | return (void *)elf->hdr + sechdrs[section].sh_offset + | ||
910 | (r->r_offset - sechdrs[section].sh_addr); | ||
911 | } | ||
912 | |||
913 | static int addend_386_rel(struct elf_info *elf, int rsection, Elf_Rela *r) | ||
914 | { | ||
915 | unsigned int r_typ = ELF_R_TYPE(r->r_info); | ||
916 | unsigned int *location = reloc_location(elf, rsection, r); | ||
917 | |||
918 | switch (r_typ) { | ||
919 | case R_386_32: | ||
920 | r->r_addend = TO_NATIVE(*location); | ||
921 | break; | ||
922 | case R_386_PC32: | ||
923 | r->r_addend = TO_NATIVE(*location) + 4; | ||
924 | /* For CONFIG_RELOCATABLE=y */ | ||
925 | if (elf->hdr->e_type == ET_EXEC) | ||
926 | r->r_addend += r->r_offset; | ||
927 | break; | ||
928 | } | ||
929 | return 0; | ||
930 | } | ||
931 | |||
932 | static int addend_mips_rel(struct elf_info *elf, int rsection, Elf_Rela *r) | ||
933 | { | ||
934 | unsigned int r_typ = ELF_R_TYPE(r->r_info); | ||
935 | unsigned int *location = reloc_location(elf, rsection, r); | ||
936 | unsigned int inst; | ||
937 | |||
938 | if (r_typ == R_MIPS_HI16) | ||
939 | return 1; /* skip this */ | ||
940 | inst = TO_NATIVE(*location); | ||
941 | switch (r_typ) { | ||
942 | case R_MIPS_LO16: | ||
943 | r->r_addend = inst & 0xffff; | ||
944 | break; | ||
945 | case R_MIPS_26: | ||
946 | r->r_addend = (inst & 0x03ffffff) << 2; | ||
947 | break; | ||
948 | case R_MIPS_32: | ||
949 | r->r_addend = inst; | ||
950 | break; | ||
951 | } | ||
952 | return 0; | ||
953 | } | ||
954 | |||
898 | /** | 955 | /** |
899 | * A module includes a number of sections that are discarded | 956 | * A module includes a number of sections that are discarded |
900 | * either when loaded or when used as built-in. | 957 | * either when loaded or when used as built-in. |
@@ -938,8 +995,11 @@ static void check_sec_ref(struct module *mod, const char *modname, | |||
938 | r.r_offset = TO_NATIVE(rela->r_offset); | 995 | r.r_offset = TO_NATIVE(rela->r_offset); |
939 | #if KERNEL_ELFCLASS == ELFCLASS64 | 996 | #if KERNEL_ELFCLASS == ELFCLASS64 |
940 | if (hdr->e_machine == EM_MIPS) { | 997 | if (hdr->e_machine == EM_MIPS) { |
998 | unsigned int r_typ; | ||
941 | r_sym = ELF64_MIPS_R_SYM(rela->r_info); | 999 | r_sym = ELF64_MIPS_R_SYM(rela->r_info); |
942 | r_sym = TO_NATIVE(r_sym); | 1000 | r_sym = TO_NATIVE(r_sym); |
1001 | r_typ = ELF64_MIPS_R_TYPE(rela->r_info); | ||
1002 | r.r_info = ELF64_R_INFO(r_sym, r_typ); | ||
943 | } else { | 1003 | } else { |
944 | r.r_info = TO_NATIVE(rela->r_info); | 1004 | r.r_info = TO_NATIVE(rela->r_info); |
945 | r_sym = ELF_R_SYM(r.r_info); | 1005 | r_sym = ELF_R_SYM(r.r_info); |
@@ -972,8 +1032,11 @@ static void check_sec_ref(struct module *mod, const char *modname, | |||
972 | r.r_offset = TO_NATIVE(rel->r_offset); | 1032 | r.r_offset = TO_NATIVE(rel->r_offset); |
973 | #if KERNEL_ELFCLASS == ELFCLASS64 | 1033 | #if KERNEL_ELFCLASS == ELFCLASS64 |
974 | if (hdr->e_machine == EM_MIPS) { | 1034 | if (hdr->e_machine == EM_MIPS) { |
1035 | unsigned int r_typ; | ||
975 | r_sym = ELF64_MIPS_R_SYM(rel->r_info); | 1036 | r_sym = ELF64_MIPS_R_SYM(rel->r_info); |
976 | r_sym = TO_NATIVE(r_sym); | 1037 | r_sym = TO_NATIVE(r_sym); |
1038 | r_typ = ELF64_MIPS_R_TYPE(rel->r_info); | ||
1039 | r.r_info = ELF64_R_INFO(r_sym, r_typ); | ||
977 | } else { | 1040 | } else { |
978 | r.r_info = TO_NATIVE(rel->r_info); | 1041 | r.r_info = TO_NATIVE(rel->r_info); |
979 | r_sym = ELF_R_SYM(r.r_info); | 1042 | r_sym = ELF_R_SYM(r.r_info); |
@@ -983,6 +1046,16 @@ static void check_sec_ref(struct module *mod, const char *modname, | |||
983 | r_sym = ELF_R_SYM(r.r_info); | 1046 | r_sym = ELF_R_SYM(r.r_info); |
984 | #endif | 1047 | #endif |
985 | r.r_addend = 0; | 1048 | r.r_addend = 0; |
1049 | switch (hdr->e_machine) { | ||
1050 | case EM_386: | ||
1051 | if (addend_386_rel(elf, i, &r)) | ||
1052 | continue; | ||
1053 | break; | ||
1054 | case EM_MIPS: | ||
1055 | if (addend_mips_rel(elf, i, &r)) | ||
1056 | continue; | ||
1057 | break; | ||
1058 | } | ||
986 | sym = elf->symtab_start + r_sym; | 1059 | sym = elf->symtab_start + r_sym; |
987 | /* Skip special sections */ | 1060 | /* Skip special sections */ |
988 | if (sym->st_shndx >= SHN_LORESERVE) | 1061 | if (sym->st_shndx >= SHN_LORESERVE) |
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 0858caa9c03f..4156dd34c5de 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h | |||
@@ -60,6 +60,9 @@ typedef union | |||
60 | #define ELF64_MIPS_R_SYM(i) \ | 60 | #define ELF64_MIPS_R_SYM(i) \ |
61 | ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym) | 61 | ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym) |
62 | 62 | ||
63 | #define ELF64_MIPS_R_TYPE(i) \ | ||
64 | ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_type1) | ||
65 | |||
63 | #if KERNEL_ELFDATA != HOST_ELFDATA | 66 | #if KERNEL_ELFDATA != HOST_ELFDATA |
64 | 67 | ||
65 | static inline void __endian(const void *src, void *dest, unsigned int size) | 68 | static inline void __endian(const void *src, void *dest, unsigned int size) |