Commit fe319756924992f836531957fd680065a0136296
1 parent
95f7652d
fixed __op_label handling if RELA relocations are used
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@206 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
99 additions
and
61 deletions
dyngen.c
| @@ -95,6 +95,12 @@ typedef uint64_t host_ulong; | @@ -95,6 +95,12 @@ typedef uint64_t host_ulong; | ||
| 95 | #define swabls(x) swab64s(x) | 95 | #define swabls(x) swab64s(x) |
| 96 | #endif | 96 | #endif |
| 97 | 97 | ||
| 98 | +#ifdef ELF_USES_RELOCA | ||
| 99 | +#define SHT_RELOC SHT_RELA | ||
| 100 | +#else | ||
| 101 | +#define SHT_RELOC SHT_REL | ||
| 102 | +#endif | ||
| 103 | + | ||
| 98 | #include "thunk.h" | 104 | #include "thunk.h" |
| 99 | 105 | ||
| 100 | /* all dynamically generated functions begin with this code */ | 106 | /* all dynamically generated functions begin with this code */ |
| @@ -170,16 +176,24 @@ void elf_swap_phdr(struct elf_phdr *h) | @@ -170,16 +176,24 @@ void elf_swap_phdr(struct elf_phdr *h) | ||
| 170 | swabls(&h->p_align); /* Segment alignment */ | 176 | swabls(&h->p_align); /* Segment alignment */ |
| 171 | } | 177 | } |
| 172 | 178 | ||
| 179 | +void elf_swap_rel(ELF_RELOC *rel) | ||
| 180 | +{ | ||
| 181 | + swabls(&rel->r_offset); | ||
| 182 | + swabls(&rel->r_info); | ||
| 183 | +#ifdef ELF_USES_RELOCA | ||
| 184 | + swabls(&rel->r_addend); | ||
| 185 | +#endif | ||
| 186 | +} | ||
| 187 | + | ||
| 173 | /* ELF file info */ | 188 | /* ELF file info */ |
| 174 | int do_swap; | 189 | int do_swap; |
| 175 | struct elf_shdr *shdr; | 190 | struct elf_shdr *shdr; |
| 191 | +uint8_t **sdata; | ||
| 176 | struct elfhdr ehdr; | 192 | struct elfhdr ehdr; |
| 177 | ElfW(Sym) *symtab; | 193 | ElfW(Sym) *symtab; |
| 178 | int nb_syms; | 194 | int nb_syms; |
| 179 | char *strtab; | 195 | char *strtab; |
| 180 | -/* data section */ | ||
| 181 | -uint8_t *data_data, *sdata_data; | ||
| 182 | -int data_shndx, sdata_shndx; | 196 | +int text_shndx; |
| 183 | 197 | ||
| 184 | uint16_t get16(uint16_t *p) | 198 | uint16_t get16(uint16_t *p) |
| 185 | { | 199 | { |
| @@ -243,6 +257,19 @@ struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char * | @@ -243,6 +257,19 @@ struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char * | ||
| 243 | return NULL; | 257 | return NULL; |
| 244 | } | 258 | } |
| 245 | 259 | ||
| 260 | +int find_reloc(int sh_index) | ||
| 261 | +{ | ||
| 262 | + struct elf_shdr *sec; | ||
| 263 | + int i; | ||
| 264 | + | ||
| 265 | + for(i = 0; i < ehdr.e_shnum; i++) { | ||
| 266 | + sec = &shdr[i]; | ||
| 267 | + if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) | ||
| 268 | + return i; | ||
| 269 | + } | ||
| 270 | + return 0; | ||
| 271 | +} | ||
| 272 | + | ||
| 246 | void *load_data(int fd, long offset, unsigned int size) | 273 | void *load_data(int fd, long offset, unsigned int size) |
| 247 | { | 274 | { |
| 248 | char *data; | 275 | char *data; |
| @@ -278,7 +305,7 @@ int strstart(const char *str, const char *val, const char **ptr) | @@ -278,7 +305,7 @@ int strstart(const char *str, const char *val, const char **ptr) | ||
| 278 | 305 | ||
| 279 | /* generate op code */ | 306 | /* generate op code */ |
| 280 | void gen_code(const char *name, host_ulong offset, host_ulong size, | 307 | void gen_code(const char *name, host_ulong offset, host_ulong size, |
| 281 | - FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int reloc_sh_type, | 308 | + FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, |
| 282 | int gen_switch) | 309 | int gen_switch) |
| 283 | { | 310 | { |
| 284 | int copy_size = 0; | 311 | int copy_size = 0; |
| @@ -500,16 +527,39 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, | @@ -500,16 +527,39 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, | ||
| 500 | sym_name = strtab + sym->st_name; | 527 | sym_name = strtab + sym->st_name; |
| 501 | if (strstart(sym_name, "__op_label", &p)) { | 528 | if (strstart(sym_name, "__op_label", &p)) { |
| 502 | uint8_t *ptr; | 529 | uint8_t *ptr; |
| 503 | - | 530 | + int addend; |
| 531 | + unsigned long offset; | ||
| 532 | + | ||
| 504 | /* test if the variable refers to a label inside | 533 | /* test if the variable refers to a label inside |
| 505 | the code we are generating */ | 534 | the code we are generating */ |
| 506 | - if (sym->st_shndx == data_shndx) | ||
| 507 | - ptr = data_data; | ||
| 508 | - else if (sym->st_shndx == sdata_shndx) | ||
| 509 | - ptr = sdata_data; | ||
| 510 | - else | ||
| 511 | - error("__op_labelN symbols must be in .data or .sdata section"); | ||
| 512 | - val = *(target_ulong *)(ptr + sym->st_value); | 535 | + ptr = sdata[sym->st_shndx]; |
| 536 | + if (!ptr) | ||
| 537 | + error("__op_labelN in invalid section"); | ||
| 538 | + offset = sym->st_value; | ||
| 539 | + addend = 0; | ||
| 540 | +#ifdef ELF_USES_RELOCA | ||
| 541 | + { | ||
| 542 | + int reloc_shndx, nb_relocs1, j; | ||
| 543 | + | ||
| 544 | + /* try to find a matching relocation */ | ||
| 545 | + reloc_shndx = find_reloc(sym->st_shndx); | ||
| 546 | + if (reloc_shndx) { | ||
| 547 | + nb_relocs1 = shdr[reloc_shndx].sh_size / | ||
| 548 | + shdr[reloc_shndx].sh_entsize; | ||
| 549 | + rel = (ELF_RELOC *)sdata[reloc_shndx]; | ||
| 550 | + for(j = 0; j < nb_relocs1; j++) { | ||
| 551 | + if (rel->r_offset == offset) { | ||
| 552 | + addend = rel->r_addend; | ||
| 553 | + break; | ||
| 554 | + } | ||
| 555 | + rel++; | ||
| 556 | + } | ||
| 557 | + } | ||
| 558 | + } | ||
| 559 | +#endif | ||
| 560 | + val = *(target_ulong *)(ptr + offset); | ||
| 561 | + val += addend; | ||
| 562 | + | ||
| 513 | if (val >= start_offset && val < start_offset + copy_size) { | 563 | if (val >= start_offset && val < start_offset + copy_size) { |
| 514 | n = strtol(p, NULL, 10); | 564 | n = strtol(p, NULL, 10); |
| 515 | fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset); | 565 | fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset); |
| @@ -886,8 +936,9 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) | @@ -886,8 +936,9 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) | ||
| 886 | ElfW(Sym) *sym; | 936 | ElfW(Sym) *sym; |
| 887 | char *shstr; | 937 | char *shstr; |
| 888 | uint8_t *text; | 938 | uint8_t *text; |
| 889 | - void *relocs; | ||
| 890 | - int nb_relocs, reloc_sh_type; | 939 | + ELF_RELOC *relocs; |
| 940 | + int nb_relocs; | ||
| 941 | + ELF_RELOC *rel; | ||
| 891 | 942 | ||
| 892 | fd = open(filename, O_RDONLY); | 943 | fd = open(filename, O_RDONLY); |
| 893 | if (fd < 0) | 944 | if (fd < 0) |
| @@ -926,58 +977,45 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) | @@ -926,58 +977,45 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) | ||
| 926 | } | 977 | } |
| 927 | } | 978 | } |
| 928 | 979 | ||
| 980 | + /* read all section data */ | ||
| 981 | + sdata = malloc(sizeof(void *) * ehdr.e_shnum); | ||
| 982 | + memset(sdata, 0, sizeof(void *) * ehdr.e_shnum); | ||
| 983 | + | ||
| 984 | + for(i = 0;i < ehdr.e_shnum; i++) { | ||
| 985 | + sec = &shdr[i]; | ||
| 986 | + if (sec->sh_type != SHT_NOBITS) | ||
| 987 | + sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size); | ||
| 988 | + } | ||
| 989 | + | ||
| 929 | sec = &shdr[ehdr.e_shstrndx]; | 990 | sec = &shdr[ehdr.e_shstrndx]; |
| 930 | - shstr = load_data(fd, sec->sh_offset, sec->sh_size); | 991 | + shstr = sdata[ehdr.e_shstrndx]; |
| 931 | 992 | ||
| 993 | + /* swap relocations */ | ||
| 994 | + for(i = 0; i < ehdr.e_shnum; i++) { | ||
| 995 | + sec = &shdr[i]; | ||
| 996 | + if (sec->sh_type == SHT_RELOC) { | ||
| 997 | + nb_relocs = sec->sh_size / sec->sh_entsize; | ||
| 998 | + if (do_swap) { | ||
| 999 | + for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++) | ||
| 1000 | + elf_swap_rel(rel); | ||
| 1001 | + } | ||
| 1002 | + } | ||
| 1003 | + } | ||
| 932 | /* text section */ | 1004 | /* text section */ |
| 933 | 1005 | ||
| 934 | text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text"); | 1006 | text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text"); |
| 935 | if (!text_sec) | 1007 | if (!text_sec) |
| 936 | error("could not find .text section"); | 1008 | error("could not find .text section"); |
| 937 | - text = load_data(fd, text_sec->sh_offset, text_sec->sh_size); | 1009 | + text_shndx = text_sec - shdr; |
| 1010 | + text = sdata[text_shndx]; | ||
| 938 | 1011 | ||
| 939 | - data_shndx = -1; | ||
| 940 | - sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".data"); | ||
| 941 | - if (sec) { | ||
| 942 | - data_shndx = sec - shdr; | ||
| 943 | - data_data = load_data(fd, sec->sh_offset, sec->sh_size); | ||
| 944 | - } | ||
| 945 | - sdata_shndx = -1; | ||
| 946 | - sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".sdata"); | ||
| 947 | - if (sec) { | ||
| 948 | - sdata_shndx = sec - shdr; | ||
| 949 | - sdata_data = load_data(fd, sec->sh_offset, sec->sh_size); | ||
| 950 | - } | ||
| 951 | - | ||
| 952 | /* find text relocations, if any */ | 1012 | /* find text relocations, if any */ |
| 953 | - nb_relocs = 0; | ||
| 954 | relocs = NULL; | 1013 | relocs = NULL; |
| 955 | - reloc_sh_type = 0; | ||
| 956 | - for(i = 0; i < ehdr.e_shnum; i++) { | ||
| 957 | - sec = &shdr[i]; | ||
| 958 | - if ((sec->sh_type == SHT_REL || sec->sh_type == SHT_RELA) && | ||
| 959 | - sec->sh_info == (text_sec - shdr)) { | ||
| 960 | - reloc_sh_type = sec->sh_type; | ||
| 961 | - relocs = load_data(fd, sec->sh_offset, sec->sh_size); | ||
| 962 | - nb_relocs = sec->sh_size / sec->sh_entsize; | ||
| 963 | - if (do_swap) { | ||
| 964 | - if (sec->sh_type == SHT_REL) { | ||
| 965 | - ElfW(Rel) *rel = relocs; | ||
| 966 | - for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { | ||
| 967 | - swabls(&rel->r_offset); | ||
| 968 | - swabls(&rel->r_info); | ||
| 969 | - } | ||
| 970 | - } else { | ||
| 971 | - ElfW(Rela) *rel = relocs; | ||
| 972 | - for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { | ||
| 973 | - swabls(&rel->r_offset); | ||
| 974 | - swabls(&rel->r_info); | ||
| 975 | - swabls(&rel->r_addend); | ||
| 976 | - } | ||
| 977 | - } | ||
| 978 | - } | ||
| 979 | - break; | ||
| 980 | - } | 1014 | + nb_relocs = 0; |
| 1015 | + i = find_reloc(text_shndx); | ||
| 1016 | + if (i != 0) { | ||
| 1017 | + relocs = (ELF_RELOC *)sdata[i]; | ||
| 1018 | + nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize; | ||
| 981 | } | 1019 | } |
| 982 | 1020 | ||
| 983 | symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab"); | 1021 | symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab"); |
| @@ -985,8 +1023,8 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) | @@ -985,8 +1023,8 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) | ||
| 985 | error("could not find .symtab section"); | 1023 | error("could not find .symtab section"); |
| 986 | strtab_sec = &shdr[symtab_sec->sh_link]; | 1024 | strtab_sec = &shdr[symtab_sec->sh_link]; |
| 987 | 1025 | ||
| 988 | - symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size); | ||
| 989 | - strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size); | 1026 | + symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr]; |
| 1027 | + strtab = sdata[symtab_sec->sh_link]; | ||
| 990 | 1028 | ||
| 991 | nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym)); | 1029 | nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym)); |
| 992 | if (do_swap) { | 1030 | if (do_swap) { |
| @@ -1005,7 +1043,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) | @@ -1005,7 +1043,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) | ||
| 1005 | name = strtab + sym->st_name; | 1043 | name = strtab + sym->st_name; |
| 1006 | if (strstart(name, OP_PREFIX, &p)) { | 1044 | if (strstart(name, OP_PREFIX, &p)) { |
| 1007 | gen_code(name, sym->st_value, sym->st_size, outfile, | 1045 | gen_code(name, sym->st_value, sym->st_size, outfile, |
| 1008 | - text, relocs, nb_relocs, reloc_sh_type, 2); | 1046 | + text, relocs, nb_relocs, 2); |
| 1009 | } | 1047 | } |
| 1010 | } | 1048 | } |
| 1011 | } else { | 1049 | } else { |
| @@ -1071,7 +1109,7 @@ fprintf(outfile, | @@ -1071,7 +1109,7 @@ fprintf(outfile, | ||
| 1071 | if (sym->st_shndx != (text_sec - shdr)) | 1109 | if (sym->st_shndx != (text_sec - shdr)) |
| 1072 | error("invalid section for opcode (0x%x)", sym->st_shndx); | 1110 | error("invalid section for opcode (0x%x)", sym->st_shndx); |
| 1073 | gen_code(name, sym->st_value, sym->st_size, outfile, | 1111 | gen_code(name, sym->st_value, sym->st_size, outfile, |
| 1074 | - text, relocs, nb_relocs, reloc_sh_type, 1); | 1112 | + text, relocs, nb_relocs, 1); |
| 1075 | } | 1113 | } |
| 1076 | } | 1114 | } |
| 1077 | 1115 | ||
| @@ -1126,7 +1164,7 @@ fprintf(outfile, | @@ -1126,7 +1164,7 @@ fprintf(outfile, | ||
| 1126 | if (sym->st_shndx != (text_sec - shdr)) | 1164 | if (sym->st_shndx != (text_sec - shdr)) |
| 1127 | error("invalid section for opcode (0x%x)", sym->st_shndx); | 1165 | error("invalid section for opcode (0x%x)", sym->st_shndx); |
| 1128 | gen_code(name, sym->st_value, sym->st_size, outfile, | 1166 | gen_code(name, sym->st_value, sym->st_size, outfile, |
| 1129 | - text, relocs, nb_relocs, reloc_sh_type, 0); | 1167 | + text, relocs, nb_relocs, 0); |
| 1130 | } | 1168 | } |
| 1131 | } | 1169 | } |
| 1132 | } | 1170 | } |