Rewrite Arm host support.
[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  *  Mach-O Support by Matt Reda and Pierre d'Herbemont
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <inttypes.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32
33 #include "config-host.h"
34
35 /* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross
36    compilation */
37 #if defined(CONFIG_WIN32)
38 #define CONFIG_FORMAT_COFF
39 #elif defined(CONFIG_DARWIN)
40 #define CONFIG_FORMAT_MACH
41 #else
42 #define CONFIG_FORMAT_ELF
43 #endif
44
45 #ifdef CONFIG_FORMAT_ELF
46
47 /* elf format definitions. We use these macros to test the CPU to
48    allow cross compilation (this tool must be ran on the build
49    platform) */
50 #if defined(HOST_I386)
51
52 #define ELF_CLASS       ELFCLASS32
53 #define ELF_ARCH        EM_386
54 #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
55 #undef ELF_USES_RELOCA
56
57 #elif defined(HOST_X86_64)
58
59 #define ELF_CLASS       ELFCLASS64
60 #define ELF_ARCH        EM_X86_64
61 #define elf_check_arch(x) ((x) == EM_X86_64)
62 #define ELF_USES_RELOCA
63
64 #elif defined(HOST_PPC)
65
66 #define ELF_CLASS       ELFCLASS32
67 #define ELF_ARCH        EM_PPC
68 #define elf_check_arch(x) ((x) == EM_PPC)
69 #define ELF_USES_RELOCA
70
71 #elif defined(HOST_S390)
72
73 #define ELF_CLASS       ELFCLASS32
74 #define ELF_ARCH        EM_S390
75 #define elf_check_arch(x) ((x) == EM_S390)
76 #define ELF_USES_RELOCA
77
78 #elif defined(HOST_ALPHA)
79
80 #define ELF_CLASS       ELFCLASS64
81 #define ELF_ARCH        EM_ALPHA
82 #define elf_check_arch(x) ((x) == EM_ALPHA)
83 #define ELF_USES_RELOCA
84
85 #elif defined(HOST_IA64)
86
87 #define ELF_CLASS       ELFCLASS64
88 #define ELF_ARCH        EM_IA_64
89 #define elf_check_arch(x) ((x) == EM_IA_64)
90 #define ELF_USES_RELOCA
91
92 #elif defined(HOST_SPARC)
93
94 #define ELF_CLASS       ELFCLASS32
95 #define ELF_ARCH        EM_SPARC
96 #define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS)
97 #define ELF_USES_RELOCA
98
99 #elif defined(HOST_SPARC64)
100
101 #define ELF_CLASS       ELFCLASS64
102 #define ELF_ARCH        EM_SPARCV9
103 #define elf_check_arch(x) ((x) == EM_SPARCV9)
104 #define ELF_USES_RELOCA
105
106 #elif defined(HOST_ARM)
107
108 #define ELF_CLASS       ELFCLASS32
109 #define ELF_ARCH        EM_ARM
110 #define elf_check_arch(x) ((x) == EM_ARM)
111 #define ELF_USES_RELOC
112
113 #elif defined(HOST_M68K)
114
115 #define ELF_CLASS       ELFCLASS32
116 #define ELF_ARCH        EM_68K
117 #define elf_check_arch(x) ((x) == EM_68K)
118 #define ELF_USES_RELOCA
119
120 #else
121 #error unsupported CPU - please update the code
122 #endif
123
124 #include "elf.h"
125
126 #if ELF_CLASS == ELFCLASS32
127 typedef int32_t host_long;
128 typedef uint32_t host_ulong;
129 #define swabls(x) swab32s(x)
130 #else
131 typedef int64_t host_long;
132 typedef uint64_t host_ulong;
133 #define swabls(x) swab64s(x)
134 #endif
135
136 #ifdef ELF_USES_RELOCA
137 #define SHT_RELOC SHT_RELA
138 #else
139 #define SHT_RELOC SHT_REL
140 #endif
141
142 #define EXE_RELOC ELF_RELOC
143 #define EXE_SYM ElfW(Sym)
144
145 #endif /* CONFIG_FORMAT_ELF */
146
147 #ifdef CONFIG_FORMAT_COFF
148
149 #include "a.out.h"
150
151 typedef int32_t host_long;
152 typedef uint32_t host_ulong;
153
154 #define FILENAMELEN 256
155
156 typedef struct coff_sym {
157     struct external_syment *st_syment;
158     char st_name[FILENAMELEN];
159     uint32_t st_value;
160     int  st_size;
161     uint8_t st_type;
162     uint8_t st_shndx;
163 } coff_Sym;
164
165 typedef struct coff_rel {
166     struct external_reloc *r_reloc;
167     int  r_offset;
168     uint8_t r_type;
169 } coff_Rel;
170
171 #define EXE_RELOC struct coff_rel
172 #define EXE_SYM struct coff_sym
173
174 #endif /* CONFIG_FORMAT_COFF */
175
176 #ifdef CONFIG_FORMAT_MACH
177
178 #include <mach-o/loader.h>
179 #include <mach-o/nlist.h>
180 #include <mach-o/reloc.h>
181 #include <mach-o/ppc/reloc.h>
182
183 # define check_mach_header(x) (x.magic == MH_MAGIC)
184 typedef int32_t host_long;
185 typedef uint32_t host_ulong;
186
187 struct nlist_extended
188 {
189    union {
190    char *n_name; 
191    long  n_strx; 
192    } n_un;
193    unsigned char n_type; 
194    unsigned char n_sect; 
195    short st_desc;
196    unsigned long st_value;
197    unsigned long st_size;
198 };
199
200 #define EXE_RELOC struct relocation_info
201 #define EXE_SYM struct nlist_extended
202
203 #endif /* CONFIG_FORMAT_MACH */
204
205 #include "bswap.h"
206
207 enum {
208     OUT_GEN_OP,
209     OUT_CODE,
210     OUT_INDEX_OP,
211 };
212
213 /* all dynamically generated functions begin with this code */
214 #define OP_PREFIX "op_"
215
216 int do_swap;
217
218 void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
219 {
220     va_list ap;
221     va_start(ap, fmt);
222     fprintf(stderr, "dyngen: ");
223     vfprintf(stderr, fmt, ap);
224     fprintf(stderr, "\n");
225     va_end(ap);
226     exit(1);
227 }
228
229 void *load_data(int fd, long offset, unsigned int size)
230 {
231     char *data;
232
233     data = malloc(size);
234     if (!data)
235         return NULL;
236     lseek(fd, offset, SEEK_SET);
237     if (read(fd, data, size) != size) {
238         free(data);
239         return NULL;
240     }
241     return data;
242 }
243
244 int strstart(const char *str, const char *val, const char **ptr)
245 {
246     const char *p, *q;
247     p = str;
248     q = val;
249     while (*q != '\0') {
250         if (*p != *q)
251             return 0;
252         p++;
253         q++;
254     }
255     if (ptr)
256         *ptr = p;
257     return 1;
258 }
259
260 void pstrcpy(char *buf, int buf_size, const char *str)
261 {
262     int c;
263     char *q = buf;
264
265     if (buf_size <= 0)
266         return;
267
268     for(;;) {
269         c = *str++;
270         if (c == 0 || q >= buf + buf_size - 1)
271             break;
272         *q++ = c;
273     }
274     *q = '\0';
275 }
276
277 void swab16s(uint16_t *p)
278 {
279     *p = bswap16(*p);
280 }
281
282 void swab32s(uint32_t *p)
283 {
284     *p = bswap32(*p);
285 }
286
287 void swab64s(uint64_t *p)
288 {
289     *p = bswap64(*p);
290 }
291
292 uint16_t get16(uint16_t *p)
293 {
294     uint16_t val;
295     val = *p;
296     if (do_swap)
297         val = bswap16(val);
298     return val;
299 }
300
301 uint32_t get32(uint32_t *p)
302 {
303     uint32_t val;
304     val = *p;
305     if (do_swap)
306         val = bswap32(val);
307     return val;
308 }
309
310 void put16(uint16_t *p, uint16_t val)
311 {
312     if (do_swap)
313         val = bswap16(val);
314     *p = val;
315 }
316
317 void put32(uint32_t *p, uint32_t val)
318 {
319     if (do_swap)
320         val = bswap32(val);
321     *p = val;
322 }
323
324 /* executable information */
325 EXE_SYM *symtab;
326 int nb_syms;
327 int text_shndx;
328 uint8_t *text;
329 EXE_RELOC *relocs;
330 int nb_relocs;
331
332 #ifdef CONFIG_FORMAT_ELF
333
334 /* ELF file info */
335 struct elf_shdr *shdr;
336 uint8_t **sdata;
337 struct elfhdr ehdr;
338 char *strtab;
339
340 int elf_must_swap(struct elfhdr *h)
341 {
342   union {
343       uint32_t i;
344       uint8_t b[4];
345   } swaptest;
346
347   swaptest.i = 1;
348   return (h->e_ident[EI_DATA] == ELFDATA2MSB) != 
349       (swaptest.b[0] == 0);
350 }
351   
352 void elf_swap_ehdr(struct elfhdr *h)
353 {
354     swab16s(&h->e_type);                        /* Object file type */
355     swab16s(&h->        e_machine);             /* Architecture */
356     swab32s(&h->        e_version);             /* Object file version */
357     swabls(&h-> e_entry);               /* Entry point virtual address */
358     swabls(&h-> e_phoff);               /* Program header table file offset */
359     swabls(&h-> e_shoff);               /* Section header table file offset */
360     swab32s(&h->        e_flags);               /* Processor-specific flags */
361     swab16s(&h->        e_ehsize);              /* ELF header size in bytes */
362     swab16s(&h->        e_phentsize);           /* Program header table entry size */
363     swab16s(&h->        e_phnum);               /* Program header table entry count */
364     swab16s(&h->        e_shentsize);           /* Section header table entry size */
365     swab16s(&h->        e_shnum);               /* Section header table entry count */
366     swab16s(&h->        e_shstrndx);            /* Section header string table index */
367 }
368
369 void elf_swap_shdr(struct elf_shdr *h)
370 {
371   swab32s(&h->  sh_name);               /* Section name (string tbl index) */
372   swab32s(&h->  sh_type);               /* Section type */
373   swabls(&h->   sh_flags);              /* Section flags */
374   swabls(&h->   sh_addr);               /* Section virtual addr at execution */
375   swabls(&h->   sh_offset);             /* Section file offset */
376   swabls(&h->   sh_size);               /* Section size in bytes */
377   swab32s(&h->  sh_link);               /* Link to another section */
378   swab32s(&h->  sh_info);               /* Additional section information */
379   swabls(&h->   sh_addralign);          /* Section alignment */
380   swabls(&h->   sh_entsize);            /* Entry size if section holds table */
381 }
382
383 void elf_swap_phdr(struct elf_phdr *h)
384 {
385     swab32s(&h->p_type);                        /* Segment type */
386     swabls(&h->p_offset);               /* Segment file offset */
387     swabls(&h->p_vaddr);                /* Segment virtual address */
388     swabls(&h->p_paddr);                /* Segment physical address */
389     swabls(&h->p_filesz);               /* Segment size in file */
390     swabls(&h->p_memsz);                /* Segment size in memory */
391     swab32s(&h->p_flags);               /* Segment flags */
392     swabls(&h->p_align);                /* Segment alignment */
393 }
394
395 void elf_swap_rel(ELF_RELOC *rel)
396 {
397     swabls(&rel->r_offset);
398     swabls(&rel->r_info);
399 #ifdef ELF_USES_RELOCA
400     swabls(&rel->r_addend);
401 #endif
402 }
403
404 struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr, 
405                                   const char *name)
406 {
407     int i;
408     const char *shname;
409     struct elf_shdr *sec;
410
411     for(i = 0; i < shnum; i++) {
412         sec = &shdr[i];
413         if (!sec->sh_name)
414             continue;
415         shname = shstr + sec->sh_name;
416         if (!strcmp(shname, name))
417             return sec;
418     }
419     return NULL;
420 }
421
422 int find_reloc(int sh_index)
423 {
424     struct elf_shdr *sec;
425     int i;
426
427     for(i = 0; i < ehdr.e_shnum; i++) {
428         sec = &shdr[i];
429         if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) 
430             return i;
431     }
432     return 0;
433 }
434
435 static host_ulong get_rel_offset(EXE_RELOC *rel)
436 {
437     return rel->r_offset;
438 }
439
440 static char *get_rel_sym_name(EXE_RELOC *rel)
441 {
442     return strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
443 }
444
445 static char *get_sym_name(EXE_SYM *sym)
446 {
447     return strtab + sym->st_name;
448 }
449
450 /* load an elf object file */
451 int load_object(const char *filename)
452 {
453     int fd;
454     struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec;
455     int i, j;
456     ElfW(Sym) *sym;
457     char *shstr;
458     ELF_RELOC *rel;
459     
460     fd = open(filename, O_RDONLY);
461     if (fd < 0) 
462         error("can't open file '%s'", filename);
463     
464     /* Read ELF header.  */
465     if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
466         error("unable to read file header");
467
468     /* Check ELF identification.  */
469     if (ehdr.e_ident[EI_MAG0] != ELFMAG0
470      || ehdr.e_ident[EI_MAG1] != ELFMAG1
471      || ehdr.e_ident[EI_MAG2] != ELFMAG2
472      || ehdr.e_ident[EI_MAG3] != ELFMAG3
473      || ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
474         error("bad ELF header");
475     }
476
477     do_swap = elf_must_swap(&ehdr);
478     if (do_swap)
479         elf_swap_ehdr(&ehdr);
480     if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
481         error("Unsupported ELF class");
482     if (ehdr.e_type != ET_REL)
483         error("ELF object file expected");
484     if (ehdr.e_version != EV_CURRENT)
485         error("Invalid ELF version");
486     if (!elf_check_arch(ehdr.e_machine))
487         error("Unsupported CPU (e_machine=%d)", ehdr.e_machine);
488
489     /* read section headers */
490     shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(struct elf_shdr));
491     if (do_swap) {
492         for(i = 0; i < ehdr.e_shnum; i++) {
493             elf_swap_shdr(&shdr[i]);
494         }
495     }
496
497     /* read all section data */
498     sdata = malloc(sizeof(void *) * ehdr.e_shnum);
499     memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
500     
501     for(i = 0;i < ehdr.e_shnum; i++) {
502         sec = &shdr[i];
503         if (sec->sh_type != SHT_NOBITS)
504             sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size);
505     }
506
507     sec = &shdr[ehdr.e_shstrndx];
508     shstr = sdata[ehdr.e_shstrndx];
509
510     /* swap relocations */
511     for(i = 0; i < ehdr.e_shnum; i++) {
512         sec = &shdr[i];
513         if (sec->sh_type == SHT_RELOC) {
514             nb_relocs = sec->sh_size / sec->sh_entsize;
515             if (do_swap) {
516                 for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++)
517                     elf_swap_rel(rel);
518             }
519         }
520     }
521     /* text section */
522
523     text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
524     if (!text_sec)
525         error("could not find .text section");
526     text_shndx = text_sec - shdr;
527     text = sdata[text_shndx];
528
529     /* find text relocations, if any */
530     relocs = NULL;
531     nb_relocs = 0;
532     i = find_reloc(text_shndx);
533     if (i != 0) {
534         relocs = (ELF_RELOC *)sdata[i];
535         nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize;
536     }
537
538     symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
539     if (!symtab_sec)
540         error("could not find .symtab section");
541     strtab_sec = &shdr[symtab_sec->sh_link];
542
543     symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
544     strtab = sdata[symtab_sec->sh_link];
545     
546     nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
547     if (do_swap) {
548         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
549             swab32s(&sym->st_name);
550             swabls(&sym->st_value);
551             swabls(&sym->st_size);
552             swab16s(&sym->st_shndx);
553         }
554     }
555     close(fd);
556     return 0;
557 }
558
559 #endif /* CONFIG_FORMAT_ELF */
560
561 #ifdef CONFIG_FORMAT_COFF
562
563 /* COFF file info */
564 struct external_scnhdr *shdr;
565 uint8_t **sdata;
566 struct external_filehdr fhdr;
567 struct external_syment *coff_symtab;
568 char *strtab;
569 int coff_text_shndx, coff_data_shndx;
570
571 int data_shndx;
572
573 #define STRTAB_SIZE 4
574
575 #define DIR32   0x06
576 #define DISP32  0x14
577
578 #define T_FUNCTION  0x20
579 #define C_EXTERNAL  2
580
581 void sym_ent_name(struct external_syment *ext_sym, EXE_SYM *sym)
582 {
583     char *q;
584     int c, i, len;
585     
586     if (ext_sym->e.e.e_zeroes != 0) {
587         q = sym->st_name;
588         for(i = 0; i < 8; i++) {
589             c = ext_sym->e.e_name[i];
590             if (c == '\0')
591                 break;
592             *q++ = c;
593         }
594         *q = '\0';
595     } else {
596         pstrcpy(sym->st_name, sizeof(sym->st_name), strtab + ext_sym->e.e.e_offset);
597     }
598
599     /* now convert the name to a C name (suppress the leading '_') */
600     if (sym->st_name[0] == '_') {
601         len = strlen(sym->st_name);
602         memmove(sym->st_name, sym->st_name + 1, len - 1);
603         sym->st_name[len - 1] = '\0';
604     }
605 }
606
607 char *name_for_dotdata(struct coff_rel *rel)
608 {
609         int i;
610         struct coff_sym *sym;
611         uint32_t text_data;
612
613         text_data = *(uint32_t *)(text + rel->r_offset);
614
615         for (i = 0, sym = symtab; i < nb_syms; i++, sym++) {
616                 if (sym->st_syment->e_scnum == data_shndx &&
617                     text_data >= sym->st_value &&
618                     text_data < sym->st_value + sym->st_size) {
619                     
620                     return sym->st_name;
621
622                 }
623         }
624         return NULL;
625 }
626
627 static char *get_sym_name(EXE_SYM *sym)
628 {
629     return sym->st_name;
630 }
631
632 static char *get_rel_sym_name(EXE_RELOC *rel)
633 {
634     char *name;
635     name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
636     if (!strcmp(name, ".data"))
637         name = name_for_dotdata(rel);
638     if (name[0] == '.')
639         return NULL;
640     return name;
641 }
642
643 static host_ulong get_rel_offset(EXE_RELOC *rel)
644 {
645     return rel->r_offset;
646 }
647
648 struct external_scnhdr *find_coff_section(struct external_scnhdr *shdr, int shnum, const char *name)
649 {
650     int i;
651     const char *shname;
652     struct external_scnhdr *sec;
653
654     for(i = 0; i < shnum; i++) {
655         sec = &shdr[i];
656         if (!sec->s_name)
657             continue;
658         shname = sec->s_name;
659         if (!strcmp(shname, name))
660             return sec;
661     }
662     return NULL;
663 }
664
665 /* load a coff object file */
666 int load_object(const char *filename)
667 {
668     int fd;
669     struct external_scnhdr *sec, *text_sec, *data_sec;
670     int i;
671     struct external_syment *ext_sym;
672     struct external_reloc *coff_relocs;
673     struct external_reloc *ext_rel;
674     uint32_t *n_strtab;
675     EXE_SYM *sym;
676     EXE_RELOC *rel;
677         
678     fd = open(filename, O_RDONLY 
679 #ifdef _WIN32
680               | O_BINARY
681 #endif
682               );
683     if (fd < 0) 
684         error("can't open file '%s'", filename);
685     
686     /* Read COFF header.  */
687     if (read(fd, &fhdr, sizeof (fhdr)) != sizeof (fhdr))
688         error("unable to read file header");
689
690     /* Check COFF identification.  */
691     if (fhdr.f_magic != I386MAGIC) {
692         error("bad COFF header");
693     }
694     do_swap = 0;
695
696     /* read section headers */
697     shdr = load_data(fd, sizeof(struct external_filehdr) + fhdr.f_opthdr, fhdr.f_nscns * sizeof(struct external_scnhdr));
698         
699     /* read all section data */
700     sdata = malloc(sizeof(void *) * fhdr.f_nscns);
701     memset(sdata, 0, sizeof(void *) * fhdr.f_nscns);
702     
703     const char *p;
704     for(i = 0;i < fhdr.f_nscns; i++) {
705         sec = &shdr[i];
706         if (!strstart(sec->s_name,  ".bss", &p))
707             sdata[i] = load_data(fd, sec->s_scnptr, sec->s_size);
708     }
709
710
711     /* text section */
712     text_sec = find_coff_section(shdr, fhdr.f_nscns, ".text");
713     if (!text_sec)
714         error("could not find .text section");
715     coff_text_shndx = text_sec - shdr;
716     text = sdata[coff_text_shndx];
717
718     /* data section */
719     data_sec = find_coff_section(shdr, fhdr.f_nscns, ".data");
720     if (!data_sec)
721         error("could not find .data section");
722     coff_data_shndx = data_sec - shdr;
723     
724     coff_symtab = load_data(fd, fhdr.f_symptr, fhdr.f_nsyms*SYMESZ);
725     for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
726         for(i=0;i<8;i++)
727             printf(" %02x", ((uint8_t *)ext_sym->e.e_name)[i]);
728         printf("\n");
729     }
730
731
732     n_strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), STRTAB_SIZE);
733     strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab); 
734     
735     nb_syms = fhdr.f_nsyms;
736
737     for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
738       if (strstart(ext_sym->e.e_name, ".text", NULL))
739                   text_shndx = ext_sym->e_scnum;
740           if (strstart(ext_sym->e.e_name, ".data", NULL))
741                   data_shndx = ext_sym->e_scnum;
742     }
743
744         /* set coff symbol */
745         symtab = malloc(sizeof(struct coff_sym) * nb_syms);
746
747         int aux_size, j;
748         for (i = 0, ext_sym = coff_symtab, sym = symtab; i < nb_syms; i++, ext_sym++, sym++) {
749                 memset(sym, 0, sizeof(*sym));
750                 sym->st_syment = ext_sym;
751                 sym_ent_name(ext_sym, sym);
752                 sym->st_value = ext_sym->e_value;
753
754                 aux_size = *(int8_t *)ext_sym->e_numaux;
755                 if (ext_sym->e_scnum == text_shndx && ext_sym->e_type == T_FUNCTION) {
756                         for (j = aux_size + 1; j < nb_syms - i; j++) {
757                                 if ((ext_sym + j)->e_scnum == text_shndx &&
758                                         (ext_sym + j)->e_type == T_FUNCTION ){
759                                         sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
760                                         break;
761                                 } else if (j == nb_syms - i - 1) {
762                                         sec = &shdr[coff_text_shndx];
763                                         sym->st_size = sec->s_size - ext_sym->e_value;
764                                         break;
765                                 }
766                         }
767                 } else if (ext_sym->e_scnum == data_shndx && *(uint8_t *)ext_sym->e_sclass == C_EXTERNAL) {
768                         for (j = aux_size + 1; j < nb_syms - i; j++) {
769                                 if ((ext_sym + j)->e_scnum == data_shndx) {
770                                         sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
771                                         break;
772                                 } else if (j == nb_syms - i - 1) {
773                                         sec = &shdr[coff_data_shndx];
774                                         sym->st_size = sec->s_size - ext_sym->e_value;
775                                         break;
776                                 }
777                         }
778                 } else {
779                         sym->st_size = 0;
780                 }
781                 
782                 sym->st_type = ext_sym->e_type;
783                 sym->st_shndx = ext_sym->e_scnum;
784         }
785
786                 
787     /* find text relocations, if any */
788     sec = &shdr[coff_text_shndx];
789     coff_relocs = load_data(fd, sec->s_relptr, sec->s_nreloc*RELSZ);
790     nb_relocs = sec->s_nreloc;
791
792     /* set coff relocation */
793     relocs = malloc(sizeof(struct coff_rel) * nb_relocs);
794     for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs; 
795          i++, ext_rel++, rel++) {
796         memset(rel, 0, sizeof(*rel));
797         rel->r_reloc = ext_rel;
798         rel->r_offset = *(uint32_t *)ext_rel->r_vaddr;
799         rel->r_type = *(uint16_t *)ext_rel->r_type;
800     }
801     return 0;
802 }
803
804 #endif /* CONFIG_FORMAT_COFF */
805
806 #ifdef CONFIG_FORMAT_MACH
807
808 /* File Header */
809 struct mach_header      mach_hdr;
810
811 /* commands */
812 struct segment_command  *segment = 0;
813 struct dysymtab_command *dysymtabcmd = 0;
814 struct symtab_command   *symtabcmd = 0;
815
816 /* section */
817 struct section  *section_hdr;
818 struct section *text_sec_hdr;
819 uint8_t         **sdata;
820
821 /* relocs */
822 struct relocation_info *relocs;
823         
824 /* symbols */
825 EXE_SYM                 *symtab;
826 struct nlist    *symtab_std;
827 char                    *strtab;
828
829 /* indirect symbols */
830 uint32_t        *tocdylib;
831
832 /* Utility functions */
833
834 static inline char *find_str_by_index(int index)
835 {
836     return strtab+index;
837 }
838
839 /* Used by dyngen common code */
840 static char *get_sym_name(EXE_SYM *sym)
841 {
842         char *name = find_str_by_index(sym->n_un.n_strx);
843         
844         if ( sym->n_type & N_STAB ) /* Debug symbols are ignored */
845                 return "debug";
846                         
847         if(!name)
848                 return name;
849         if(name[0]=='_')
850                 return name + 1;
851         else
852                 return name;
853 }
854
855 /* find a section index given its segname, sectname */
856 static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname, 
857                                   const char *sectname)
858 {
859     int i;
860     struct section *sec = section_hdr;
861
862     for(i = 0; i < shnum; i++, sec++) {
863         if (!sec->segname || !sec->sectname)
864             continue;
865         if (!strcmp(sec->sectname, sectname) && !strcmp(sec->segname, segname))
866             return i;
867     }
868     return -1;
869 }
870
871 /* find a section header given its segname, sectname */
872 struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname, 
873                                   const char *sectname)
874 {
875     int index = find_mach_sec_index(section_hdr, shnum, segname, sectname);
876         if(index == -1)
877                 return NULL;
878         return section_hdr+index;
879 }
880
881
882 static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned int *value)
883 {
884     struct scattered_relocation_info * scarel;
885         
886     if(R_SCATTERED & rel->r_address) {
887         scarel = (struct scattered_relocation_info*)rel;
888         if(scarel->r_type != PPC_RELOC_PAIR)
889             error("fetch_next_pair_value: looking for a pair which was not found (1)");
890         *value = scarel->r_value;
891     } else {
892                 if(rel->r_type != PPC_RELOC_PAIR)
893                         error("fetch_next_pair_value: looking for a pair which was not found (2)");
894                 *value = rel->r_address;
895         }
896 }
897
898 /* find a sym name given its value, in a section number */
899 static const char * find_sym_with_value_and_sec_number( int value, int sectnum, int * offset )
900 {
901         int i, ret = -1;
902         
903         for( i = 0 ; i < nb_syms; i++ )
904         {
905             if( !(symtab[i].n_type & N_STAB) && (symtab[i].n_type & N_SECT) &&
906                          (symtab[i].n_sect ==  sectnum) && (symtab[i].st_value <= value) )
907                 {
908                         if( (ret<0) || (symtab[i].st_value >= symtab[ret].st_value) )
909                                 ret = i;
910                 }
911         }
912         if( ret < 0 ) {
913                 *offset = 0;
914                 return 0;
915         } else {
916                 *offset = value - symtab[ret].st_value;
917                 return get_sym_name(&symtab[ret]);
918         }
919 }
920
921 /* 
922  *  Find symbol name given a (virtual) address, and a section which is of type 
923  *  S_NON_LAZY_SYMBOL_POINTERS or S_LAZY_SYMBOL_POINTERS or S_SYMBOL_STUBS
924  */
925 static const char * find_reloc_name_in_sec_ptr(int address, struct section * sec_hdr)
926 {
927     unsigned int tocindex, symindex, size;
928     const char *name = 0;
929     
930     /* Sanity check */
931     if(!( address >= sec_hdr->addr && address < (sec_hdr->addr + sec_hdr->size) ) )
932         return (char*)0;
933                 
934         if( sec_hdr->flags & S_SYMBOL_STUBS ){
935                 size = sec_hdr->reserved2;
936                 if(size == 0)
937                     error("size = 0");
938                 
939         }
940         else if( sec_hdr->flags & S_LAZY_SYMBOL_POINTERS ||
941                     sec_hdr->flags & S_NON_LAZY_SYMBOL_POINTERS)
942                 size = sizeof(unsigned long);
943         else
944                 return 0;
945                 
946     /* Compute our index in toc */
947         tocindex = (address - sec_hdr->addr)/size;
948         symindex = tocdylib[sec_hdr->reserved1 + tocindex];
949         
950         name = get_sym_name(&symtab[symindex]);
951
952     return name;
953 }
954
955 static const char * find_reloc_name_given_its_address(int address)
956 {
957     unsigned int i;
958     for(i = 0; i < segment->nsects ; i++)
959     {
960         const char * name = find_reloc_name_in_sec_ptr(address, &section_hdr[i]);
961         if((long)name != -1)
962             return name;
963     }
964     return 0;
965 }
966
967 static const char * get_reloc_name(EXE_RELOC * rel, int * sslide)
968 {
969         char * name = 0;
970         struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
971         int sectnum = rel->r_symbolnum;
972         int sectoffset;
973         int other_half=0;
974         
975         /* init the slide value */
976         *sslide = 0;
977         
978         if(R_SCATTERED & rel->r_address)
979                 return (char *)find_reloc_name_given_its_address(sca_rel->r_value);
980
981         if(rel->r_extern)
982         {
983                 /* ignore debug sym */
984                 if ( symtab[rel->r_symbolnum].n_type & N_STAB ) 
985                         return 0;
986                 return get_sym_name(&symtab[rel->r_symbolnum]);
987         }
988
989         /* Intruction contains an offset to the symbols pointed to, in the rel->r_symbolnum section */
990         sectoffset = *(uint32_t *)(text + rel->r_address) & 0xffff;
991                         
992         if(sectnum==0xffffff)
993                 return 0;
994
995         /* Sanity Check */
996         if(sectnum > segment->nsects)
997                 error("sectnum > segment->nsects");
998
999         switch(rel->r_type)
1000         {
1001                 case PPC_RELOC_LO16: fetch_next_pair_value(rel+1, &other_half); sectoffset |= (other_half << 16);
1002                         break;
1003                 case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) | (uint16_t)(other_half & 0xffff);
1004                         break;
1005                 case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) + (int16_t)(other_half & 0xffff);
1006                         break;
1007                 case PPC_RELOC_BR24:
1008                         sectoffset = ( *(uint32_t *)(text + rel->r_address) & 0x03fffffc );
1009                         if (sectoffset & 0x02000000) sectoffset |= 0xfc000000;
1010                         break;
1011                 default:
1012                         error("switch(rel->type) not found");
1013         }
1014
1015         if(rel->r_pcrel)
1016                 sectoffset += rel->r_address;
1017                         
1018         if (rel->r_type == PPC_RELOC_BR24)
1019                 name = (char *)find_reloc_name_in_sec_ptr((int)sectoffset, &section_hdr[sectnum-1]);
1020
1021         /* search it in the full symbol list, if not found */
1022         if(!name)
1023                 name = (char *)find_sym_with_value_and_sec_number(sectoffset, sectnum, sslide);
1024         
1025         return name;
1026 }
1027
1028 /* Used by dyngen common code */
1029 static const char * get_rel_sym_name(EXE_RELOC * rel)
1030 {
1031         int sslide;
1032         return get_reloc_name( rel, &sslide);
1033 }
1034
1035 /* Used by dyngen common code */
1036 static host_ulong get_rel_offset(EXE_RELOC *rel)
1037 {
1038         struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
1039     if(R_SCATTERED & rel->r_address)
1040                 return sca_rel->r_address;
1041         else
1042                 return rel->r_address;
1043 }
1044
1045 /* load a mach-o object file */
1046 int load_object(const char *filename)
1047 {
1048         int fd;
1049         unsigned int offset_to_segment = 0;
1050     unsigned int offset_to_dysymtab = 0;
1051     unsigned int offset_to_symtab = 0;
1052     struct load_command lc;
1053     unsigned int i, j;
1054         EXE_SYM *sym;
1055         struct nlist *syment;
1056     
1057         fd = open(filename, O_RDONLY);
1058     if (fd < 0) 
1059         error("can't open file '%s'", filename);
1060                 
1061     /* Read Mach header.  */
1062     if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
1063         error("unable to read file header");
1064
1065     /* Check Mach identification.  */
1066     if (!check_mach_header(mach_hdr)) {
1067         error("bad Mach header");
1068     }
1069     
1070     if (mach_hdr.cputype != CPU_TYPE_POWERPC)
1071         error("Unsupported CPU");
1072         
1073     if (mach_hdr.filetype != MH_OBJECT)
1074         error("Unsupported Mach Object");
1075     
1076     /* read segment headers */
1077     for(i=0, j=sizeof(mach_hdr); i<mach_hdr.ncmds ; i++)
1078     {
1079         if(read(fd, &lc, sizeof(struct load_command)) != sizeof(struct load_command))
1080             error("unable to read load_command");
1081         if(lc.cmd == LC_SEGMENT)
1082         {
1083             offset_to_segment = j;
1084             lseek(fd, offset_to_segment, SEEK_SET);
1085             segment = malloc(sizeof(struct segment_command));
1086             if(read(fd, segment, sizeof(struct segment_command)) != sizeof(struct segment_command))
1087                 error("unable to read LC_SEGMENT");
1088         }
1089         if(lc.cmd == LC_DYSYMTAB)
1090         {
1091             offset_to_dysymtab = j;
1092             lseek(fd, offset_to_dysymtab, SEEK_SET);
1093             dysymtabcmd = malloc(sizeof(struct dysymtab_command));
1094             if(read(fd, dysymtabcmd, sizeof(struct dysymtab_command)) != sizeof(struct dysymtab_command))
1095                 error("unable to read LC_DYSYMTAB");
1096         }
1097         if(lc.cmd == LC_SYMTAB)
1098         {
1099             offset_to_symtab = j;
1100             lseek(fd, offset_to_symtab, SEEK_SET);
1101             symtabcmd = malloc(sizeof(struct symtab_command));
1102             if(read(fd, symtabcmd, sizeof(struct symtab_command)) != sizeof(struct symtab_command))
1103                 error("unable to read LC_SYMTAB");
1104         }
1105         j+=lc.cmdsize;
1106
1107         lseek(fd, j, SEEK_SET);
1108     }
1109
1110     if(!segment)
1111         error("unable to find LC_SEGMENT");
1112
1113     /* read section headers */
1114     section_hdr = load_data(fd, offset_to_segment + sizeof(struct segment_command), segment->nsects * sizeof(struct section));
1115
1116     /* read all section data */
1117     sdata = (uint8_t **)malloc(sizeof(void *) * segment->nsects);
1118     memset(sdata, 0, sizeof(void *) * segment->nsects);
1119     
1120         /* Load the data in section data */
1121         for(i = 0; i < segment->nsects; i++) {
1122         sdata[i] = load_data(fd, section_hdr[i].offset, section_hdr[i].size);
1123     }
1124         
1125     /* text section */
1126         text_sec_hdr = find_mach_sec_hdr(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
1127         i = find_mach_sec_index(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
1128         if (i == -1 || !text_sec_hdr)
1129         error("could not find __TEXT,__text section");
1130     text = sdata[i];
1131         
1132     /* Make sure dysym was loaded */
1133     if(!(int)dysymtabcmd)
1134         error("could not find __DYSYMTAB segment");
1135     
1136     /* read the table of content of the indirect sym */
1137     tocdylib = load_data( fd, dysymtabcmd->indirectsymoff, dysymtabcmd->nindirectsyms * sizeof(uint32_t) );
1138     
1139     /* Make sure symtab was loaded  */
1140     if(!(int)symtabcmd)
1141         error("could not find __SYMTAB segment");
1142     nb_syms = symtabcmd->nsyms;
1143
1144     symtab_std = load_data(fd, symtabcmd->symoff, symtabcmd->nsyms * sizeof(struct nlist));
1145     strtab = load_data(fd, symtabcmd->stroff, symtabcmd->strsize);
1146         
1147         symtab = malloc(sizeof(EXE_SYM) * nb_syms);
1148         
1149         /* Now transform the symtab, to an extended version, with the sym size, and the C name */
1150         for(i = 0, sym = symtab, syment = symtab_std; i < nb_syms; i++, sym++, syment++) {
1151         struct nlist *sym_follow, *sym_next = 0;
1152         unsigned int j;
1153                 memset(sym, 0, sizeof(*sym));
1154                 
1155                 if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
1156             continue;
1157                         
1158                 memcpy(sym, syment, sizeof(*syment));
1159                         
1160                 /* Find the following symbol in order to get the current symbol size */
1161         for(j = 0, sym_follow = symtab_std; j < nb_syms; j++, sym_follow++) {
1162             if ( sym_follow->n_sect != 1 || sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value))
1163                 continue;
1164             if(!sym_next) {
1165                 sym_next = sym_follow;
1166                 continue;
1167             }
1168             if(!(sym_next->n_value > sym_follow->n_value))
1169                 continue;
1170             sym_next = sym_follow;
1171         }
1172                 if(sym_next)
1173             sym->st_size = sym_next->n_value - sym->st_value;
1174                 else
1175             sym->st_size = text_sec_hdr->size - sym->st_value;
1176         }
1177         
1178     /* Find Reloc */
1179     relocs = load_data(fd, text_sec_hdr->reloff, text_sec_hdr->nreloc * sizeof(struct relocation_info));
1180     nb_relocs = text_sec_hdr->nreloc;
1181
1182         close(fd);
1183         return 0;
1184 }
1185
1186 #endif /* CONFIG_FORMAT_MACH */
1187
1188 void get_reloc_expr(char *name, int name_size, const char *sym_name)
1189 {
1190     const char *p;
1191
1192     if (strstart(sym_name, "__op_param", &p)) {
1193         snprintf(name, name_size, "param%s", p);
1194     } else if (strstart(sym_name, "__op_gen_label", &p)) {
1195         snprintf(name, name_size, "gen_labels[param%s]", p);
1196     } else {
1197 #ifdef HOST_SPARC
1198         if (sym_name[0] == '.')
1199             snprintf(name, name_size,
1200                      "(long)(&__dot_%s)",
1201                      sym_name + 1);
1202         else
1203 #endif
1204             snprintf(name, name_size, "(long)(&%s)", sym_name);
1205     }
1206 }
1207
1208 #ifdef HOST_IA64
1209
1210 #define PLT_ENTRY_SIZE  16      /* 1 bundle containing "brl" */
1211
1212 struct plt_entry {
1213     struct plt_entry *next;
1214     const char *name;
1215     unsigned long addend;
1216 } *plt_list;
1217
1218 static int
1219 get_plt_index (const char *name, unsigned long addend)
1220 {
1221     struct plt_entry *plt, *prev= NULL;
1222     int index = 0;
1223
1224     /* see if we already have an entry for this target: */
1225     for (plt = plt_list; plt; ++index, prev = plt, plt = plt->next)
1226         if (strcmp(plt->name, name) == 0 && plt->addend == addend)
1227             return index;
1228
1229     /* nope; create a new PLT entry: */
1230
1231     plt = malloc(sizeof(*plt));
1232     if (!plt) {
1233         perror("malloc");
1234         exit(1);
1235     }
1236     memset(plt, 0, sizeof(*plt));
1237     plt->name = strdup(name);
1238     plt->addend = addend;
1239
1240     /* append to plt-list: */
1241     if (prev)
1242         prev->next = plt;
1243     else
1244         plt_list = plt;
1245     return index;
1246 }
1247
1248 #endif
1249
1250 #ifdef HOST_ARM
1251
1252 int arm_emit_ldr_info(const char *name, unsigned long start_offset,
1253                       FILE *outfile, uint8_t *p_start, uint8_t *p_end,
1254                       ELF_RELOC *relocs, int nb_relocs)
1255 {
1256     uint8_t *p;
1257     uint32_t insn;
1258     int offset, min_offset, pc_offset, data_size, spare, max_pool;
1259     uint8_t data_allocated[1024];
1260     unsigned int data_index;
1261     int type;
1262     
1263     memset(data_allocated, 0, sizeof(data_allocated));
1264     
1265     p = p_start;
1266     min_offset = p_end - p_start;
1267     spare = 0x7fffffff;
1268     while (p < p_start + min_offset) {
1269         insn = get32((uint32_t *)p);
1270         /* TODO: Armv5e ldrd.  */
1271         /* TODO: VFP load.  */
1272         if ((insn & 0x0d5f0000) == 0x051f0000) {
1273             /* ldr reg, [pc, #im] */
1274             offset = insn & 0xfff;
1275             if (!(insn & 0x00800000))
1276                 offset = -offset;
1277             max_pool = 4096;
1278             type = 0;
1279         } else if ((insn & 0x0e5f0f00) == 0x0c1f0100) {
1280             /* FPA ldf.  */
1281             offset = (insn & 0xff) << 2;
1282             if (!(insn & 0x00800000))
1283                 offset = -offset;
1284             max_pool = 1024;
1285             type = 1;
1286         } else if ((insn & 0x0fff0000) == 0x028f0000) {
1287             /* Some gcc load a doubleword immediate with
1288                add regN, pc, #imm
1289                ldmia regN, {regN, regM}
1290                Hope and pray the compiler never generates somethin like
1291                add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */
1292             int r;
1293
1294             r = (insn & 0xf00) >> 7;
1295             offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r));
1296             max_pool = 1024;
1297             type = 2;
1298         } else {
1299             max_pool = 0;
1300             type = -1;
1301         }
1302         if (type >= 0) {
1303             /* PC-relative load needs fixing up.  */
1304             if (spare > max_pool - offset)
1305                 spare = max_pool - offset;
1306             if ((offset & 3) !=0)
1307                 error("%s:%04x: pc offset must be 32 bit aligned", 
1308                       name, start_offset + p - p_start);
1309             if (offset < 0)
1310                 error("%s:%04x: Embedded literal value",
1311                       name, start_offset + p - p_start);
1312             pc_offset = p - p_start + offset + 8;
1313             if (pc_offset <= (p - p_start) || 
1314                 pc_offset >= (p_end - p_start))
1315                 error("%s:%04x: pc offset must point inside the function code", 
1316                       name, start_offset + p - p_start);
1317             if (pc_offset < min_offset)
1318                 min_offset = pc_offset;
1319             if (outfile) {
1320                 /* The intruction position */
1321                 fprintf(outfile, "    arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", 
1322                         p - p_start);
1323                 /* The position of the constant pool data.  */
1324                 data_index = ((p_end - p_start) - pc_offset) >> 2;
1325                 fprintf(outfile, "    arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n", 
1326                         data_index);
1327                 fprintf(outfile, "    arm_ldr_ptr->type = %d;\n", type);
1328                 fprintf(outfile, "    arm_ldr_ptr++;\n");
1329             }
1330         }
1331         p += 4;
1332     }
1333
1334     /* Copy and relocate the constant pool data.  */
1335     data_size = (p_end - p_start) - min_offset;
1336     if (data_size > 0 && outfile) {
1337         spare += min_offset;
1338         fprintf(outfile, "    arm_data_ptr -= %d;\n", data_size >> 2);
1339         fprintf(outfile, "    arm_pool_ptr -= %d;\n", data_size);
1340         fprintf(outfile, "    if (arm_pool_ptr > gen_code_ptr + %d)\n"
1341                          "        arm_pool_ptr = gen_code_ptr + %d;\n",
1342                          spare, spare);
1343
1344         data_index = 0;
1345         for (pc_offset = min_offset;
1346              pc_offset < p_end - p_start;
1347              pc_offset += 4) {
1348
1349             ELF_RELOC *rel;
1350             int i, addend, type;
1351             const char *sym_name;
1352             char relname[1024];
1353
1354             /* data value */
1355             addend = get32((uint32_t *)(p_start + pc_offset));
1356             relname[0] = '\0';
1357             for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1358                 if (rel->r_offset == (pc_offset + start_offset)) {
1359                     sym_name = get_rel_sym_name(rel);
1360                     /* the compiler leave some unnecessary references to the code */
1361                     get_reloc_expr(relname, sizeof(relname), sym_name);
1362                     type = ELF32_R_TYPE(rel->r_info);
1363                     if (type != R_ARM_ABS32)
1364                         error("%s: unsupported data relocation", name);
1365                     break;
1366                 }
1367             }
1368             fprintf(outfile, "    arm_data_ptr[%d] = 0x%x",
1369                     data_index, addend);
1370             if (relname[0] != '\0')
1371                 fprintf(outfile, " + %s", relname);
1372             fprintf(outfile, ";\n");
1373
1374             data_index++;
1375         }
1376     }
1377
1378     if (p == p_start)
1379         goto arm_ret_error;
1380     p -= 4;
1381     insn = get32((uint32_t *)p);
1382     /* The last instruction must be an ldm instruction.  There are several
1383        forms generated by gcc:
1384         ldmib sp, {..., pc}  (implies a sp adjustment of +4)
1385         ldmia sp, {..., pc}
1386         ldmea fp, {..., pc} */
1387     if ((insn & 0xffff8000) == 0xe99d8000) {
1388         if (outfile) {
1389             fprintf(outfile,
1390                     "    *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n",
1391                     p - p_start);
1392         }
1393         p += 4;
1394     } else if ((insn & 0xffff8000) != 0xe89d8000
1395         && (insn & 0xffff8000) != 0xe91b8000) {
1396     arm_ret_error:
1397         if (!outfile)
1398             printf("%s: invalid epilog\n", name);
1399     }
1400     return p - p_start;
1401 }
1402 #endif
1403
1404
1405 #define MAX_ARGS 3
1406
1407 /* generate op code */
1408 void gen_code(const char *name, host_ulong offset, host_ulong size, 
1409               FILE *outfile, int gen_switch)
1410 {
1411     int copy_size = 0;
1412     uint8_t *p_start, *p_end;
1413     host_ulong start_offset;
1414     int nb_args, i, n;
1415     uint8_t args_present[MAX_ARGS];
1416     const char *sym_name, *p;
1417     EXE_RELOC *rel;
1418
1419     /* Compute exact size excluding prologue and epilogue instructions.
1420      * Increment start_offset to skip epilogue instructions, then compute
1421      * copy_size the indicate the size of the remaining instructions (in
1422      * bytes).
1423      */
1424     p_start = text + offset;
1425     p_end = p_start + size;
1426     start_offset = offset;
1427 #if defined(HOST_I386) || defined(HOST_X86_64)
1428 #ifdef CONFIG_FORMAT_COFF
1429     {
1430         uint8_t *p;
1431         p = p_end - 1;
1432         if (p == p_start)
1433             error("empty code for %s", name);
1434         while (*p != 0xc3) {
1435             p--;
1436             if (p <= p_start)
1437                 error("ret or jmp expected at the end of %s", name);
1438         }
1439         copy_size = p - p_start;
1440     }
1441 #else
1442     {
1443         int len;
1444         len = p_end - p_start;
1445         if (len == 0)
1446             error("empty code for %s", name);
1447         if (p_end[-1] == 0xc3) {
1448             len--;
1449         } else {
1450             error("ret or jmp expected at the end of %s", name);
1451         }
1452         copy_size = len;
1453     }
1454 #endif    
1455 #elif defined(HOST_PPC)
1456     {
1457         uint8_t *p;
1458         p = (void *)(p_end - 4);
1459         if (p == p_start)
1460             error("empty code for %s", name);
1461         if (get32((uint32_t *)p) != 0x4e800020)
1462             error("blr expected at the end of %s", name);
1463         copy_size = p - p_start;
1464     }
1465 #elif defined(HOST_S390)
1466     {
1467         uint8_t *p;
1468         p = (void *)(p_end - 2);
1469         if (p == p_start)
1470             error("empty code for %s", name);
1471         if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
1472             error("br %%r14 expected at the end of %s", name);
1473         copy_size = p - p_start;
1474     }
1475 #elif defined(HOST_ALPHA)
1476     {
1477         uint8_t *p;
1478         p = p_end - 4;
1479 #if 0
1480         /* XXX: check why it occurs */
1481         if (p == p_start)
1482             error("empty code for %s", name);
1483 #endif
1484         if (get32((uint32_t *)p) != 0x6bfa8001)
1485             error("ret expected at the end of %s", name);
1486         copy_size = p - p_start;            
1487     }
1488 #elif defined(HOST_IA64)
1489     {
1490         uint8_t *p;
1491         p = (void *)(p_end - 4);
1492         if (p == p_start)
1493             error("empty code for %s", name);
1494         /* br.ret.sptk.many b0;; */
1495         /* 08 00 84 00 */
1496         if (get32((uint32_t *)p) != 0x00840008)
1497             error("br.ret.sptk.many b0;; expected at the end of %s", name);
1498         copy_size = p_end - p_start;
1499     }
1500 #elif defined(HOST_SPARC)
1501     {
1502 #define INSN_SAVE       0x9de3a000
1503 #define INSN_RET        0x81c7e008
1504 #define INSN_RETL       0x81c3e008
1505 #define INSN_RESTORE    0x81e80000
1506 #define INSN_RETURN     0x81cfe008
1507 #define INSN_NOP        0x01000000
1508 #define INSN_ADD_SP     0x9c03a000 // add %sp, nn, %sp
1509 #define INSN_SUB_SP     0x9c23a000 // sub %sp, nn, %sp
1510
1511         uint32_t start_insn, end_insn1, end_insn2;
1512         uint8_t *p;
1513         p = (void *)(p_end - 8);
1514         if (p <= p_start)
1515             error("empty code for %s", name);
1516         start_insn = get32((uint32_t *)(p_start + 0x0));
1517         end_insn1 = get32((uint32_t *)(p + 0x0));
1518         end_insn2 = get32((uint32_t *)(p + 0x4));
1519         if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1520             (start_insn & ~0x1fff) == INSN_ADD_SP) {
1521             p_start += 0x4;
1522             start_offset += 0x4;
1523             if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
1524                 /* SPARC v7: ret; restore; */ ;
1525             else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
1526                 /* SPARC v9: return; nop; */ ;
1527             else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
1528                 /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
1529             else
1530
1531                 error("ret; restore; not found at end of %s", name);
1532         } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1533             ;
1534         } else {
1535             error("No save at the beginning of %s", name);
1536         }
1537 #if 0
1538         /* Skip a preceeding nop, if present.  */
1539         if (p > p_start) {
1540             skip_insn = get32((uint32_t *)(p - 0x4));
1541             if (skip_insn == INSN_NOP)
1542                 p -= 4;
1543         }
1544 #endif
1545         copy_size = p - p_start;
1546     }
1547 #elif defined(HOST_SPARC64)
1548     {
1549 #define INSN_SAVE       0x9de3a000
1550 #define INSN_RET        0x81c7e008
1551 #define INSN_RETL       0x81c3e008
1552 #define INSN_RESTORE    0x81e80000
1553 #define INSN_RETURN     0x81cfe008
1554 #define INSN_NOP        0x01000000
1555 #define INSN_ADD_SP     0x9c03a000 // add %sp, nn, %sp
1556 #define INSN_SUB_SP     0x9c23a000 // sub %sp, nn, %sp
1557
1558         uint32_t start_insn, end_insn1, end_insn2, skip_insn;
1559         uint8_t *p;
1560         p = (void *)(p_end - 8);
1561 #if 0
1562         /* XXX: check why it occurs */
1563         if (p <= p_start)
1564             error("empty code for %s", name);
1565 #endif
1566         start_insn = get32((uint32_t *)(p_start + 0x0));
1567         end_insn1 = get32((uint32_t *)(p + 0x0));
1568         end_insn2 = get32((uint32_t *)(p + 0x4));
1569         if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1570             (start_insn & ~0x1fff) == INSN_ADD_SP) {
1571             p_start += 0x4;
1572             start_offset += 0x4;
1573             if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
1574                 /* SPARC v7: ret; restore; */ ;
1575             else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
1576                 /* SPARC v9: return; nop; */ ;
1577             else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
1578                 /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
1579             else
1580
1581                 error("ret; restore; not found at end of %s", name);
1582         } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1583             ;
1584         } else {
1585             error("No save at the beginning of %s", name);
1586         }
1587         
1588         /* Skip a preceeding nop, if present.  */
1589         if (p > p_start) {
1590             skip_insn = get32((uint32_t *)(p - 0x4));
1591             if (skip_insn == 0x01000000)
1592                 p -= 4;
1593         }
1594         
1595         copy_size = p - p_start;
1596     }
1597 #elif defined(HOST_ARM)
1598     {
1599         uint32_t insn;
1600
1601         if ((p_end - p_start) <= 16)
1602             error("%s: function too small", name);
1603         if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
1604             (get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 ||
1605             get32((uint32_t *)(p_start + 8)) != 0xe24cb004)
1606             error("%s: invalid prolog", name);
1607         p_start += 12;
1608         start_offset += 12;
1609         insn = get32((uint32_t *)p_start);
1610         if ((insn & 0xffffff00) == 0xe24dd000) {
1611             /* Stack adjustment.  Assume op uses the frame pointer.  */
1612             p_start -= 4;
1613             start_offset -= 4;
1614         }
1615         copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, 
1616                                       relocs, nb_relocs);
1617     }
1618 #elif defined(HOST_M68K)
1619     {
1620         uint8_t *p;
1621         p = (void *)(p_end - 2);
1622         if (p == p_start)
1623             error("empty code for %s", name);
1624         // remove NOP's, probably added for alignment
1625         while ((get16((uint16_t *)p) == 0x4e71) &&
1626                (p>p_start)) 
1627             p -= 2;
1628         if (get16((uint16_t *)p) != 0x4e75)
1629             error("rts expected at the end of %s", name);
1630         copy_size = p - p_start;
1631     }
1632 #else
1633 #error unsupported CPU
1634 #endif
1635
1636     /* compute the number of arguments by looking at the relocations */
1637     for(i = 0;i < MAX_ARGS; i++)
1638         args_present[i] = 0;
1639
1640     for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1641         host_ulong offset = get_rel_offset(rel);
1642         if (offset >= start_offset &&
1643             offset < start_offset + (p_end - p_start)) {
1644             sym_name = get_rel_sym_name(rel);
1645             if(!sym_name)
1646                 continue;
1647             if (strstart(sym_name, "__op_param", &p) ||
1648                 strstart(sym_name, "__op_gen_label", &p)) {
1649                 n = strtoul(p, NULL, 10);
1650                 if (n > MAX_ARGS)
1651                     error("too many arguments in %s", name);
1652                 args_present[n - 1] = 1;
1653             }
1654         }
1655     }
1656     
1657     nb_args = 0;
1658     while (nb_args < MAX_ARGS && args_present[nb_args])
1659         nb_args++;
1660     for(i = nb_args; i < MAX_ARGS; i++) {
1661         if (args_present[i])
1662             error("inconsistent argument numbering in %s", name);
1663     }
1664
1665     if (gen_switch == 2) {
1666         fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
1667     } else if (gen_switch == 1) {
1668
1669         /* output C code */
1670         fprintf(outfile, "case INDEX_%s: {\n", name);
1671         if (nb_args > 0) {
1672             fprintf(outfile, "    long ");
1673             for(i = 0; i < nb_args; i++) {
1674                 if (i != 0)
1675                     fprintf(outfile, ", ");
1676                 fprintf(outfile, "param%d", i + 1);
1677             }
1678             fprintf(outfile, ";\n");
1679         }
1680 #if defined(HOST_IA64)
1681         fprintf(outfile, "    extern char %s;\n", name);
1682 #else
1683         fprintf(outfile, "    extern void %s();\n", name);
1684 #endif
1685
1686         for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1687             host_ulong offset = get_rel_offset(rel);
1688             if (offset >= start_offset &&
1689                 offset < start_offset + (p_end - p_start)) {
1690                 sym_name = get_rel_sym_name(rel);
1691                 if(!sym_name)
1692                     continue;
1693                 if (*sym_name && 
1694                     !strstart(sym_name, "__op_param", NULL) &&
1695                     !strstart(sym_name, "__op_jmp", NULL) &&
1696                     !strstart(sym_name, "__op_gen_label", NULL)) {
1697 #if defined(HOST_SPARC)
1698                     if (sym_name[0] == '.') {
1699                         fprintf(outfile,
1700                                 "extern char __dot_%s __asm__(\"%s\");\n",
1701                                 sym_name+1, sym_name);
1702                         continue;
1703                     }
1704 #endif
1705 #if defined(__APPLE__)
1706 /* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */
1707                     fprintf(outfile, "extern char %s __attribute__((unused));\n", sym_name);
1708 #elif defined(HOST_IA64)
1709                         if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
1710                                 /*
1711                                  * PCREL21 br.call targets generally
1712                                  * are out of range and need to go
1713                                  * through an "import stub".
1714                                  */
1715                                 fprintf(outfile, "    extern char %s;\n",
1716                                         sym_name);
1717 #else
1718                     fprintf(outfile, "extern char %s;\n", sym_name);
1719 #endif
1720                 }
1721             }
1722         }
1723
1724         fprintf(outfile, "    memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n",
1725                                         name, (int)(start_offset - offset), copy_size);
1726
1727         /* emit code offset information */
1728         {
1729             EXE_SYM *sym;
1730             const char *sym_name, *p;
1731             unsigned long val;
1732             int n;
1733
1734             for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
1735                 sym_name = get_sym_name(sym);
1736                 if (strstart(sym_name, "__op_label", &p)) {
1737                     uint8_t *ptr;
1738                     unsigned long offset;
1739                     
1740                     /* test if the variable refers to a label inside
1741                        the code we are generating */
1742 #ifdef CONFIG_FORMAT_COFF
1743                     if (sym->st_shndx == text_shndx) {
1744                         ptr = sdata[coff_text_shndx];
1745                     } else if (sym->st_shndx == data_shndx) {
1746                         ptr = sdata[coff_data_shndx];
1747                     } else {
1748                         ptr = NULL;
1749                     }
1750 #elif defined(CONFIG_FORMAT_MACH)
1751                     if(!sym->n_sect)
1752                         continue;
1753                     ptr = sdata[sym->n_sect-1];
1754 #else
1755                     ptr = sdata[sym->st_shndx];
1756 #endif
1757                     if (!ptr)
1758                         error("__op_labelN in invalid section");
1759                     offset = sym->st_value;
1760 #ifdef CONFIG_FORMAT_MACH
1761                     offset -= section_hdr[sym->n_sect-1].addr;
1762 #endif
1763                     val = *(unsigned long *)(ptr + offset);
1764 #ifdef ELF_USES_RELOCA
1765                     {
1766                         int reloc_shndx, nb_relocs1, j;
1767
1768                         /* try to find a matching relocation */
1769                         reloc_shndx = find_reloc(sym->st_shndx);
1770                         if (reloc_shndx) {
1771                             nb_relocs1 = shdr[reloc_shndx].sh_size / 
1772                                 shdr[reloc_shndx].sh_entsize;
1773                             rel = (ELF_RELOC *)sdata[reloc_shndx];
1774                             for(j = 0; j < nb_relocs1; j++) {
1775                                 if (rel->r_offset == offset) {
1776                                     val = rel->r_addend;
1777                                     break;
1778                                 }
1779                                 rel++;
1780                             }
1781                         }
1782                     }
1783 #endif                    
1784                     if (val >= start_offset && val <= start_offset + copy_size) {
1785                         n = strtol(p, NULL, 10);
1786                         fprintf(outfile, "    label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset));
1787                     }
1788                 }
1789             }
1790         }
1791
1792         /* load parameres in variables */
1793         for(i = 0; i < nb_args; i++) {
1794             fprintf(outfile, "    param%d = *opparam_ptr++;\n", i + 1);
1795         }
1796
1797         /* patch relocations */
1798 #if defined(HOST_I386)
1799             {
1800                 char name[256];
1801                 int type;
1802                 int addend;
1803                 int reloc_offset;
1804                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1805                 if (rel->r_offset >= start_offset &&
1806                     rel->r_offset < start_offset + copy_size) {
1807                     sym_name = get_rel_sym_name(rel);
1808                     if (!sym_name)
1809                         continue;
1810                     reloc_offset = rel->r_offset - start_offset;
1811                     if (strstart(sym_name, "__op_jmp", &p)) {
1812                         int n;
1813                         n = strtol(p, NULL, 10);
1814                         /* __op_jmp relocations are done at
1815                            runtime to do translated block
1816                            chaining: the offset of the instruction
1817                            needs to be stored */
1818                         fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
1819                                 n, reloc_offset);
1820                         continue;
1821                     }
1822
1823                     get_reloc_expr(name, sizeof(name), sym_name);
1824                     addend = get32((uint32_t *)(text + rel->r_offset));
1825 #ifdef CONFIG_FORMAT_ELF
1826                     type = ELF32_R_TYPE(rel->r_info);
1827                     switch(type) {
1828                     case R_386_32:
1829                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
1830                                 reloc_offset, name, addend);
1831                         break;
1832                     case R_386_PC32:
1833                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", 
1834                                 reloc_offset, name, reloc_offset, addend);
1835                         break;
1836                     default:
1837                         error("unsupported i386 relocation (%d)", type);
1838                     }
1839 #elif defined(CONFIG_FORMAT_COFF)
1840                     {
1841                         char *temp_name;
1842                         int j;
1843                         EXE_SYM *sym;
1844                         temp_name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
1845                         if (!strcmp(temp_name, ".data")) {
1846                             for (j = 0, sym = symtab; j < nb_syms; j++, sym++) {
1847                                 if (strstart(sym->st_name, sym_name, NULL)) {
1848                                     addend -= sym->st_value;
1849                                 }
1850                             }
1851                         }
1852                     }
1853                     type = rel->r_type;
1854                     switch(type) {
1855                     case DIR32:
1856                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
1857                                 reloc_offset, name, addend);
1858                         break;
1859                     case DISP32:
1860                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", 
1861                                 reloc_offset, name, reloc_offset, addend);
1862                         break;
1863                     default:
1864                         error("unsupported i386 relocation (%d)", type);
1865                     }
1866 #else
1867 #error unsupport object format
1868 #endif
1869                 }
1870                 }
1871             }
1872 #elif defined(HOST_X86_64)
1873             {
1874                 char name[256];
1875                 int type;
1876                 int addend;
1877                 int reloc_offset;
1878                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1879                 if (rel->r_offset >= start_offset &&
1880                     rel->r_offset < start_offset + copy_size) {
1881                     sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1882                     get_reloc_expr(name, sizeof(name), sym_name);
1883                     type = ELF32_R_TYPE(rel->r_info);
1884                     addend = rel->r_addend;
1885                     reloc_offset = rel->r_offset - start_offset;
1886                     switch(type) {
1887                     case R_X86_64_32:
1888                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n", 
1889                                 reloc_offset, name, addend);
1890                         break;
1891                     case R_X86_64_32S:
1892                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", 
1893                                 reloc_offset, name, addend);
1894                         break;
1895                     case R_X86_64_PC32:
1896                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", 
1897                                 reloc_offset, name, reloc_offset, addend);
1898                         break;
1899                     default:
1900                         error("unsupported X86_64 relocation (%d)", type);
1901                     }
1902                 }
1903                 }
1904             }
1905 #elif defined(HOST_PPC)
1906             {
1907 #ifdef CONFIG_FORMAT_ELF
1908                 char name[256];
1909                 int type;
1910                 int addend;
1911                 int reloc_offset;
1912                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1913                     if (rel->r_offset >= start_offset &&
1914                         rel->r_offset < start_offset + copy_size) {
1915                         sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1916                         reloc_offset = rel->r_offset - start_offset;
1917                         if (strstart(sym_name, "__op_jmp", &p)) {
1918                             int n;
1919                             n = strtol(p, NULL, 10);
1920                             /* __op_jmp relocations are done at
1921                                runtime to do translated block
1922                                chaining: the offset of the instruction
1923                                needs to be stored */
1924                             fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
1925                                     n, reloc_offset);
1926                             continue;
1927                         }
1928                         
1929                         get_reloc_expr(name, sizeof(name), sym_name);
1930                         type = ELF32_R_TYPE(rel->r_info);
1931                         addend = rel->r_addend;
1932                         switch(type) {
1933                         case R_PPC_ADDR32:
1934                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
1935                                     reloc_offset, name, addend);
1936                             break;
1937                         case R_PPC_ADDR16_LO:
1938                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", 
1939                                     reloc_offset, name, addend);
1940                             break;
1941                         case R_PPC_ADDR16_HI:
1942                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", 
1943                                     reloc_offset, name, addend);
1944                             break;
1945                         case R_PPC_ADDR16_HA:
1946                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", 
1947                                     reloc_offset, name, addend);
1948                             break;
1949                         case R_PPC_REL24:
1950                             /* warning: must be at 32 MB distancy */
1951                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n", 
1952                                     reloc_offset, reloc_offset, name, reloc_offset, addend);
1953                             break;
1954                         default:
1955                             error("unsupported powerpc relocation (%d)", type);
1956                         }
1957                     }
1958                 }
1959 #elif defined(CONFIG_FORMAT_MACH)
1960                                 struct scattered_relocation_info *scarel;
1961                                 struct relocation_info * rel;
1962                                 char final_sym_name[256];
1963                                 const char *sym_name;
1964                                 const char *p;
1965                                 int slide, sslide;
1966                                 int i;
1967         
1968                                 for(i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
1969                                         unsigned int offset, length, value = 0;
1970                                         unsigned int type, pcrel, isym = 0;
1971                                         unsigned int usesym = 0;
1972                                 
1973                                         if(R_SCATTERED & rel->r_address) {
1974                                                 scarel = (struct scattered_relocation_info*)rel;
1975                                                 offset = (unsigned int)scarel->r_address;
1976                                                 length = scarel->r_length;
1977                                                 pcrel = scarel->r_pcrel;
1978                                                 type = scarel->r_type;
1979                                                 value = scarel->r_value;
1980                                         } else {
1981                                                 value = isym = rel->r_symbolnum;
1982                                                 usesym = (rel->r_extern);
1983                                                 offset = rel->r_address;
1984                                                 length = rel->r_length;
1985                                                 pcrel = rel->r_pcrel;
1986                                                 type = rel->r_type;
1987                                         }
1988                                 
1989                                         slide = offset - start_offset;
1990                 
1991                                         if (!(offset >= start_offset && offset < start_offset + size)) 
1992                                                 continue;  /* not in our range */
1993
1994                                         sym_name = get_reloc_name(rel, &sslide);
1995                                         
1996                                         if(usesym && symtab[isym].n_type & N_STAB)
1997                                                 continue; /* don't handle STAB (debug sym) */
1998                                         
1999                                         if (sym_name && strstart(sym_name, "__op_jmp", &p)) {
2000                                                 int n;
2001                                                 n = strtol(p, NULL, 10);
2002                                                 fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
2003                                                         n, slide);
2004                                                 continue; /* Nothing more to do */
2005                                         }
2006                                         
2007                                         if(!sym_name)
2008                                         {
2009                                                 fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n",
2010                                                            name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type);
2011                                                 continue; /* dunno how to handle without final_sym_name */
2012                                         }
2013                                                                                                            
2014                                         get_reloc_expr(final_sym_name, sizeof(final_sym_name), 
2015                                                        sym_name);
2016                                         switch(type) {
2017                                         case PPC_RELOC_BR24:
2018                                             if (!strstart(sym_name,"__op_gen_label",&p)) {
2019                                                 fprintf(outfile, "{\n");
2020                                                 fprintf(outfile, "    uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
2021                                                 fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n", 
2022                                                                                         slide, slide, name, sslide );
2023                                                 fprintf(outfile, "}\n");
2024                                         } else {
2025                                                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
2026                                                                                         slide, slide, final_sym_name, slide);
2027                                         }
2028                                                 break;
2029                                         case PPC_RELOC_HI16:
2030                                                 fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n", 
2031                                                         slide, final_sym_name, sslide);
2032                                                 break;
2033                                         case PPC_RELOC_LO16:
2034                                                 fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n", 
2035                                         slide, final_sym_name, sslide);
2036                             break;
2037                                         case PPC_RELOC_HA16:
2038                                                 fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n", 
2039                                                         slide, final_sym_name, sslide);
2040                                                 break;
2041                                 default:
2042                                         error("unsupported powerpc relocation (%d)", type);
2043                                 }
2044                         }
2045 #else
2046 #error unsupport object format
2047 #endif
2048             }
2049 #elif defined(HOST_S390)
2050             {
2051                 char name[256];
2052                 int type;
2053                 int addend;
2054                 int reloc_offset;
2055                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2056                     if (rel->r_offset >= start_offset &&
2057                         rel->r_offset < start_offset + copy_size) {
2058                         sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2059                         get_reloc_expr(name, sizeof(name), sym_name);
2060                         type = ELF32_R_TYPE(rel->r_info);
2061                         addend = rel->r_addend;
2062                         reloc_offset = rel->r_offset - start_offset;
2063                         switch(type) {
2064                         case R_390_32:
2065                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
2066                                     reloc_offset, name, addend);
2067                             break;
2068                         case R_390_16:
2069                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", 
2070                                     reloc_offset, name, addend);
2071                             break;
2072                         case R_390_8:
2073                             fprintf(outfile, "    *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", 
2074                                     reloc_offset, name, addend);
2075                             break;
2076                         default:
2077                             error("unsupported s390 relocation (%d)", type);
2078                         }
2079                     }
2080                 }
2081             }
2082 #elif defined(HOST_ALPHA)
2083             {
2084                 for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
2085                     if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
2086                         int type;
2087                         long reloc_offset;
2088
2089                         type = ELF64_R_TYPE(rel->r_info);
2090                         sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
2091                         reloc_offset = rel->r_offset - start_offset;
2092                         switch (type) {
2093                         case R_ALPHA_GPDISP:
2094                             /* The gp is just 32 bit, and never changes, so it's easiest to emit it
2095                                as an immediate instead of constructing it from the pv or ra.  */
2096                             fprintf(outfile, "    immediate_ldah(gen_code_ptr + %ld, gp);\n",
2097                                     reloc_offset);
2098                             fprintf(outfile, "    immediate_lda(gen_code_ptr + %ld, gp);\n",
2099                                     reloc_offset + (int)rel->r_addend);
2100                             break;
2101                         case R_ALPHA_LITUSE:
2102                             /* jsr to literal hint. Could be used to optimize to bsr. Ignore for
2103                                now, since some called functions (libc) need pv to be set up.  */
2104                             break;
2105                         case R_ALPHA_HINT:
2106                             /* Branch target prediction hint. Ignore for now.  Should be already
2107                                correct for in-function jumps.  */
2108                             break;
2109                         case R_ALPHA_LITERAL:
2110                             /* Load a literal from the GOT relative to the gp.  Since there's only a
2111                                single gp, nothing is to be done.  */
2112                             break;
2113                         case R_ALPHA_GPRELHIGH:
2114                             /* Handle fake relocations against __op_param symbol.  Need to emit the
2115                                high part of the immediate value instead.  Other symbols need no
2116                                special treatment.  */
2117                             if (strstart(sym_name, "__op_param", &p))
2118                                 fprintf(outfile, "    immediate_ldah(gen_code_ptr + %ld, param%s);\n",
2119                                         reloc_offset, p);
2120                             break;
2121                         case R_ALPHA_GPRELLOW:
2122                             if (strstart(sym_name, "__op_param", &p))
2123                                 fprintf(outfile, "    immediate_lda(gen_code_ptr + %ld, param%s);\n",
2124                                         reloc_offset, p);
2125                             break;
2126                         case R_ALPHA_BRSGP:
2127                             /* PC-relative jump. Tweak offset to skip the two instructions that try to
2128                                set up the gp from the pv.  */
2129                             fprintf(outfile, "    fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
2130                                     reloc_offset, sym_name, reloc_offset);
2131                             break;
2132                         default:
2133                             error("unsupported Alpha relocation (%d)", type);
2134                         }
2135                     }
2136                 }
2137             }
2138 #elif defined(HOST_IA64)
2139             {
2140                 unsigned long sym_idx;
2141                 long code_offset;
2142                 char name[256];
2143                 int type;
2144                 long addend;
2145
2146                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2147                     sym_idx = ELF64_R_SYM(rel->r_info);
2148                     if (rel->r_offset < start_offset
2149                         || rel->r_offset >= start_offset + copy_size)
2150                         continue;
2151                     sym_name = (strtab + symtab[sym_idx].st_name);
2152                     code_offset = rel->r_offset - start_offset;
2153                     if (strstart(sym_name, "__op_jmp", &p)) {
2154                         int n;
2155                         n = strtol(p, NULL, 10);
2156                         /* __op_jmp relocations are done at
2157                            runtime to do translated block
2158                            chaining: the offset of the instruction
2159                            needs to be stored */
2160                         fprintf(outfile, "    jmp_offsets[%d] ="
2161                                 "%ld + (gen_code_ptr - gen_code_buf);\n",
2162                                 n, code_offset);
2163                         continue;
2164                     }
2165                     get_reloc_expr(name, sizeof(name), sym_name);
2166                     type = ELF64_R_TYPE(rel->r_info);
2167                     addend = rel->r_addend;
2168                     switch(type) {
2169                       case R_IA64_IMM64:
2170                           fprintf(outfile,
2171                                   "    ia64_imm64(gen_code_ptr + %ld, "
2172                                   "%s + %ld);\n",
2173                                   code_offset, name, addend);
2174                           break;
2175                       case R_IA64_LTOFF22X:
2176                       case R_IA64_LTOFF22:
2177                           fprintf(outfile, "    IA64_LTOFF(gen_code_ptr + %ld,"
2178                                   " %s + %ld, %d);\n",
2179                                   code_offset, name, addend,
2180                                   (type == R_IA64_LTOFF22X));
2181                           break;
2182                       case R_IA64_LDXMOV:
2183                           fprintf(outfile,
2184                                   "    ia64_ldxmov(gen_code_ptr + %ld,"
2185                                   " %s + %ld);\n", code_offset, name, addend);
2186                           break;
2187
2188                       case R_IA64_PCREL21B:
2189                           if (strstart(sym_name, "__op_gen_label", NULL)) {
2190                               fprintf(outfile,
2191                                       "    ia64_imm21b(gen_code_ptr + %ld,"
2192                                       " (long) (%s + %ld -\n\t\t"
2193                                       "((long) gen_code_ptr + %ld)) >> 4);\n",
2194                                       code_offset, name, addend,
2195                                       code_offset & ~0xfUL);
2196                           } else {
2197                               fprintf(outfile,
2198                                       "    IA64_PLT(gen_code_ptr + %ld, "
2199                                       "%d);\t/* %s + %ld */\n",
2200                                       code_offset,
2201                                       get_plt_index(sym_name, addend),
2202                                       sym_name, addend);
2203                           }
2204                           break;
2205                       default:
2206                           error("unsupported ia64 relocation (0x%x)",
2207                                 type);
2208                     }
2209                 }
2210                 fprintf(outfile, "    ia64_nop_b(gen_code_ptr + %d);\n",
2211                         copy_size - 16 + 2);
2212             }
2213 #elif defined(HOST_SPARC)
2214             {
2215                 char name[256];
2216                 int type;
2217                 int addend;
2218                 int reloc_offset;
2219                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2220                     if (rel->r_offset >= start_offset &&
2221                         rel->r_offset < start_offset + copy_size) {
2222                         sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
2223                         get_reloc_expr(name, sizeof(name), sym_name);
2224                         type = ELF32_R_TYPE(rel->r_info);
2225                         addend = rel->r_addend;
2226                         reloc_offset = rel->r_offset - start_offset;
2227                         switch(type) {
2228                         case R_SPARC_32:
2229                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
2230                                     reloc_offset, name, addend);
2231                             break;
2232                         case R_SPARC_HI22:
2233                             fprintf(outfile,
2234                                     "    *(uint32_t *)(gen_code_ptr + %d) = "
2235                                     "((*(uint32_t *)(gen_code_ptr + %d)) "
2236                                     " & ~0x3fffff) "
2237                                     " | (((%s + %d) >> 10) & 0x3fffff);\n",
2238                                     reloc_offset, reloc_offset, name, addend);
2239                             break;
2240                         case R_SPARC_LO10:
2241                             fprintf(outfile,
2242                                     "    *(uint32_t *)(gen_code_ptr + %d) = "
2243                                     "((*(uint32_t *)(gen_code_ptr + %d)) "
2244                                     " & ~0x3ff) "
2245                                     " | ((%s + %d) & 0x3ff);\n",
2246                                     reloc_offset, reloc_offset, name, addend);
2247                             break;
2248                         case R_SPARC_WDISP30:
2249                             fprintf(outfile,
2250                                     "    *(uint32_t *)(gen_code_ptr + %d) = "
2251                                     "((*(uint32_t *)(gen_code_ptr + %d)) "
2252                                     " & ~0x3fffffff) "
2253                                     " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2254                                     "    & 0x3fffffff);\n",
2255                                     reloc_offset, reloc_offset, name, addend,
2256                                     reloc_offset);
2257                             break;
2258                         case R_SPARC_WDISP22:
2259                             fprintf(outfile,
2260                                     "    *(uint32_t *)(gen_code_ptr + %d) = "
2261                                     "((*(uint32_t *)(gen_code_ptr + %d)) "
2262                                     " & ~0x3fffff) "
2263                                     " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2264                                     "    & 0x3fffff);\n",
2265                                     rel->r_offset - start_offset,
2266                                     rel->r_offset - start_offset,
2267                                     name, addend,
2268                                     rel->r_offset - start_offset);
2269                             break;
2270                         default:
2271                             error("unsupported sparc relocation (%d)", type);
2272                         }
2273                     }
2274                 }
2275             }
2276 #elif defined(HOST_SPARC64)
2277             {
2278                 char name[256];
2279                 int type;
2280                 int addend;
2281                 int reloc_offset;
2282                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2283                     if (rel->r_offset >= start_offset &&
2284                         rel->r_offset < start_offset + copy_size) {
2285                         sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
2286                         get_reloc_expr(name, sizeof(name), sym_name);
2287                         type = ELF32_R_TYPE(rel->r_info);
2288                         addend = rel->r_addend;
2289                         reloc_offset = rel->r_offset - start_offset;
2290                         switch(type) {
2291                         case R_SPARC_32:
2292                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2293                                     reloc_offset, name, addend);
2294                             break;
2295                         case R_SPARC_HI22:
2296                             fprintf(outfile,
2297                                     "    *(uint32_t *)(gen_code_ptr + %d) = "
2298                                     "((*(uint32_t *)(gen_code_ptr + %d)) "
2299                                     " & ~0x3fffff) "
2300                                     " | (((%s + %d) >> 10) & 0x3fffff);\n",
2301                                     reloc_offset, reloc_offset, name, addend);
2302                             break;
2303                         case R_SPARC_LO10:
2304                             fprintf(outfile,
2305                                     "    *(uint32_t *)(gen_code_ptr + %d) = "
2306                                     "((*(uint32_t *)(gen_code_ptr + %d)) "
2307                                     " & ~0x3ff) "
2308                                     " | ((%s + %d) & 0x3ff);\n",
2309                                     reloc_offset, reloc_offset, name, addend);
2310                             break;
2311                         case R_SPARC_OLO10:
2312                             addend += ELF64_R_TYPE_DATA (rel->r_info);
2313                             fprintf(outfile,
2314                                     "    *(uint32_t *)(gen_code_ptr + %d) = "
2315                                     "((*(uint32_t *)(gen_code_ptr + %d)) "
2316                                     " & ~0x3ff) "
2317                                     " | ((%s + %d) & 0x3ff);\n",
2318                                     reloc_offset, reloc_offset, name, addend);
2319                             break;
2320                         case R_SPARC_WDISP30:
2321                             fprintf(outfile,
2322                                     "    *(uint32_t *)(gen_code_ptr + %d) = "
2323                                     "((*(uint32_t *)(gen_code_ptr + %d)) "
2324                                     " & ~0x3fffffff) "
2325                                     " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2326                                     "    & 0x3fffffff);\n",
2327                                     reloc_offset, reloc_offset, name, addend,
2328                                     reloc_offset);
2329                             break;
2330                         case R_SPARC_WDISP22:
2331                             fprintf(outfile,
2332                                     "    *(uint32_t *)(gen_code_ptr + %d) = "
2333                                     "((*(uint32_t *)(gen_code_ptr + %d)) "
2334                                     " & ~0x3fffff) "
2335                                     " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2336                                     "    & 0x3fffff);\n",
2337                                     reloc_offset, reloc_offset, name, addend,
2338                                     reloc_offset);
2339                             break;
2340                         default:
2341                             error("unsupported sparc64 relocation (%d) for symbol %s", type, name);
2342                         }
2343                     }
2344                 }
2345             }
2346 #elif defined(HOST_ARM)
2347             {
2348                 char name[256];
2349                 int type;
2350                 int addend;
2351                 int reloc_offset;
2352                 uint32_t insn;
2353
2354                 insn = get32((uint32_t *)(p_start + 4));
2355                 /* If prologue ends in sub sp, sp, #const then assume
2356                    op has a stack frame and needs the frame pointer.  */
2357                 if ((insn & 0xffffff00) == 0xe24dd000) {
2358                     int i;
2359                     uint32_t opcode;
2360                     opcode = 0xe28db000; /* add fp, sp, #0.  */
2361 #if 0
2362 /* ??? Need to undo the extra stack adjustment at the end of the op.
2363    For now just leave the stack misaligned and hope it doesn't break anything
2364    too important.  */
2365                     if ((insn & 4) != 0) {
2366                         /* Preserve doubleword stack alignment.  */
2367                         fprintf(outfile,
2368                                 "    *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n",
2369                                 insn + 4);
2370                         opcode -= 4;
2371                     }
2372 #endif
2373                     insn = get32((uint32_t *)(p_start - 4));
2374                     /* Calculate the size of the saved registers,
2375                        excluding pc.  */
2376                     for (i = 0; i < 15; i++) {
2377                         if (insn & (1 << i))
2378                             opcode += 4;
2379                     }
2380                     fprintf(outfile,
2381                             "    *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
2382                 }
2383                 arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
2384                                   relocs, nb_relocs);
2385
2386                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2387                 if (rel->r_offset >= start_offset &&
2388                     rel->r_offset < start_offset + copy_size) {
2389                     sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2390                     /* the compiler leave some unnecessary references to the code */
2391                     if (sym_name[0] == '\0')
2392                         continue;
2393                     get_reloc_expr(name, sizeof(name), sym_name);
2394                     type = ELF32_R_TYPE(rel->r_info);
2395                     addend = get32((uint32_t *)(text + rel->r_offset));
2396                     reloc_offset = rel->r_offset - start_offset;
2397                     switch(type) {
2398                     case R_ARM_ABS32:
2399                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
2400                                 reloc_offset, name, addend);
2401                         break;
2402                     case R_ARM_PC24:
2403                     case R_ARM_JUMP24:
2404                     case R_ARM_CALL:
2405                         fprintf(outfile, "    arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", 
2406                                 reloc_offset, addend, name);
2407                         break;
2408                     default:
2409                         error("unsupported arm relocation (%d)", type);
2410                     }
2411                 }
2412                 }
2413             }
2414 #elif defined(HOST_M68K)
2415             {
2416                 char name[256];
2417                 int type;
2418                 int addend;
2419                 int reloc_offset;
2420                 Elf32_Sym *sym;
2421                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2422                 if (rel->r_offset >= start_offset &&
2423                     rel->r_offset < start_offset + copy_size) {
2424                     sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
2425                     sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2426                     get_reloc_expr(name, sizeof(name), sym_name);
2427                     type = ELF32_R_TYPE(rel->r_info);
2428                     addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
2429                     reloc_offset = rel->r_offset - start_offset;
2430                     switch(type) {
2431                     case R_68K_32:
2432                         fprintf(outfile, "    /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
2433                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n", 
2434                                 reloc_offset, name, addend );
2435                         break;
2436                     case R_68K_PC32:
2437                         fprintf(outfile, "    /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
2438                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n", 
2439                                 reloc_offset, name, reloc_offset, /*sym->st_value+*/ addend);
2440                         break;
2441                     default:
2442                         error("unsupported m68k relocation (%d)", type);
2443                     }
2444                 }
2445                 }
2446             }
2447 #else
2448 #error unsupported CPU
2449 #endif
2450         fprintf(outfile, "    gen_code_ptr += %d;\n", copy_size);
2451         fprintf(outfile, "}\n");
2452         fprintf(outfile, "break;\n\n");
2453     } else {
2454         fprintf(outfile, "static inline void gen_%s(", name);
2455         if (nb_args == 0) {
2456             fprintf(outfile, "void");
2457         } else {
2458             for(i = 0; i < nb_args; i++) {
2459                 if (i != 0)
2460                     fprintf(outfile, ", ");
2461                 fprintf(outfile, "long param%d", i + 1);
2462             }
2463         }
2464         fprintf(outfile, ")\n");
2465         fprintf(outfile, "{\n");
2466         for(i = 0; i < nb_args; i++) {
2467             fprintf(outfile, "    *gen_opparam_ptr++ = param%d;\n", i + 1);
2468         }
2469         fprintf(outfile, "    *gen_opc_ptr++ = INDEX_%s;\n", name);
2470         fprintf(outfile, "}\n\n");
2471     }
2472 }
2473
2474 int gen_file(FILE *outfile, int out_type)
2475 {
2476     int i;
2477     EXE_SYM *sym;
2478
2479     if (out_type == OUT_INDEX_OP) {
2480         fprintf(outfile, "DEF(end, 0, 0)\n");
2481         fprintf(outfile, "DEF(nop, 0, 0)\n");
2482         fprintf(outfile, "DEF(nop1, 1, 0)\n");
2483         fprintf(outfile, "DEF(nop2, 2, 0)\n");
2484         fprintf(outfile, "DEF(nop3, 3, 0)\n");
2485         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2486             const char *name;
2487             name = get_sym_name(sym);
2488             if (strstart(name, OP_PREFIX, NULL)) {
2489                 gen_code(name, sym->st_value, sym->st_size, outfile, 2);
2490             }
2491         }
2492     } else if (out_type == OUT_GEN_OP) {
2493         /* generate gen_xxx functions */
2494         fprintf(outfile, "#include \"dyngen-op.h\"\n");
2495         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2496             const char *name;
2497             name = get_sym_name(sym);
2498             if (strstart(name, OP_PREFIX, NULL)) {
2499 #if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
2500                 if (sym->st_shndx != text_shndx)
2501                     error("invalid section for opcode (0x%x)", sym->st_shndx);
2502 #endif
2503                 gen_code(name, sym->st_value, sym->st_size, outfile, 0);
2504             }
2505         }
2506         
2507     } else {
2508         /* generate big code generation switch */
2509
2510 #ifdef HOST_ARM
2511         /* We need to know the size of all the ops so we can figure out when
2512            to emit constant pools.  This must be consistent with opc.h.  */
2513 fprintf(outfile,
2514 "static const uint32_t arm_opc_size[] = {\n"
2515 "  0,\n" /* end */
2516 "  0,\n" /* nop */
2517 "  0,\n" /* nop1 */
2518 "  0,\n" /* nop2 */
2519 "  0,\n"); /* nop3 */
2520         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2521             const char *name;
2522             name = get_sym_name(sym);
2523             if (strstart(name, OP_PREFIX, NULL)) {
2524                 fprintf(outfile, "  %d,\n", sym->st_size);
2525             }
2526         }
2527 fprintf(outfile,
2528 "};\n");
2529 #endif
2530
2531 fprintf(outfile,
2532 "int dyngen_code(uint8_t *gen_code_buf,\n"
2533 "                uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
2534 "                const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n"
2535 "{\n"
2536 "    uint8_t *gen_code_ptr;\n"
2537 "    const uint16_t *opc_ptr;\n"
2538 "    const uint32_t *opparam_ptr;\n");
2539
2540 #ifdef HOST_ARM
2541 /* Arm is tricky because it uses constant pools for loading immediate values.
2542    We assume (and require) each function is code followed by a constant pool.
2543    All the ops are small so this should be ok.  For each op we figure
2544    out how much "spare" range we have in the load instructions.  This allows
2545    us to insert subsequent ops in between the op and the constant pool,
2546    eliminating the neeed to jump around the pool.
2547
2548    We currently generate:
2549    
2550    [ For this example we assume merging would move op1_pool out of range.
2551      In practice we should be able to combine many ops before the offset
2552      limits are reached. ]
2553    op1_code;
2554    op2_code;
2555    goto op3;
2556    op2_pool;
2557    op1_pool;
2558 op3:
2559    op3_code;
2560    ret;
2561    op3_pool;
2562
2563    Ideally we'd put op1_pool before op2_pool, but that requires two passes.
2564  */
2565 fprintf(outfile,
2566 "    uint8_t *last_gen_code_ptr = gen_code_buf;\n"
2567 "    LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
2568 "    uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
2569 /* Initialise the parmissible pool offset to an arbitary large value.  */
2570 "    uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
2571 #endif
2572 #ifdef HOST_IA64
2573     {
2574         long addend, not_first = 0;
2575         unsigned long sym_idx;
2576         int index, max_index;
2577         const char *sym_name;
2578         EXE_RELOC *rel;
2579
2580         max_index = -1;
2581         for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2582             sym_idx = ELF64_R_SYM(rel->r_info);
2583             sym_name = (strtab + symtab[sym_idx].st_name);
2584             if (strstart(sym_name, "__op_gen_label", NULL))
2585                 continue;
2586             if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
2587                 continue;
2588
2589             addend = rel->r_addend;
2590             index = get_plt_index(sym_name, addend);
2591             if (index <= max_index)
2592                 continue;
2593             max_index = index;
2594             fprintf(outfile, "    extern void %s(void);\n", sym_name);
2595         }
2596
2597         fprintf(outfile,
2598                 "    struct ia64_fixup *plt_fixes = NULL, "
2599                 "*ltoff_fixes = NULL;\n"
2600                 "    static long plt_target[] = {\n\t");
2601
2602         max_index = -1;
2603         for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2604             sym_idx = ELF64_R_SYM(rel->r_info);
2605             sym_name = (strtab + symtab[sym_idx].st_name);
2606             if (strstart(sym_name, "__op_gen_label", NULL))
2607                 continue;
2608             if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
2609                 continue;
2610
2611             addend = rel->r_addend;
2612             index = get_plt_index(sym_name, addend);
2613             if (index <= max_index)
2614                 continue;
2615             max_index = index;
2616
2617             if (not_first)
2618                 fprintf(outfile, ",\n\t");
2619             not_first = 1;
2620             if (addend)
2621                 fprintf(outfile, "(long) &%s + %ld", sym_name, addend);
2622             else
2623                 fprintf(outfile, "(long) &%s", sym_name);
2624         }
2625         fprintf(outfile, "\n    };\n"
2626             "    unsigned int plt_offset[%u] = { 0 };\n", max_index + 1);
2627     }
2628 #endif
2629
2630 fprintf(outfile,
2631 "\n"
2632 "    gen_code_ptr = gen_code_buf;\n"
2633 "    opc_ptr = opc_buf;\n"
2634 "    opparam_ptr = opparam_buf;\n");
2635
2636         /* Generate prologue, if needed. */ 
2637
2638 fprintf(outfile,
2639 "    for(;;) {\n");
2640
2641 #ifdef HOST_ARM
2642 /* Generate constant pool if needed */
2643 fprintf(outfile,
2644 "            if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
2645 "                gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
2646 "arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n"
2647 "                last_gen_code_ptr = gen_code_ptr;\n"
2648 "                arm_ldr_ptr = arm_ldr_table;\n"
2649 "                arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
2650 "                arm_pool_ptr = gen_code_ptr + 0x1000000;\n"
2651 "            }\n");
2652 #endif
2653
2654 fprintf(outfile,
2655 "        switch(*opc_ptr++) {\n");
2656
2657         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2658             const char *name;
2659             name = get_sym_name(sym);
2660             if (strstart(name, OP_PREFIX, NULL)) {
2661 #if 0
2662                 printf("%4d: %s pos=0x%08x len=%d\n", 
2663                        i, name, sym->st_value, sym->st_size);
2664 #endif
2665 #if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
2666                 if (sym->st_shndx != text_shndx)
2667                     error("invalid section for opcode (0x%x)", sym->st_shndx);
2668 #endif
2669                 gen_code(name, sym->st_value, sym->st_size, outfile, 1);
2670             }
2671         }
2672
2673 fprintf(outfile,
2674 "        case INDEX_op_nop:\n"
2675 "            break;\n"
2676 "        case INDEX_op_nop1:\n"
2677 "            opparam_ptr++;\n"
2678 "            break;\n"
2679 "        case INDEX_op_nop2:\n"
2680 "            opparam_ptr += 2;\n"
2681 "            break;\n"
2682 "        case INDEX_op_nop3:\n"
2683 "            opparam_ptr += 3;\n"
2684 "            break;\n"
2685 "        default:\n"
2686 "            goto the_end;\n"
2687 "        }\n");
2688
2689
2690 fprintf(outfile,
2691 "    }\n"
2692 " the_end:\n"
2693 );
2694 #ifdef HOST_IA64
2695     fprintf(outfile,
2696             "    {\n"
2697             "      extern char code_gen_buffer[];\n"
2698             "      ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
2699             "(uint64_t) code_gen_buffer + 2*(1<<20), plt_fixes,\n\t\t\t"
2700             "sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t"
2701             "plt_target, plt_offset);\n    }\n");
2702 #endif
2703
2704 /* generate some code patching */ 
2705 #ifdef HOST_ARM
2706 fprintf(outfile,
2707 "if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
2708 "    gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
2709 "arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");
2710 #endif
2711     /* flush instruction cache */
2712     fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
2713
2714     fprintf(outfile, "return gen_code_ptr -  gen_code_buf;\n");
2715     fprintf(outfile, "}\n\n");
2716
2717     }
2718
2719     return 0;
2720 }
2721
2722 void usage(void)
2723 {
2724     printf("dyngen (c) 2003 Fabrice Bellard\n"
2725            "usage: dyngen [-o outfile] [-c] objfile\n"
2726            "Generate a dynamic code generator from an object file\n"
2727            "-c     output enum of operations\n"
2728            "-g     output gen_op_xx() functions\n"
2729            );
2730     exit(1);
2731 }
2732
2733 int main(int argc, char **argv)
2734 {
2735     int c, out_type;
2736     const char *filename, *outfilename;
2737     FILE *outfile;
2738
2739     outfilename = "out.c";
2740     out_type = OUT_CODE;
2741     for(;;) {
2742         c = getopt(argc, argv, "ho:cg");
2743         if (c == -1)
2744             break;
2745         switch(c) {
2746         case 'h':
2747             usage();
2748             break;
2749         case 'o':
2750             outfilename = optarg;
2751             break;
2752         case 'c':
2753             out_type = OUT_INDEX_OP;
2754             break;
2755         case 'g':
2756             out_type = OUT_GEN_OP;
2757             break;
2758         }
2759     }
2760     if (optind >= argc)
2761         usage();
2762     filename = argv[optind];
2763     outfile = fopen(outfilename, "w");
2764     if (!outfile)
2765         error("could not open '%s'", outfilename);
2766
2767     load_object(filename);
2768     gen_file(outfile, out_type);
2769     fclose(outfile);
2770     return 0;
2771 }