Commit fe319756924992f836531957fd680065a0136296

Authored by bellard
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 }
... ...