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