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