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