]> git.proxmox.com Git - mirror_qemu.git/blob - dyngen.c
win32 port (initial patch by kazu)
[mirror_qemu.git] / dyngen.c
1 /*
2 * Generic Dynamic compiler generator
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * The COFF object format support was extracted from Kazu's QEMU port
7 * to Win32.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <inttypes.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30
31 #include "config-host.h"
32
33 #if defined(_WIN32)
34 #define CONFIG_FORMAT_COFF
35 #else
36 #define CONFIG_FORMAT_ELF
37 #endif
38
39 #ifdef CONFIG_FORMAT_ELF
40
41 /* elf format definitions. We use these macros to test the CPU to
42 allow cross compilation (this tool must be ran on the build
43 platform) */
44 #if defined(HOST_I386)
45
46 #define ELF_CLASS ELFCLASS32
47 #define ELF_ARCH EM_386
48 #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
49 #undef ELF_USES_RELOCA
50
51 #elif defined(HOST_AMD64)
52
53 #define ELF_CLASS ELFCLASS64
54 #define ELF_ARCH EM_X86_64
55 #define elf_check_arch(x) ((x) == EM_X86_64)
56 #define ELF_USES_RELOCA
57
58 #elif defined(HOST_PPC)
59
60 #define ELF_CLASS ELFCLASS32
61 #define ELF_ARCH EM_PPC
62 #define elf_check_arch(x) ((x) == EM_PPC)
63 #define ELF_USES_RELOCA
64
65 #elif defined(HOST_S390)
66
67 #define ELF_CLASS ELFCLASS32
68 #define ELF_ARCH EM_S390
69 #define elf_check_arch(x) ((x) == EM_S390)
70 #define ELF_USES_RELOCA
71
72 #elif defined(HOST_ALPHA)
73
74 #define ELF_CLASS ELFCLASS64
75 #define ELF_ARCH EM_ALPHA
76 #define elf_check_arch(x) ((x) == EM_ALPHA)
77 #define ELF_USES_RELOCA
78
79 #elif defined(HOST_IA64)
80
81 #define ELF_CLASS ELFCLASS64
82 #define ELF_ARCH EM_IA_64
83 #define elf_check_arch(x) ((x) == EM_IA_64)
84 #define ELF_USES_RELOCA
85
86 #elif defined(HOST_SPARC)
87
88 #define ELF_CLASS ELFCLASS32
89 #define ELF_ARCH EM_SPARC
90 #define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS)
91 #define ELF_USES_RELOCA
92
93 #elif defined(HOST_SPARC64)
94
95 #define ELF_CLASS ELFCLASS64
96 #define ELF_ARCH EM_SPARCV9
97 #define elf_check_arch(x) ((x) == EM_SPARCV9)
98 #define ELF_USES_RELOCA
99
100 #elif defined(HOST_ARM)
101
102 #define ELF_CLASS ELFCLASS32
103 #define ELF_ARCH EM_ARM
104 #define elf_check_arch(x) ((x) == EM_ARM)
105 #define ELF_USES_RELOC
106
107 #elif defined(HOST_M68K)
108
109 #define ELF_CLASS ELFCLASS32
110 #define ELF_ARCH EM_68K
111 #define elf_check_arch(x) ((x) == EM_68K)
112 #define ELF_USES_RELOCA
113
114 #else
115 #error unsupported CPU - please update the code
116 #endif
117
118 #include "elf.h"
119
120 #if ELF_CLASS == ELFCLASS32
121 typedef int32_t host_long;
122 typedef uint32_t host_ulong;
123 #define swabls(x) swab32s(x)
124 #else
125 typedef int64_t host_long;
126 typedef uint64_t host_ulong;
127 #define swabls(x) swab64s(x)
128 #endif
129
130 #ifdef ELF_USES_RELOCA
131 #define SHT_RELOC SHT_RELA
132 #else
133 #define SHT_RELOC SHT_REL
134 #endif
135
136 #define EXE_RELOC ELF_RELOC
137 #define EXE_SYM ElfW(Sym)
138
139 #endif /* CONFIG_FORMAT_ELF */
140
141 #ifdef CONFIG_FORMAT_COFF
142
143 #include "a.out.h"
144
145 typedef int32_t host_long;
146 typedef uint32_t host_ulong;
147
148 #define FILENAMELEN 256
149
150 typedef struct coff_sym {
151 struct external_syment *st_syment;
152 char st_name[FILENAMELEN];
153 uint32_t st_value;
154 int st_size;
155 uint8_t st_type;
156 uint8_t st_shndx;
157 } coff_Sym;
158
159 typedef struct coff_rel {
160 struct external_reloc *r_reloc;
161 int r_offset;
162 uint8_t r_type;
163 } coff_Rel;
164
165 #define EXE_RELOC struct coff_rel
166 #define EXE_SYM struct coff_sym
167
168 #endif /* CONFIG_FORMAT_COFF */
169
170 #include "bswap.h"
171
172 enum {
173 OUT_GEN_OP,
174 OUT_CODE,
175 OUT_INDEX_OP,
176 };
177
178 /* all dynamically generated functions begin with this code */
179 #define OP_PREFIX "op_"
180
181 int do_swap;
182
183 void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
184 {
185 va_list ap;
186 va_start(ap, fmt);
187 fprintf(stderr, "dyngen: ");
188 vfprintf(stderr, fmt, ap);
189 fprintf(stderr, "\n");
190 va_end(ap);
191 exit(1);
192 }
193
194 void *load_data(int fd, long offset, unsigned int size)
195 {
196 char *data;
197
198 data = malloc(size);
199 if (!data)
200 return NULL;
201 lseek(fd, offset, SEEK_SET);
202 if (read(fd, data, size) != size) {
203 free(data);
204 return NULL;
205 }
206 return data;
207 }
208
209 int strstart(const char *str, const char *val, const char **ptr)
210 {
211 const char *p, *q;
212 p = str;
213 q = val;
214 while (*q != '\0') {
215 if (*p != *q)
216 return 0;
217 p++;
218 q++;
219 }
220 if (ptr)
221 *ptr = p;
222 return 1;
223 }
224
225 void pstrcpy(char *buf, int buf_size, const char *str)
226 {
227 int c;
228 char *q = buf;
229
230 if (buf_size <= 0)
231 return;
232
233 for(;;) {
234 c = *str++;
235 if (c == 0 || q >= buf + buf_size - 1)
236 break;
237 *q++ = c;
238 }
239 *q = '\0';
240 }
241
242 void swab16s(uint16_t *p)
243 {
244 *p = bswap16(*p);
245 }
246
247 void swab32s(uint32_t *p)
248 {
249 *p = bswap32(*p);
250 }
251
252 void swab64s(uint64_t *p)
253 {
254 *p = bswap64(*p);
255 }
256
257 uint16_t get16(uint16_t *p)
258 {
259 uint16_t val;
260 val = *p;
261 if (do_swap)
262 val = bswap16(val);
263 return val;
264 }
265
266 uint32_t get32(uint32_t *p)
267 {
268 uint32_t val;
269 val = *p;
270 if (do_swap)
271 val = bswap32(val);
272 return val;
273 }
274
275 void put16(uint16_t *p, uint16_t val)
276 {
277 if (do_swap)
278 val = bswap16(val);
279 *p = val;
280 }
281
282 void put32(uint32_t *p, uint32_t val)
283 {
284 if (do_swap)
285 val = bswap32(val);
286 *p = val;
287 }
288
289 /* executable information */
290 EXE_SYM *symtab;
291 int nb_syms;
292 int text_shndx;
293 uint8_t *text;
294 EXE_RELOC *relocs;
295 int nb_relocs;
296
297 #ifdef CONFIG_FORMAT_ELF
298
299 /* ELF file info */
300 struct elf_shdr *shdr;
301 uint8_t **sdata;
302 struct elfhdr ehdr;
303 char *strtab;
304
305 int elf_must_swap(struct elfhdr *h)
306 {
307 union {
308 uint32_t i;
309 uint8_t b[4];
310 } swaptest;
311
312 swaptest.i = 1;
313 return (h->e_ident[EI_DATA] == ELFDATA2MSB) !=
314 (swaptest.b[0] == 0);
315 }
316
317 void elf_swap_ehdr(struct elfhdr *h)
318 {
319 swab16s(&h->e_type); /* Object file type */
320 swab16s(&h-> e_machine); /* Architecture */
321 swab32s(&h-> e_version); /* Object file version */
322 swabls(&h-> e_entry); /* Entry point virtual address */
323 swabls(&h-> e_phoff); /* Program header table file offset */
324 swabls(&h-> e_shoff); /* Section header table file offset */
325 swab32s(&h-> e_flags); /* Processor-specific flags */
326 swab16s(&h-> e_ehsize); /* ELF header size in bytes */
327 swab16s(&h-> e_phentsize); /* Program header table entry size */
328 swab16s(&h-> e_phnum); /* Program header table entry count */
329 swab16s(&h-> e_shentsize); /* Section header table entry size */
330 swab16s(&h-> e_shnum); /* Section header table entry count */
331 swab16s(&h-> e_shstrndx); /* Section header string table index */
332 }
333
334 void elf_swap_shdr(struct elf_shdr *h)
335 {
336 swab32s(&h-> sh_name); /* Section name (string tbl index) */
337 swab32s(&h-> sh_type); /* Section type */
338 swabls(&h-> sh_flags); /* Section flags */
339 swabls(&h-> sh_addr); /* Section virtual addr at execution */
340 swabls(&h-> sh_offset); /* Section file offset */
341 swabls(&h-> sh_size); /* Section size in bytes */
342 swab32s(&h-> sh_link); /* Link to another section */
343 swab32s(&h-> sh_info); /* Additional section information */
344 swabls(&h-> sh_addralign); /* Section alignment */
345 swabls(&h-> sh_entsize); /* Entry size if section holds table */
346 }
347
348 void elf_swap_phdr(struct elf_phdr *h)
349 {
350 swab32s(&h->p_type); /* Segment type */
351 swabls(&h->p_offset); /* Segment file offset */
352 swabls(&h->p_vaddr); /* Segment virtual address */
353 swabls(&h->p_paddr); /* Segment physical address */
354 swabls(&h->p_filesz); /* Segment size in file */
355 swabls(&h->p_memsz); /* Segment size in memory */
356 swab32s(&h->p_flags); /* Segment flags */
357 swabls(&h->p_align); /* Segment alignment */
358 }
359
360 void elf_swap_rel(ELF_RELOC *rel)
361 {
362 swabls(&rel->r_offset);
363 swabls(&rel->r_info);
364 #ifdef ELF_USES_RELOCA
365 swabls(&rel->r_addend);
366 #endif
367 }
368
369 struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr,
370 const char *name)
371 {
372 int i;
373 const char *shname;
374 struct elf_shdr *sec;
375
376 for(i = 0; i < shnum; i++) {
377 sec = &shdr[i];
378 if (!sec->sh_name)
379 continue;
380 shname = shstr + sec->sh_name;
381 if (!strcmp(shname, name))
382 return sec;
383 }
384 return NULL;
385 }
386
387 int find_reloc(int sh_index)
388 {
389 struct elf_shdr *sec;
390 int i;
391
392 for(i = 0; i < ehdr.e_shnum; i++) {
393 sec = &shdr[i];
394 if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index)
395 return i;
396 }
397 return 0;
398 }
399
400 static char *get_rel_sym_name(EXE_RELOC *rel)
401 {
402 return strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
403 }
404
405 static char *get_sym_name(EXE_SYM *sym)
406 {
407 return strtab + sym->st_name;
408 }
409
410 /* load an elf object file */
411 int load_object(const char *filename)
412 {
413 int fd;
414 struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec;
415 int i, j;
416 ElfW(Sym) *sym;
417 char *shstr;
418 ELF_RELOC *rel;
419
420 fd = open(filename, O_RDONLY);
421 if (fd < 0)
422 error("can't open file '%s'", filename);
423
424 /* Read ELF header. */
425 if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
426 error("unable to read file header");
427
428 /* Check ELF identification. */
429 if (ehdr.e_ident[EI_MAG0] != ELFMAG0
430 || ehdr.e_ident[EI_MAG1] != ELFMAG1
431 || ehdr.e_ident[EI_MAG2] != ELFMAG2
432 || ehdr.e_ident[EI_MAG3] != ELFMAG3
433 || ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
434 error("bad ELF header");
435 }
436
437 do_swap = elf_must_swap(&ehdr);
438 if (do_swap)
439 elf_swap_ehdr(&ehdr);
440 if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
441 error("Unsupported ELF class");
442 if (ehdr.e_type != ET_REL)
443 error("ELF object file expected");
444 if (ehdr.e_version != EV_CURRENT)
445 error("Invalid ELF version");
446 if (!elf_check_arch(ehdr.e_machine))
447 error("Unsupported CPU (e_machine=%d)", ehdr.e_machine);
448
449 /* read section headers */
450 shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(struct elf_shdr));
451 if (do_swap) {
452 for(i = 0; i < ehdr.e_shnum; i++) {
453 elf_swap_shdr(&shdr[i]);
454 }
455 }
456
457 /* read all section data */
458 sdata = malloc(sizeof(void *) * ehdr.e_shnum);
459 memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
460
461 for(i = 0;i < ehdr.e_shnum; i++) {
462 sec = &shdr[i];
463 if (sec->sh_type != SHT_NOBITS)
464 sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size);
465 }
466
467 sec = &shdr[ehdr.e_shstrndx];
468 shstr = sdata[ehdr.e_shstrndx];
469
470 /* swap relocations */
471 for(i = 0; i < ehdr.e_shnum; i++) {
472 sec = &shdr[i];
473 if (sec->sh_type == SHT_RELOC) {
474 nb_relocs = sec->sh_size / sec->sh_entsize;
475 if (do_swap) {
476 for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++)
477 elf_swap_rel(rel);
478 }
479 }
480 }
481 /* text section */
482
483 text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
484 if (!text_sec)
485 error("could not find .text section");
486 text_shndx = text_sec - shdr;
487 text = sdata[text_shndx];
488
489 /* find text relocations, if any */
490 relocs = NULL;
491 nb_relocs = 0;
492 i = find_reloc(text_shndx);
493 if (i != 0) {
494 relocs = (ELF_RELOC *)sdata[i];
495 nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize;
496 }
497
498 symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
499 if (!symtab_sec)
500 error("could not find .symtab section");
501 strtab_sec = &shdr[symtab_sec->sh_link];
502
503 symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
504 strtab = sdata[symtab_sec->sh_link];
505
506 nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
507 if (do_swap) {
508 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
509 swab32s(&sym->st_name);
510 swabls(&sym->st_value);
511 swabls(&sym->st_size);
512 swab16s(&sym->st_shndx);
513 }
514 }
515 close(fd);
516 return 0;
517 }
518
519 #endif /* CONFIG_FORMAT_ELF */
520
521 #ifdef CONFIG_FORMAT_COFF
522
523 /* COFF file info */
524 struct external_scnhdr *shdr;
525 uint8_t **sdata;
526 struct external_filehdr fhdr;
527 struct external_syment *coff_symtab;
528 char *strtab;
529 int coff_text_shndx, coff_data_shndx;
530
531 int data_shndx;
532
533 #define STRTAB_SIZE 4
534
535 #define DIR32 0x06
536 #define DISP32 0x14
537
538 #define T_FUNCTION 0x20
539 #define C_EXTERNAL 2
540
541 void sym_ent_name(struct external_syment *ext_sym, EXE_SYM *sym)
542 {
543 char *q;
544 int c, i, len;
545
546 if (ext_sym->e.e.e_zeroes != 0) {
547 q = sym->st_name;
548 for(i = 0; i < 8; i++) {
549 c = ext_sym->e.e_name[i];
550 if (c == '\0')
551 break;
552 *q++ = c;
553 }
554 *q = '\0';
555 } else {
556 pstrcpy(sym->st_name, sizeof(sym->st_name), strtab + ext_sym->e.e.e_offset);
557 }
558
559 /* now convert the name to a C name (suppress the leading '_') */
560 if (sym->st_name[0] == '_') {
561 len = strlen(sym->st_name);
562 memmove(sym->st_name, sym->st_name + 1, len - 1);
563 sym->st_name[len - 1] = '\0';
564 }
565 }
566
567 char *name_for_dotdata(struct coff_rel *rel)
568 {
569 int i;
570 struct coff_sym *sym;
571 uint32_t text_data;
572
573 text_data = *(uint32_t *)(text + rel->r_offset);
574
575 for (i = 0, sym = symtab; i < nb_syms; i++, sym++) {
576 if (sym->st_syment->e_scnum == data_shndx &&
577 text_data >= sym->st_value &&
578 text_data < sym->st_value + sym->st_size) {
579
580 return sym->st_name;
581
582 }
583 }
584 return NULL;
585 }
586
587 static char *get_sym_name(EXE_SYM *sym)
588 {
589 return sym->st_name;
590 }
591
592 static char *get_rel_sym_name(EXE_RELOC *rel)
593 {
594 char *name;
595 name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
596 if (!strcmp(name, ".data"))
597 name = name_for_dotdata(rel);
598 return name;
599 }
600
601 struct external_scnhdr *find_coff_section(struct external_scnhdr *shdr, int shnum, const char *name)
602 {
603 int i;
604 const char *shname;
605 struct external_scnhdr *sec;
606
607 for(i = 0; i < shnum; i++) {
608 sec = &shdr[i];
609 if (!sec->s_name)
610 continue;
611 shname = sec->s_name;
612 if (!strcmp(shname, name))
613 return sec;
614 }
615 return NULL;
616 }
617
618 /* load a coff object file */
619 int load_object(const char *filename)
620 {
621 int fd;
622 struct external_scnhdr *sec, *text_sec, *data_sec;
623 int i;
624 struct external_syment *ext_sym;
625 struct external_reloc *coff_relocs;
626 struct external_reloc *ext_rel;
627 uint32_t *n_strtab;
628 EXE_SYM *sym;
629 EXE_RELOC *rel;
630
631 fd = open(filename, O_RDONLY
632 #ifdef _WIN32
633 | O_BINARY
634 #endif
635 );
636 if (fd < 0)
637 error("can't open file '%s'", filename);
638
639 /* Read COFF header. */
640 if (read(fd, &fhdr, sizeof (fhdr)) != sizeof (fhdr))
641 error("unable to read file header");
642
643 /* Check COFF identification. */
644 if (fhdr.f_magic != I386MAGIC) {
645 error("bad COFF header");
646 }
647 do_swap = 0;
648
649 /* read section headers */
650 shdr = load_data(fd, sizeof(struct external_filehdr) + fhdr.f_opthdr, fhdr.f_nscns * sizeof(struct external_scnhdr));
651
652 /* read all section data */
653 sdata = malloc(sizeof(void *) * fhdr.f_nscns);
654 memset(sdata, 0, sizeof(void *) * fhdr.f_nscns);
655
656 const char *p;
657 for(i = 0;i < fhdr.f_nscns; i++) {
658 sec = &shdr[i];
659 if (!strstart(sec->s_name, ".bss", &p))
660 sdata[i] = load_data(fd, sec->s_scnptr, sec->s_size);
661 }
662
663
664 /* text section */
665 text_sec = find_coff_section(shdr, fhdr.f_nscns, ".text");
666 if (!text_sec)
667 error("could not find .text section");
668 coff_text_shndx = text_sec - shdr;
669 text = sdata[coff_text_shndx];
670
671 /* data section */
672 data_sec = find_coff_section(shdr, fhdr.f_nscns, ".data");
673 if (!data_sec)
674 error("could not find .data section");
675 coff_data_shndx = data_sec - shdr;
676
677 coff_symtab = load_data(fd, fhdr.f_symptr, fhdr.f_nsyms*SYMESZ);
678 for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
679 for(i=0;i<8;i++)
680 printf(" %02x", ((uint8_t *)ext_sym->e.e_name)[i]);
681 printf("\n");
682 }
683
684
685 n_strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), STRTAB_SIZE);
686 strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab);
687
688 nb_syms = fhdr.f_nsyms;
689
690 for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
691 if (strstart(ext_sym->e.e_name, ".text", NULL))
692 text_shndx = ext_sym->e_scnum;
693 if (strstart(ext_sym->e.e_name, ".data", NULL))
694 data_shndx = ext_sym->e_scnum;
695 }
696
697 /* set coff symbol */
698 symtab = malloc(sizeof(struct coff_sym) * nb_syms);
699
700 int aux_size, j;
701 for (i = 0, ext_sym = coff_symtab, sym = symtab; i < nb_syms; i++, ext_sym++, sym++) {
702 memset(sym, 0, sizeof(*sym));
703 sym->st_syment = ext_sym;
704 sym_ent_name(ext_sym, sym);
705 sym->st_value = ext_sym->e_value;
706
707 aux_size = *(int8_t *)ext_sym->e_numaux;
708 if (ext_sym->e_scnum == text_shndx && ext_sym->e_type == T_FUNCTION) {
709 for (j = aux_size + 1; j < nb_syms - i; j++) {
710 if ((ext_sym + j)->e_scnum == text_shndx &&
711 (ext_sym + j)->e_type == T_FUNCTION ){
712 sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
713 break;
714 } else if (j == nb_syms - i - 1) {
715 sec = &shdr[coff_text_shndx];
716 sym->st_size = sec->s_size - ext_sym->e_value;
717 break;
718 }
719 }
720 } else if (ext_sym->e_scnum == data_shndx && *(uint8_t *)ext_sym->e_sclass == C_EXTERNAL) {
721 for (j = aux_size + 1; j < nb_syms - i; j++) {
722 if ((ext_sym + j)->e_scnum == data_shndx) {
723 sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
724 break;
725 } else if (j == nb_syms - i - 1) {
726 sec = &shdr[coff_data_shndx];
727 sym->st_size = sec->s_size - ext_sym->e_value;
728 break;
729 }
730 }
731 } else {
732 sym->st_size = 0;
733 }
734
735 sym->st_type = ext_sym->e_type;
736 sym->st_shndx = ext_sym->e_scnum;
737 }
738
739
740 /* find text relocations, if any */
741 sec = &shdr[coff_text_shndx];
742 coff_relocs = load_data(fd, sec->s_relptr, sec->s_nreloc*RELSZ);
743 nb_relocs = sec->s_nreloc;
744
745 /* set coff relocation */
746 relocs = malloc(sizeof(struct coff_rel) * nb_relocs);
747 for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs;
748 i++, ext_rel++, rel++) {
749 memset(rel, 0, sizeof(*rel));
750 rel->r_reloc = ext_rel;
751 rel->r_offset = *(uint32_t *)ext_rel->r_vaddr;
752 rel->r_type = *(uint16_t *)ext_rel->r_type;
753 }
754 return 0;
755 }
756
757 #endif /* CONFIG_FORMAT_COFF */
758
759 #ifdef HOST_ARM
760
761 int arm_emit_ldr_info(const char *name, unsigned long start_offset,
762 FILE *outfile, uint8_t *p_start, uint8_t *p_end,
763 ELF_RELOC *relocs, int nb_relocs)
764 {
765 uint8_t *p;
766 uint32_t insn;
767 int offset, min_offset, pc_offset, data_size;
768 uint8_t data_allocated[1024];
769 unsigned int data_index;
770
771 memset(data_allocated, 0, sizeof(data_allocated));
772
773 p = p_start;
774 min_offset = p_end - p_start;
775 while (p < p_start + min_offset) {
776 insn = get32((uint32_t *)p);
777 if ((insn & 0x0d5f0000) == 0x051f0000) {
778 /* ldr reg, [pc, #im] */
779 offset = insn & 0xfff;
780 if (!(insn & 0x00800000))
781 offset = -offset;
782 if ((offset & 3) !=0)
783 error("%s:%04x: ldr pc offset must be 32 bit aligned",
784 name, start_offset + p - p_start);
785 pc_offset = p - p_start + offset + 8;
786 if (pc_offset <= (p - p_start) ||
787 pc_offset >= (p_end - p_start))
788 error("%s:%04x: ldr pc offset must point inside the function code",
789 name, start_offset + p - p_start);
790 if (pc_offset < min_offset)
791 min_offset = pc_offset;
792 if (outfile) {
793 /* ldr position */
794 fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
795 p - p_start);
796 /* ldr data index */
797 data_index = ((p_end - p_start) - pc_offset - 4) >> 2;
798 fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n",
799 data_index);
800 fprintf(outfile, " arm_ldr_ptr++;\n");
801 if (data_index >= sizeof(data_allocated))
802 error("%s: too many data", name);
803 if (!data_allocated[data_index]) {
804 ELF_RELOC *rel;
805 int i, addend, type;
806 const char *sym_name, *p;
807 char relname[1024];
808
809 data_allocated[data_index] = 1;
810
811 /* data value */
812 addend = get32((uint32_t *)(p_start + pc_offset));
813 relname[0] = '\0';
814 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
815 if (rel->r_offset == (pc_offset + start_offset)) {
816 sym_name = get_rel_sym_name(rel);
817 /* the compiler leave some unnecessary references to the code */
818 if (strstart(sym_name, "__op_param", &p)) {
819 snprintf(relname, sizeof(relname), "param%s", p);
820 } else {
821 snprintf(relname, sizeof(relname), "(long)(&%s)", sym_name);
822 }
823 type = ELF32_R_TYPE(rel->r_info);
824 if (type != R_ARM_ABS32)
825 error("%s: unsupported data relocation", name);
826 break;
827 }
828 }
829 fprintf(outfile, " arm_data_ptr[%d] = 0x%x",
830 data_index, addend);
831 if (relname[0] != '\0')
832 fprintf(outfile, " + %s", relname);
833 fprintf(outfile, ";\n");
834 }
835 }
836 }
837 p += 4;
838 }
839 data_size = (p_end - p_start) - min_offset;
840 if (data_size > 0 && outfile) {
841 fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2);
842 }
843
844 /* the last instruction must be a mov pc, lr */
845 if (p == p_start)
846 goto arm_ret_error;
847 p -= 4;
848 insn = get32((uint32_t *)p);
849 if ((insn & 0xffff0000) != 0xe91b0000) {
850 arm_ret_error:
851 if (!outfile)
852 printf("%s: invalid epilog\n", name);
853 }
854 return p - p_start;
855 }
856 #endif
857
858
859 #define MAX_ARGS 3
860
861 /* generate op code */
862 void gen_code(const char *name, host_ulong offset, host_ulong size,
863 FILE *outfile, int gen_switch)
864 {
865 int copy_size = 0;
866 uint8_t *p_start, *p_end;
867 host_ulong start_offset;
868 int nb_args, i, n;
869 uint8_t args_present[MAX_ARGS];
870 const char *sym_name, *p;
871 EXE_RELOC *rel;
872
873 /* Compute exact size excluding prologue and epilogue instructions.
874 * Increment start_offset to skip epilogue instructions, then compute
875 * copy_size the indicate the size of the remaining instructions (in
876 * bytes).
877 */
878 p_start = text + offset;
879 p_end = p_start + size;
880 start_offset = offset;
881 #if defined(HOST_I386) || defined(HOST_AMD64)
882 #ifdef CONFIG_FORMAT_COFF
883 {
884 uint8_t *p;
885 p = p_end - 1;
886 if (p == p_start)
887 error("empty code for %s", name);
888 while (*p != 0xc3) {
889 p--;
890 if (p <= p_start)
891 error("ret or jmp expected at the end of %s", name);
892 }
893 copy_size = p - p_start;
894 }
895 #else
896 {
897 int len;
898 len = p_end - p_start;
899 if (len == 0)
900 error("empty code for %s", name);
901 if (p_end[-1] == 0xc3) {
902 len--;
903 } else {
904 error("ret or jmp expected at the end of %s", name);
905 }
906 copy_size = len;
907 }
908 #endif
909 #elif defined(HOST_PPC)
910 {
911 uint8_t *p;
912 p = (void *)(p_end - 4);
913 if (p == p_start)
914 error("empty code for %s", name);
915 if (get32((uint32_t *)p) != 0x4e800020)
916 error("blr expected at the end of %s", name);
917 copy_size = p - p_start;
918 }
919 #elif defined(HOST_S390)
920 {
921 uint8_t *p;
922 p = (void *)(p_end - 2);
923 if (p == p_start)
924 error("empty code for %s", name);
925 if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
926 error("br %%r14 expected at the end of %s", name);
927 copy_size = p - p_start;
928 }
929 #elif defined(HOST_ALPHA)
930 {
931 uint8_t *p;
932 p = p_end - 4;
933 #if 0
934 /* XXX: check why it occurs */
935 if (p == p_start)
936 error("empty code for %s", name);
937 #endif
938 if (get32((uint32_t *)p) != 0x6bfa8001)
939 error("ret expected at the end of %s", name);
940 copy_size = p - p_start;
941 }
942 #elif defined(HOST_IA64)
943 {
944 uint8_t *p;
945 p = (void *)(p_end - 4);
946 if (p == p_start)
947 error("empty code for %s", name);
948 /* br.ret.sptk.many b0;; */
949 /* 08 00 84 00 */
950 if (get32((uint32_t *)p) != 0x00840008)
951 error("br.ret.sptk.many b0;; expected at the end of %s", name);
952 copy_size = p - p_start;
953 }
954 #elif defined(HOST_SPARC)
955 {
956 uint32_t start_insn, end_insn1, end_insn2;
957 uint8_t *p;
958 p = (void *)(p_end - 8);
959 if (p <= p_start)
960 error("empty code for %s", name);
961 start_insn = get32((uint32_t *)(p_start + 0x0));
962 end_insn1 = get32((uint32_t *)(p + 0x0));
963 end_insn2 = get32((uint32_t *)(p + 0x4));
964 if ((start_insn & ~0x1fff) == 0x9de3a000) {
965 p_start += 0x4;
966 start_offset += 0x4;
967 if ((int)(start_insn | ~0x1fff) < -128)
968 error("Found bogus save at the start of %s", name);
969 if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
970 error("ret; restore; not found at end of %s", name);
971 } else {
972 error("No save at the beginning of %s", name);
973 }
974 #if 0
975 /* Skip a preceeding nop, if present. */
976 if (p > p_start) {
977 skip_insn = get32((uint32_t *)(p - 0x4));
978 if (skip_insn == 0x01000000)
979 p -= 4;
980 }
981 #endif
982 copy_size = p - p_start;
983 }
984 #elif defined(HOST_SPARC64)
985 {
986 uint32_t start_insn, end_insn1, end_insn2, skip_insn;
987 uint8_t *p;
988 p = (void *)(p_end - 8);
989 if (p <= p_start)
990 error("empty code for %s", name);
991 start_insn = get32((uint32_t *)(p_start + 0x0));
992 end_insn1 = get32((uint32_t *)(p + 0x0));
993 end_insn2 = get32((uint32_t *)(p + 0x4));
994 if ((start_insn & ~0x1fff) == 0x9de3a000) {
995 p_start += 0x4;
996 start_offset += 0x4;
997 if ((int)(start_insn | ~0x1fff) < -256)
998 error("Found bogus save at the start of %s", name);
999 if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
1000 error("ret; restore; not found at end of %s", name);
1001 } else {
1002 error("No save at the beginning of %s", name);
1003 }
1004
1005 /* Skip a preceeding nop, if present. */
1006 if (p > p_start) {
1007 skip_insn = get32((uint32_t *)(p - 0x4));
1008 if (skip_insn == 0x01000000)
1009 p -= 4;
1010 }
1011
1012 copy_size = p - p_start;
1013 }
1014 #elif defined(HOST_ARM)
1015 {
1016 if ((p_end - p_start) <= 16)
1017 error("%s: function too small", name);
1018 if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
1019 (get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 ||
1020 get32((uint32_t *)(p_start + 8)) != 0xe24cb004)
1021 error("%s: invalid prolog", name);
1022 p_start += 12;
1023 start_offset += 12;
1024 copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
1025 relocs, nb_relocs);
1026 }
1027 #elif defined(HOST_M68K)
1028 {
1029 uint8_t *p;
1030 p = (void *)(p_end - 2);
1031 if (p == p_start)
1032 error("empty code for %s", name);
1033 // remove NOP's, probably added for alignment
1034 while ((get16((uint16_t *)p) == 0x4e71) &&
1035 (p>p_start))
1036 p -= 2;
1037 if (get16((uint16_t *)p) != 0x4e75)
1038 error("rts expected at the end of %s", name);
1039 copy_size = p - p_start;
1040 }
1041 #else
1042 #error unsupported CPU
1043 #endif
1044
1045 /* compute the number of arguments by looking at the relocations */
1046 for(i = 0;i < MAX_ARGS; i++)
1047 args_present[i] = 0;
1048
1049 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1050 if (rel->r_offset >= start_offset &&
1051 rel->r_offset < start_offset + (p_end - p_start)) {
1052 sym_name = get_rel_sym_name(rel);
1053 if (strstart(sym_name, "__op_param", &p)) {
1054 n = strtoul(p, NULL, 10);
1055 if (n > MAX_ARGS)
1056 error("too many arguments in %s", name);
1057 args_present[n - 1] = 1;
1058 }
1059 }
1060 }
1061
1062 nb_args = 0;
1063 while (nb_args < MAX_ARGS && args_present[nb_args])
1064 nb_args++;
1065 for(i = nb_args; i < MAX_ARGS; i++) {
1066 if (args_present[i])
1067 error("inconsistent argument numbering in %s", name);
1068 }
1069
1070 if (gen_switch == 2) {
1071 fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
1072 } else if (gen_switch == 1) {
1073
1074 /* output C code */
1075 fprintf(outfile, "case INDEX_%s: {\n", name);
1076 if (nb_args > 0) {
1077 fprintf(outfile, " long ");
1078 for(i = 0; i < nb_args; i++) {
1079 if (i != 0)
1080 fprintf(outfile, ", ");
1081 fprintf(outfile, "param%d", i + 1);
1082 }
1083 fprintf(outfile, ";\n");
1084 }
1085 fprintf(outfile, " extern void %s();\n", name);
1086
1087 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1088 if (rel->r_offset >= start_offset &&
1089 rel->r_offset < start_offset + (p_end - p_start)) {
1090 sym_name = get_rel_sym_name(rel);
1091 if (*sym_name &&
1092 !strstart(sym_name, "__op_param", NULL) &&
1093 !strstart(sym_name, "__op_jmp", NULL)) {
1094 #if defined(HOST_SPARC)
1095 if (sym_name[0] == '.') {
1096 fprintf(outfile,
1097 "extern char __dot_%s __asm__(\"%s\");\n",
1098 sym_name+1, sym_name);
1099 continue;
1100 }
1101 #endif
1102 fprintf(outfile, "extern char %s;\n", sym_name);
1103 }
1104 }
1105 }
1106
1107 fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", name, start_offset - offset, copy_size);
1108
1109 /* emit code offset information */
1110 {
1111 EXE_SYM *sym;
1112 const char *sym_name, *p;
1113 unsigned long val;
1114 int n;
1115
1116 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
1117 sym_name = get_sym_name(sym);
1118 if (strstart(sym_name, "__op_label", &p)) {
1119 uint8_t *ptr;
1120 unsigned long offset;
1121
1122 /* test if the variable refers to a label inside
1123 the code we are generating */
1124 #ifdef CONFIG_FORMAT_COFF
1125 if (sym->st_shndx == text_shndx) {
1126 ptr = sdata[coff_text_shndx];
1127 } else if (sym->st_shndx == data_shndx) {
1128 ptr = sdata[coff_data_shndx];
1129 } else {
1130 ptr = NULL;
1131 }
1132 #else
1133 ptr = sdata[sym->st_shndx];
1134 #endif
1135 if (!ptr)
1136 error("__op_labelN in invalid section");
1137 offset = sym->st_value;
1138 val = *(unsigned long *)(ptr + offset);
1139 #ifdef ELF_USES_RELOCA
1140 {
1141 int reloc_shndx, nb_relocs1, j;
1142
1143 /* try to find a matching relocation */
1144 reloc_shndx = find_reloc(sym->st_shndx);
1145 if (reloc_shndx) {
1146 nb_relocs1 = shdr[reloc_shndx].sh_size /
1147 shdr[reloc_shndx].sh_entsize;
1148 rel = (ELF_RELOC *)sdata[reloc_shndx];
1149 for(j = 0; j < nb_relocs1; j++) {
1150 if (rel->r_offset == offset) {
1151 val = rel->r_addend;
1152 break;
1153 }
1154 rel++;
1155 }
1156 }
1157 }
1158 #endif
1159
1160 if (val >= start_offset && val < start_offset + copy_size) {
1161 n = strtol(p, NULL, 10);
1162 fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
1163 }
1164 }
1165 }
1166 }
1167
1168 /* load parameres in variables */
1169 for(i = 0; i < nb_args; i++) {
1170 fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1);
1171 }
1172
1173 /* patch relocations */
1174 #if defined(HOST_I386)
1175 {
1176 char name[256];
1177 int type;
1178 int addend;
1179 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1180 if (rel->r_offset >= start_offset &&
1181 rel->r_offset < start_offset + copy_size) {
1182 sym_name = get_rel_sym_name(rel);
1183 if (strstart(sym_name, "__op_jmp", &p)) {
1184 int n;
1185 n = strtol(p, NULL, 10);
1186 /* __op_jmp relocations are done at
1187 runtime to do translated block
1188 chaining: the offset of the instruction
1189 needs to be stored */
1190 fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
1191 n, rel->r_offset - start_offset);
1192 continue;
1193 }
1194
1195 if (strstart(sym_name, "__op_param", &p)) {
1196 snprintf(name, sizeof(name), "param%s", p);
1197 } else {
1198 snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
1199 }
1200 addend = get32((uint32_t *)(text + rel->r_offset));
1201 #ifdef CONFIG_FORMAT_ELF
1202 type = ELF32_R_TYPE(rel->r_info);
1203 switch(type) {
1204 case R_386_32:
1205 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
1206 rel->r_offset - start_offset, name, addend);
1207 break;
1208 case R_386_PC32:
1209 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
1210 rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
1211 break;
1212 default:
1213 error("unsupported i386 relocation (%d)", type);
1214 }
1215 #elif defined(CONFIG_FORMAT_COFF)
1216 type = rel->r_type;
1217 switch(type) {
1218 case DIR32:
1219 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
1220 rel->r_offset - start_offset, name, addend);
1221 break;
1222 case DISP32:
1223 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
1224 rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
1225 break;
1226 default:
1227 error("unsupported i386 relocation (%d)", type);
1228 }
1229 #else
1230 #error unsupport object format
1231 #endif
1232 }
1233 }
1234 }
1235 #elif defined(HOST_AMD64)
1236 {
1237 char name[256];
1238 int type;
1239 int addend;
1240 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1241 if (rel->r_offset >= start_offset &&
1242 rel->r_offset < start_offset + copy_size) {
1243 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1244 if (strstart(sym_name, "__op_param", &p)) {
1245 snprintf(name, sizeof(name), "param%s", p);
1246 } else {
1247 snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
1248 }
1249 type = ELF32_R_TYPE(rel->r_info);
1250 addend = rel->r_addend;
1251 switch(type) {
1252 case R_X86_64_32:
1253 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
1254 rel->r_offset - start_offset, name, addend);
1255 break;
1256 case R_X86_64_32S:
1257 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
1258 rel->r_offset - start_offset, name, addend);
1259 break;
1260 case R_X86_64_PC32:
1261 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
1262 rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
1263 break;
1264 default:
1265 error("unsupported AMD64 relocation (%d)", type);
1266 }
1267 }
1268 }
1269 }
1270 #elif defined(HOST_PPC)
1271 {
1272 char name[256];
1273 int type;
1274 int addend;
1275 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1276 if (rel->r_offset >= start_offset &&
1277 rel->r_offset < start_offset + copy_size) {
1278 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1279 if (strstart(sym_name, "__op_jmp", &p)) {
1280 int n;
1281 n = strtol(p, NULL, 10);
1282 /* __op_jmp relocations are done at
1283 runtime to do translated block
1284 chaining: the offset of the instruction
1285 needs to be stored */
1286 fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
1287 n, rel->r_offset - start_offset);
1288 continue;
1289 }
1290
1291 if (strstart(sym_name, "__op_param", &p)) {
1292 snprintf(name, sizeof(name), "param%s", p);
1293 } else {
1294 snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
1295 }
1296 type = ELF32_R_TYPE(rel->r_info);
1297 addend = rel->r_addend;
1298 switch(type) {
1299 case R_PPC_ADDR32:
1300 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
1301 rel->r_offset - start_offset, name, addend);
1302 break;
1303 case R_PPC_ADDR16_LO:
1304 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
1305 rel->r_offset - start_offset, name, addend);
1306 break;
1307 case R_PPC_ADDR16_HI:
1308 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
1309 rel->r_offset - start_offset, name, addend);
1310 break;
1311 case R_PPC_ADDR16_HA:
1312 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
1313 rel->r_offset - start_offset, name, addend);
1314 break;
1315 case R_PPC_REL24:
1316 /* warning: must be at 32 MB distancy */
1317 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
1318 rel->r_offset - start_offset, rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
1319 break;
1320 default:
1321 error("unsupported powerpc relocation (%d)", type);
1322 }
1323 }
1324 }
1325 }
1326 #elif defined(HOST_S390)
1327 {
1328 char name[256];
1329 int type;
1330 int addend;
1331 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1332 if (rel->r_offset >= start_offset &&
1333 rel->r_offset < start_offset + copy_size) {
1334 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1335 if (strstart(sym_name, "__op_param", &p)) {
1336 snprintf(name, sizeof(name), "param%s", p);
1337 } else {
1338 snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
1339 }
1340 type = ELF32_R_TYPE(rel->r_info);
1341 addend = rel->r_addend;
1342 switch(type) {
1343 case R_390_32:
1344 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
1345 rel->r_offset - start_offset, name, addend);
1346 break;
1347 case R_390_16:
1348 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
1349 rel->r_offset - start_offset, name, addend);
1350 break;
1351 case R_390_8:
1352 fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
1353 rel->r_offset - start_offset, name, addend);
1354 break;
1355 default:
1356 error("unsupported s390 relocation (%d)", type);
1357 }
1358 }
1359 }
1360 }
1361 #elif defined(HOST_ALPHA)
1362 {
1363 for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
1364 if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
1365 int type;
1366
1367 type = ELF64_R_TYPE(rel->r_info);
1368 sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
1369 switch (type) {
1370 case R_ALPHA_GPDISP:
1371 /* The gp is just 32 bit, and never changes, so it's easiest to emit it
1372 as an immediate instead of constructing it from the pv or ra. */
1373 fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, gp);\n",
1374 rel->r_offset - start_offset);
1375 fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n",
1376 rel->r_offset - start_offset + rel->r_addend);
1377 break;
1378 case R_ALPHA_LITUSE:
1379 /* jsr to literal hint. Could be used to optimize to bsr. Ignore for
1380 now, since some called functions (libc) need pv to be set up. */
1381 break;
1382 case R_ALPHA_HINT:
1383 /* Branch target prediction hint. Ignore for now. Should be already
1384 correct for in-function jumps. */
1385 break;
1386 case R_ALPHA_LITERAL:
1387 /* Load a literal from the GOT relative to the gp. Since there's only a
1388 single gp, nothing is to be done. */
1389 break;
1390 case R_ALPHA_GPRELHIGH:
1391 /* Handle fake relocations against __op_param symbol. Need to emit the
1392 high part of the immediate value instead. Other symbols need no
1393 special treatment. */
1394 if (strstart(sym_name, "__op_param", &p))
1395 fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, param%s);\n",
1396 rel->r_offset - start_offset, p);
1397 break;
1398 case R_ALPHA_GPRELLOW:
1399 if (strstart(sym_name, "__op_param", &p))
1400 fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, param%s);\n",
1401 rel->r_offset - start_offset, p);
1402 break;
1403 case R_ALPHA_BRSGP:
1404 /* PC-relative jump. Tweak offset to skip the two instructions that try to
1405 set up the gp from the pv. */
1406 fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
1407 rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset);
1408 break;
1409 default:
1410 error("unsupported Alpha relocation (%d)", type);
1411 }
1412 }
1413 }
1414 }
1415 #elif defined(HOST_IA64)
1416 {
1417 char name[256];
1418 int type;
1419 int addend;
1420 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1421 if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
1422 sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
1423 if (strstart(sym_name, "__op_param", &p)) {
1424 snprintf(name, sizeof(name), "param%s", p);
1425 } else {
1426 snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
1427 }
1428 type = ELF64_R_TYPE(rel->r_info);
1429 addend = rel->r_addend;
1430 switch(type) {
1431 case R_IA64_LTOFF22:
1432 error("must implemnt R_IA64_LTOFF22 relocation");
1433 case R_IA64_PCREL21B:
1434 error("must implemnt R_IA64_PCREL21B relocation");
1435 default:
1436 error("unsupported ia64 relocation (%d)", type);
1437 }
1438 }
1439 }
1440 }
1441 #elif defined(HOST_SPARC)
1442 {
1443 char name[256];
1444 int type;
1445 int addend;
1446 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1447 if (rel->r_offset >= start_offset &&
1448 rel->r_offset < start_offset + copy_size) {
1449 sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
1450 if (strstart(sym_name, "__op_param", &p)) {
1451 snprintf(name, sizeof(name), "param%s", p);
1452 } else {
1453 if (sym_name[0] == '.')
1454 snprintf(name, sizeof(name),
1455 "(long)(&__dot_%s)",
1456 sym_name + 1);
1457 else
1458 snprintf(name, sizeof(name),
1459 "(long)(&%s)", sym_name);
1460 }
1461 type = ELF32_R_TYPE(rel->r_info);
1462 addend = rel->r_addend;
1463 switch(type) {
1464 case R_SPARC_32:
1465 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
1466 rel->r_offset - start_offset, name, addend);
1467 break;
1468 case R_SPARC_HI22:
1469 fprintf(outfile,
1470 " *(uint32_t *)(gen_code_ptr + %d) = "
1471 "((*(uint32_t *)(gen_code_ptr + %d)) "
1472 " & ~0x3fffff) "
1473 " | (((%s + %d) >> 10) & 0x3fffff);\n",
1474 rel->r_offset - start_offset,
1475 rel->r_offset - start_offset,
1476 name, addend);
1477 break;
1478 case R_SPARC_LO10:
1479 fprintf(outfile,
1480 " *(uint32_t *)(gen_code_ptr + %d) = "
1481 "((*(uint32_t *)(gen_code_ptr + %d)) "
1482 " & ~0x3ff) "
1483 " | ((%s + %d) & 0x3ff);\n",
1484 rel->r_offset - start_offset,
1485 rel->r_offset - start_offset,
1486 name, addend);
1487 break;
1488 case R_SPARC_WDISP30:
1489 fprintf(outfile,
1490 " *(uint32_t *)(gen_code_ptr + %d) = "
1491 "((*(uint32_t *)(gen_code_ptr + %d)) "
1492 " & ~0x3fffffff) "
1493 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
1494 " & 0x3fffffff);\n",
1495 rel->r_offset - start_offset,
1496 rel->r_offset - start_offset,
1497 name, addend,
1498 rel->r_offset - start_offset);
1499 break;
1500 default:
1501 error("unsupported sparc relocation (%d)", type);
1502 }
1503 }
1504 }
1505 }
1506 #elif defined(HOST_SPARC64)
1507 {
1508 char name[256];
1509 int type;
1510 int addend;
1511 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1512 if (rel->r_offset >= start_offset &&
1513 rel->r_offset < start_offset + copy_size) {
1514 sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
1515 if (strstart(sym_name, "__op_param", &p)) {
1516 snprintf(name, sizeof(name), "param%s", p);
1517 } else {
1518 snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
1519 }
1520 type = ELF64_R_TYPE(rel->r_info);
1521 addend = rel->r_addend;
1522 switch(type) {
1523 case R_SPARC_32:
1524 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
1525 rel->r_offset - start_offset, name, addend);
1526 break;
1527 case R_SPARC_HI22:
1528 fprintf(outfile,
1529 " *(uint32_t *)(gen_code_ptr + %d) = "
1530 "((*(uint32_t *)(gen_code_ptr + %d)) "
1531 " & ~0x3fffff) "
1532 " | (((%s + %d) >> 10) & 0x3fffff);\n",
1533 rel->r_offset - start_offset,
1534 rel->r_offset - start_offset,
1535 name, addend);
1536 break;
1537 case R_SPARC_LO10:
1538 fprintf(outfile,
1539 " *(uint32_t *)(gen_code_ptr + %d) = "
1540 "((*(uint32_t *)(gen_code_ptr + %d)) "
1541 " & ~0x3ff) "
1542 " | ((%s + %d) & 0x3ff);\n",
1543 rel->r_offset - start_offset,
1544 rel->r_offset - start_offset,
1545 name, addend);
1546 break;
1547 case R_SPARC_WDISP30:
1548 fprintf(outfile,
1549 " *(uint32_t *)(gen_code_ptr + %d) = "
1550 "((*(uint32_t *)(gen_code_ptr + %d)) "
1551 " & ~0x3fffffff) "
1552 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
1553 " & 0x3fffffff);\n",
1554 rel->r_offset - start_offset,
1555 rel->r_offset - start_offset,
1556 name, addend,
1557 rel->r_offset - start_offset);
1558 break;
1559 default:
1560 error("unsupported sparc64 relocation (%d)", type);
1561 }
1562 }
1563 }
1564 }
1565 #elif defined(HOST_ARM)
1566 {
1567 char name[256];
1568 int type;
1569 int addend;
1570
1571 arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
1572 relocs, nb_relocs);
1573
1574 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1575 if (rel->r_offset >= start_offset &&
1576 rel->r_offset < start_offset + copy_size) {
1577 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1578 /* the compiler leave some unnecessary references to the code */
1579 if (sym_name[0] == '\0')
1580 continue;
1581 if (strstart(sym_name, "__op_param", &p)) {
1582 snprintf(name, sizeof(name), "param%s", p);
1583 } else {
1584 snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
1585 }
1586 type = ELF32_R_TYPE(rel->r_info);
1587 addend = get32((uint32_t *)(text + rel->r_offset));
1588 switch(type) {
1589 case R_ARM_ABS32:
1590 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
1591 rel->r_offset - start_offset, name, addend);
1592 break;
1593 case R_ARM_PC24:
1594 fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
1595 rel->r_offset - start_offset, addend, name);
1596 break;
1597 default:
1598 error("unsupported arm relocation (%d)", type);
1599 }
1600 }
1601 }
1602 }
1603 #elif defined(HOST_M68K)
1604 {
1605 char name[256];
1606 int type;
1607 int addend;
1608 Elf32_Sym *sym;
1609 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1610 if (rel->r_offset >= start_offset &&
1611 rel->r_offset < start_offset + copy_size) {
1612 sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
1613 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1614 if (strstart(sym_name, "__op_param", &p)) {
1615 snprintf(name, sizeof(name), "param%s", p);
1616 } else {
1617 snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
1618 }
1619 type = ELF32_R_TYPE(rel->r_info);
1620 addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
1621 switch(type) {
1622 case R_68K_32:
1623 fprintf(outfile, " /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
1624 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
1625 rel->r_offset - start_offset, name, addend );
1626 break;
1627 case R_68K_PC32:
1628 fprintf(outfile, " /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
1629 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
1630 rel->r_offset - start_offset, name, rel->r_offset - start_offset, /*sym->st_value+*/ addend);
1631 break;
1632 default:
1633 error("unsupported m68k relocation (%d)", type);
1634 }
1635 }
1636 }
1637 }
1638 #else
1639 #error unsupported CPU
1640 #endif
1641 fprintf(outfile, " gen_code_ptr += %d;\n", copy_size);
1642 fprintf(outfile, "}\n");
1643 fprintf(outfile, "break;\n\n");
1644 } else {
1645 fprintf(outfile, "static inline void gen_%s(", name);
1646 if (nb_args == 0) {
1647 fprintf(outfile, "void");
1648 } else {
1649 for(i = 0; i < nb_args; i++) {
1650 if (i != 0)
1651 fprintf(outfile, ", ");
1652 fprintf(outfile, "long param%d", i + 1);
1653 }
1654 }
1655 fprintf(outfile, ")\n");
1656 fprintf(outfile, "{\n");
1657 for(i = 0; i < nb_args; i++) {
1658 fprintf(outfile, " *gen_opparam_ptr++ = param%d;\n", i + 1);
1659 }
1660 fprintf(outfile, " *gen_opc_ptr++ = INDEX_%s;\n", name);
1661 fprintf(outfile, "}\n\n");
1662 }
1663 }
1664
1665 int gen_file(FILE *outfile, int out_type)
1666 {
1667 int i;
1668 EXE_SYM *sym;
1669
1670 if (out_type == OUT_INDEX_OP) {
1671 fprintf(outfile, "DEF(end, 0, 0)\n");
1672 fprintf(outfile, "DEF(nop, 0, 0)\n");
1673 fprintf(outfile, "DEF(nop1, 1, 0)\n");
1674 fprintf(outfile, "DEF(nop2, 2, 0)\n");
1675 fprintf(outfile, "DEF(nop3, 3, 0)\n");
1676 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
1677 const char *name, *p;
1678 name = get_sym_name(sym);
1679 if (strstart(name, OP_PREFIX, &p)) {
1680 gen_code(name, sym->st_value, sym->st_size, outfile, 2);
1681 }
1682 }
1683 } else if (out_type == OUT_GEN_OP) {
1684 /* generate gen_xxx functions */
1685
1686 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
1687 const char *name;
1688 name = get_sym_name(sym);
1689 if (strstart(name, OP_PREFIX, NULL)) {
1690 if (sym->st_shndx != text_shndx)
1691 error("invalid section for opcode (0x%x)", sym->st_shndx);
1692 gen_code(name, sym->st_value, sym->st_size, outfile, 0);
1693 }
1694 }
1695
1696 } else {
1697 /* generate big code generation switch */
1698 fprintf(outfile,
1699 "int dyngen_code(uint8_t *gen_code_buf,\n"
1700 " uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
1701 " const uint16_t *opc_buf, const uint32_t *opparam_buf)\n"
1702 "{\n"
1703 " uint8_t *gen_code_ptr;\n"
1704 " const uint16_t *opc_ptr;\n"
1705 " const uint32_t *opparam_ptr;\n");
1706
1707 #ifdef HOST_ARM
1708 fprintf(outfile,
1709 " uint8_t *last_gen_code_ptr = gen_code_buf;\n"
1710 " LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
1711 " uint32_t *arm_data_ptr = arm_data_table;\n");
1712 #endif
1713
1714 fprintf(outfile,
1715 "\n"
1716 " gen_code_ptr = gen_code_buf;\n"
1717 " opc_ptr = opc_buf;\n"
1718 " opparam_ptr = opparam_buf;\n");
1719
1720 /* Generate prologue, if needed. */
1721
1722 fprintf(outfile,
1723 " for(;;) {\n"
1724 " switch(*opc_ptr++) {\n"
1725 );
1726
1727 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
1728 const char *name;
1729 name = get_sym_name(sym);
1730 if (strstart(name, OP_PREFIX, NULL)) {
1731 #if 0
1732 printf("%4d: %s pos=0x%08x len=%d\n",
1733 i, name, sym->st_value, sym->st_size);
1734 #endif
1735 if (sym->st_shndx != text_shndx)
1736 error("invalid section for opcode (0x%x)", sym->st_shndx);
1737 gen_code(name, sym->st_value, sym->st_size, outfile, 1);
1738 }
1739 }
1740
1741 fprintf(outfile,
1742 " case INDEX_op_nop:\n"
1743 " break;\n"
1744 " case INDEX_op_nop1:\n"
1745 " opparam_ptr++;\n"
1746 " break;\n"
1747 " case INDEX_op_nop2:\n"
1748 " opparam_ptr += 2;\n"
1749 " break;\n"
1750 " case INDEX_op_nop3:\n"
1751 " opparam_ptr += 3;\n"
1752 " break;\n"
1753 " default:\n"
1754 " goto the_end;\n"
1755 " }\n");
1756
1757 #ifdef HOST_ARM
1758 /* generate constant table if needed */
1759 fprintf(outfile,
1760 " if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n"
1761 " gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n"
1762 " last_gen_code_ptr = gen_code_ptr;\n"
1763 " arm_ldr_ptr = arm_ldr_table;\n"
1764 " arm_data_ptr = arm_data_table;\n"
1765 " }\n");
1766 #endif
1767
1768
1769 fprintf(outfile,
1770 " }\n"
1771 " the_end:\n"
1772 );
1773
1774 /* generate some code patching */
1775 #ifdef HOST_ARM
1776 fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n");
1777 #endif
1778 /* flush instruction cache */
1779 fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
1780
1781 fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
1782 fprintf(outfile, "}\n\n");
1783
1784 }
1785
1786 return 0;
1787 }
1788
1789 void usage(void)
1790 {
1791 printf("dyngen (c) 2003 Fabrice Bellard\n"
1792 "usage: dyngen [-o outfile] [-c] objfile\n"
1793 "Generate a dynamic code generator from an object file\n"
1794 "-c output enum of operations\n"
1795 "-g output gen_op_xx() functions\n"
1796 );
1797 exit(1);
1798 }
1799
1800 int main(int argc, char **argv)
1801 {
1802 int c, out_type;
1803 const char *filename, *outfilename;
1804 FILE *outfile;
1805
1806 outfilename = "out.c";
1807 out_type = OUT_CODE;
1808 for(;;) {
1809 c = getopt(argc, argv, "ho:cg");
1810 if (c == -1)
1811 break;
1812 switch(c) {
1813 case 'h':
1814 usage();
1815 break;
1816 case 'o':
1817 outfilename = optarg;
1818 break;
1819 case 'c':
1820 out_type = OUT_INDEX_OP;
1821 break;
1822 case 'g':
1823 out_type = OUT_GEN_OP;
1824 break;
1825 }
1826 }
1827 if (optind >= argc)
1828 usage();
1829 filename = argv[optind];
1830 outfile = fopen(outfilename, "w");
1831 if (!outfile)
1832 error("could not open '%s'", outfilename);
1833
1834 load_object(filename);
1835 gen_file(outfile, out_type);
1836 fclose(outfile);
1837 return 0;
1838 }