diff options
| -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) |
