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 | 95 | #define swabls(x) swab64s(x) |
| 96 | 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 | 104 | #include "thunk.h" |
| 99 | 105 | |
| 100 | 106 | /* all dynamically generated functions begin with this code */ |
| ... | ... | @@ -170,16 +176,24 @@ void elf_swap_phdr(struct elf_phdr *h) |
| 170 | 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 | 188 | /* ELF file info */ |
| 174 | 189 | int do_swap; |
| 175 | 190 | struct elf_shdr *shdr; |
| 191 | +uint8_t **sdata; | |
| 176 | 192 | struct elfhdr ehdr; |
| 177 | 193 | ElfW(Sym) *symtab; |
| 178 | 194 | int nb_syms; |
| 179 | 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 | 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 | 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 | 273 | void *load_data(int fd, long offset, unsigned int size) |
| 247 | 274 | { |
| 248 | 275 | char *data; |
| ... | ... | @@ -278,7 +305,7 @@ int strstart(const char *str, const char *val, const char **ptr) |
| 278 | 305 | |
| 279 | 306 | /* generate op code */ |
| 280 | 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 | 309 | int gen_switch) |
| 283 | 310 | { |
| 284 | 311 | int copy_size = 0; |
| ... | ... | @@ -500,16 +527,39 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, |
| 500 | 527 | sym_name = strtab + sym->st_name; |
| 501 | 528 | if (strstart(sym_name, "__op_label", &p)) { |
| 502 | 529 | uint8_t *ptr; |
| 503 | - | |
| 530 | + int addend; | |
| 531 | + unsigned long offset; | |
| 532 | + | |
| 504 | 533 | /* test if the variable refers to a label inside |
| 505 | 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 | 563 | if (val >= start_offset && val < start_offset + copy_size) { |
| 514 | 564 | n = strtol(p, NULL, 10); |
| 515 | 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 | 936 | ElfW(Sym) *sym; |
| 887 | 937 | char *shstr; |
| 888 | 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 | 943 | fd = open(filename, O_RDONLY); |
| 893 | 944 | if (fd < 0) |
| ... | ... | @@ -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 | 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 | 1004 | /* text section */ |
| 933 | 1005 | |
| 934 | 1006 | text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text"); |
| 935 | 1007 | if (!text_sec) |
| 936 | 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 | 1012 | /* find text relocations, if any */ |
| 953 | - nb_relocs = 0; | |
| 954 | 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 | 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 | 1023 | error("could not find .symtab section"); |
| 986 | 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 | 1029 | nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym)); |
| 992 | 1030 | if (do_swap) { |
| ... | ... | @@ -1005,7 +1043,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) |
| 1005 | 1043 | name = strtab + sym->st_name; |
| 1006 | 1044 | if (strstart(name, OP_PREFIX, &p)) { |
| 1007 | 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 | 1049 | } else { |
| ... | ... | @@ -1071,7 +1109,7 @@ fprintf(outfile, |
| 1071 | 1109 | if (sym->st_shndx != (text_sec - shdr)) |
| 1072 | 1110 | error("invalid section for opcode (0x%x)", sym->st_shndx); |
| 1073 | 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 | 1164 | if (sym->st_shndx != (text_sec - shdr)) |
| 1127 | 1165 | error("invalid section for opcode (0x%x)", sym->st_shndx); |
| 1128 | 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 | } | ... | ... |