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 | } | ... | ... |