s390 support
[qemu] / dyngen.c
1 /*
2  *  Generic Dynamic compiler generator
3  * 
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <inttypes.h>
25 #include <elf.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28
29 #include "thunk.h"
30
31 /* temporary fix to make it compile with old elf headers (XXX: use
32    included elf.h in all cases) */
33 #ifndef EM_390
34 #define EM_S390         22              /* IBM S390 */
35 #define R_390_8         1              /* Direct 8 bit.  */
36 #define R_390_16        3              /* Direct 16 bit.  */
37 #define R_390_32        4              /* Direct 32 bit.  */
38 #endif
39
40 /* all dynamically generated functions begin with this code */
41 #define OP_PREFIX "op_"
42
43 int elf_must_swap(Elf32_Ehdr *h)
44 {
45   union {
46       uint32_t i;
47       uint8_t b[4];
48   } swaptest;
49
50   swaptest.i = 1;
51   return (h->e_ident[EI_DATA] == ELFDATA2MSB) != 
52       (swaptest.b[0] == 0);
53 }
54   
55 void swab16s(uint16_t *p)
56 {
57     *p = bswap16(*p);
58 }
59
60 void swab32s(uint32_t *p)
61 {
62     *p = bswap32(*p);
63 }
64
65 void swab64s(uint32_t *p)
66 {
67     *p = bswap64(*p);
68 }
69
70 void elf_swap_ehdr(Elf32_Ehdr *h)
71 {
72     swab16s(&h->e_type);                        /* Object file type */
73     swab16s(&h->        e_machine);             /* Architecture */
74     swab32s(&h->        e_version);             /* Object file version */
75     swab32s(&h->        e_entry);               /* Entry point virtual address */
76     swab32s(&h->        e_phoff);               /* Program header table file offset */
77     swab32s(&h->        e_shoff);               /* Section header table file offset */
78     swab32s(&h->        e_flags);               /* Processor-specific flags */
79     swab16s(&h->        e_ehsize);              /* ELF header size in bytes */
80     swab16s(&h->        e_phentsize);           /* Program header table entry size */
81     swab16s(&h->        e_phnum);               /* Program header table entry count */
82     swab16s(&h->        e_shentsize);           /* Section header table entry size */
83     swab16s(&h->        e_shnum);               /* Section header table entry count */
84     swab16s(&h->        e_shstrndx);            /* Section header string table index */
85 }
86
87 void elf_swap_shdr(Elf32_Shdr *h)
88 {
89   swab32s(&h->  sh_name);               /* Section name (string tbl index) */
90   swab32s(&h->  sh_type);               /* Section type */
91   swab32s(&h->  sh_flags);              /* Section flags */
92   swab32s(&h->  sh_addr);               /* Section virtual addr at execution */
93   swab32s(&h->  sh_offset);             /* Section file offset */
94   swab32s(&h->  sh_size);               /* Section size in bytes */
95   swab32s(&h->  sh_link);               /* Link to another section */
96   swab32s(&h->  sh_info);               /* Additional section information */
97   swab32s(&h->  sh_addralign);          /* Section alignment */
98   swab32s(&h->  sh_entsize);            /* Entry size if section holds table */
99 }
100
101 void elf_swap_phdr(Elf32_Phdr *h)
102 {
103     swab32s(&h->p_type);                        /* Segment type */
104     swab32s(&h->p_offset);              /* Segment file offset */
105     swab32s(&h->p_vaddr);               /* Segment virtual address */
106     swab32s(&h->p_paddr);               /* Segment physical address */
107     swab32s(&h->p_filesz);              /* Segment size in file */
108     swab32s(&h->p_memsz);               /* Segment size in memory */
109     swab32s(&h->p_flags);               /* Segment flags */
110     swab32s(&h->p_align);               /* Segment alignment */
111 }
112
113 int do_swap;
114 int e_machine;
115
116 uint16_t get16(uint16_t *p)
117 {
118     uint16_t val;
119     val = *p;
120     if (do_swap)
121         val = bswap16(val);
122     return val;
123 }
124
125 uint32_t get32(uint32_t *p)
126 {
127     uint32_t val;
128     val = *p;
129     if (do_swap)
130         val = bswap32(val);
131     return val;
132 }
133
134 void put16(uint16_t *p, uint16_t val)
135 {
136     if (do_swap)
137         val = bswap16(val);
138     *p = val;
139 }
140
141 void put32(uint32_t *p, uint32_t val)
142 {
143     if (do_swap)
144         val = bswap32(val);
145     *p = val;
146 }
147
148 void __attribute__((noreturn)) error(const char *fmt, ...)
149 {
150     va_list ap;
151     va_start(ap, fmt);
152     fprintf(stderr, "dyngen: ");
153     vfprintf(stderr, fmt, ap);
154     fprintf(stderr, "\n");
155     va_end(ap);
156     exit(1);
157 }
158
159
160 Elf32_Shdr *find_elf_section(Elf32_Shdr *shdr, int shnum, const char *shstr, 
161                              const char *name)
162 {
163     int i;
164     const char *shname;
165     Elf32_Shdr *sec;
166
167     for(i = 0; i < shnum; i++) {
168         sec = &shdr[i];
169         if (!sec->sh_name)
170             continue;
171         shname = shstr + sec->sh_name;
172         if (!strcmp(shname, name))
173             return sec;
174     }
175     return NULL;
176 }
177
178 void *load_data(int fd, long offset, unsigned int size)
179 {
180     char *data;
181
182     data = malloc(size);
183     if (!data)
184         return NULL;
185     lseek(fd, offset, SEEK_SET);
186     if (read(fd, data, size) != size) {
187         free(data);
188         return NULL;
189     }
190     return data;
191 }
192
193 int strstart(const char *str, const char *val, const char **ptr)
194 {
195     const char *p, *q;
196     p = str;
197     q = val;
198     while (*q != '\0') {
199         if (*p != *q)
200             return 0;
201         p++;
202         q++;
203     }
204     if (ptr)
205         *ptr = p;
206     return 1;
207 }
208
209 #define MAX_ARGS 3
210
211 /* generate op code */
212 void gen_code(const char *name, unsigned long offset, unsigned long size, 
213               FILE *outfile, uint8_t *text, void *relocs, int nb_relocs, int reloc_sh_type,
214               Elf32_Sym *symtab, char *strtab, int gen_switch)
215 {
216     int copy_size = 0;
217     uint8_t *p_start, *p_end;
218     int nb_args, i;
219     uint8_t args_present[MAX_ARGS];
220     const char *sym_name, *p;
221
222     /* compute exact size excluding return instruction */
223     p_start = text + offset;
224     p_end = p_start + size;
225     switch(e_machine) {
226     case EM_386:
227         {
228             uint8_t *p;
229             p = p_end - 1;
230             if (p == p_start)
231                 error("empty code for %s", name);
232             if (p[0] != 0xc3)
233                 error("ret expected at the end of %s", name);
234             copy_size = p - p_start;
235         }
236         break;
237     case EM_PPC:
238         {
239             uint8_t *p;
240             p = (void *)(p_end - 4);
241             if (p == p_start)
242                 error("empty code for %s", name);
243             if (get32((uint32_t *)p) != 0x4e800020)
244                 error("blr expected at the end of %s", name);
245             copy_size = p - p_start;
246         }
247         break;
248     case EM_S390:
249         {
250             uint8_t *p;
251             p = (void *)(p_end - 2);
252             if (p == p_start)
253                 error("empty code for %s", name);
254             if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
255                 error("br %r14 expected at the end of %s", name);
256             copy_size = p - p_start;
257         }
258         break;
259     default:
260         error("unsupported CPU (%d)", e_machine);
261     }
262
263     /* compute the number of arguments by looking at the relocations */
264     for(i = 0;i < MAX_ARGS; i++)
265         args_present[i] = 0;
266
267     if (reloc_sh_type == SHT_REL) {
268         Elf32_Rel *rel;
269         int n;
270         for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
271             if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
272                 sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
273                 if (strstart(sym_name, "__op_param", &p)) {
274                     n = strtoul(p, NULL, 10);
275                     if (n >= MAX_ARGS)
276                         error("too many arguments in %s", name);
277                     args_present[n - 1] = 1;
278                 }
279             }
280         }
281     } else {
282         Elf32_Rela *rel;
283         int n;
284         for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
285             if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
286                 sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
287                 if (strstart(sym_name, "__op_param", &p)) {
288                     n = strtoul(p, NULL, 10);
289                     if (n >= MAX_ARGS)
290                         error("too many arguments in %s", name);
291                     args_present[n - 1] = 1;
292                 }
293             }
294         }
295     }
296     
297     nb_args = 0;
298     while (nb_args < MAX_ARGS && args_present[nb_args])
299         nb_args++;
300     for(i = nb_args; i < MAX_ARGS; i++) {
301         if (args_present[i])
302             error("inconsistent argument numbering in %s", name);
303     }
304
305     if (gen_switch == 2) {
306         fprintf(outfile, "DEF(%s, %d)\n", name + 3, nb_args);
307     } else if (gen_switch == 1) {
308
309         /* output C code */
310         fprintf(outfile, "case INDEX_%s: {\n", name);
311         if (nb_args > 0) {
312             fprintf(outfile, "    long ");
313             for(i = 0; i < nb_args; i++) {
314                 if (i != 0)
315                     fprintf(outfile, ", ");
316                 fprintf(outfile, "param%d", i + 1);
317             }
318             fprintf(outfile, ";\n");
319         }
320         fprintf(outfile, "    extern void %s();\n", name);
321
322         if (reloc_sh_type == SHT_REL) {
323             Elf32_Rel *rel;
324             for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
325                 if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
326                     sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
327                     if (!strstart(sym_name, "__op_param", &p)) {
328                         fprintf(outfile, "extern char %s;\n", sym_name);
329                     }
330                 }
331             }
332         } else {
333             Elf32_Rela *rel;
334             for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
335                 if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
336                     sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
337                     if (!strstart(sym_name, "__op_param", &p)) {
338                         fprintf(outfile, "extern char %s;\n", sym_name);
339                     }
340                 }
341             }
342         }
343
344         fprintf(outfile, "    memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size);
345         for(i = 0; i < nb_args; i++) {
346             fprintf(outfile, "    param%d = *opparam_ptr++;\n", i + 1);
347         }
348
349         /* patch relocations */
350         switch(e_machine) {
351         case EM_386:
352             {
353                 Elf32_Rel *rel;
354                 char name[256];
355                 int type;
356                 long addend;
357                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
358                 if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
359                     sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
360                     if (strstart(sym_name, "__op_param", &p)) {
361                         snprintf(name, sizeof(name), "param%s", p);
362                     } else {
363                         snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
364                     }
365                     type = ELF32_R_TYPE(rel->r_info);
366                     addend = get32((uint32_t *)(text + rel->r_offset));
367                     switch(type) {
368                     case R_386_32:
369                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n", 
370                                 rel->r_offset - offset, name, addend);
371                         break;
372                     case R_386_PC32:
373                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %ld) = %s - (long)(gen_code_ptr + %ld) + %ld;\n", 
374                                 rel->r_offset - offset, name, rel->r_offset - offset, addend);
375                         break;
376                     default:
377                         error("unsupported i386 relocation (%d)", type);
378                     }
379                 }
380                 }
381             }
382             break;
383         case EM_PPC:
384             {
385                 Elf32_Rela *rel;
386                 char name[256];
387                 int type;
388                 long addend;
389                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
390                     if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
391                         sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
392                         if (strstart(sym_name, "__op_param", &p)) {
393                             snprintf(name, sizeof(name), "param%s", p);
394                         } else {
395                             snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
396                         }
397                         type = ELF32_R_TYPE(rel->r_info);
398                         addend = rel->r_addend;
399                         switch(type) {
400                         case R_PPC_ADDR32:
401                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n", 
402                                     rel->r_offset - offset, name, addend);
403                             break;
404                         case R_PPC_ADDR16_LO:
405                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld);\n", 
406                                     rel->r_offset - offset, name, addend);
407                             break;
408                         case R_PPC_ADDR16_HI:
409                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld) >> 16;\n", 
410                                     rel->r_offset - offset, name, addend);
411                             break;
412                         case R_PPC_ADDR16_HA:
413                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld + 0x8000) >> 16;\n", 
414                                     rel->r_offset - offset, name, addend);
415                             break;
416                         case R_PPC_REL24:
417                             /* warning: must be at 32 MB distancy */
418                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %ld) = (*(uint32_t *)(gen_code_ptr + %ld) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %ld) + %ld) & 0x03fffffc);\n", 
419                                     rel->r_offset - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend);
420                             break;
421                         default:
422                             error("unsupported powerpc relocation (%d)", type);
423                         }
424                     }
425                 }
426             }
427             break;
428         case EM_S390:
429             {
430                 Elf32_Rela *rel;
431                 char name[256];
432                 int type;
433                 long addend;
434                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
435                     if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
436                         sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
437                         if (strstart(sym_name, "__op_param", &p)) {
438                             snprintf(name, sizeof(name), "param%s", p);
439                         } else {
440                             snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
441                         }
442                         type = ELF32_R_TYPE(rel->r_info);
443                         addend = rel->r_addend;
444                         switch(type) {
445                         case R_390_32:
446                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n", 
447                                     rel->r_offset - offset, name, addend);
448                             break;
449                         case R_390_16:
450                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %ld) = %s + %ld;\n", 
451                                     rel->r_offset - offset, name, addend);
452                             break;
453                         case R_390_8:
454                             fprintf(outfile, "    *(uint8_t *)(gen_code_ptr + %ld) = %s + %ld;\n", 
455                                     rel->r_offset - offset, name, addend);
456                             break;
457                         default:
458                             error("unsupported s390 relocation (%d)", type);
459                         }
460                     }
461                 }
462             }
463             break;
464         default:
465             error("unsupported CPU for relocations (%d)", e_machine);
466         }
467         fprintf(outfile, "    gen_code_ptr += %d;\n", copy_size);
468         fprintf(outfile, "}\n");
469         fprintf(outfile, "break;\n\n");
470     } else {
471         fprintf(outfile, "static inline void gen_%s(", name);
472         if (nb_args == 0) {
473             fprintf(outfile, "void");
474         } else {
475             for(i = 0; i < nb_args; i++) {
476                 if (i != 0)
477                     fprintf(outfile, ", ");
478                 fprintf(outfile, "long param%d", i + 1);
479             }
480         }
481         fprintf(outfile, ")\n");
482         fprintf(outfile, "{\n");
483         for(i = 0; i < nb_args; i++) {
484             fprintf(outfile, "    *gen_opparam_ptr++ = param%d;\n", i + 1);
485         }
486         fprintf(outfile, "    *gen_opc_ptr++ = INDEX_%s;\n", name);
487         fprintf(outfile, "}\n\n");
488     }
489 }
490
491 /* load an elf object file */
492 int load_elf(const char *filename, FILE *outfile, int do_print_enum)
493 {
494     int fd;
495     Elf32_Ehdr ehdr;
496     Elf32_Shdr *sec, *shdr, *symtab_sec, *strtab_sec, *text_sec;
497     int i, j, nb_syms;
498     Elf32_Sym *symtab, *sym;
499     const char *cpu_name;
500     char *shstr, *strtab;
501     uint8_t *text;
502     void *relocs;
503     int nb_relocs, reloc_sh_type;
504     
505     fd = open(filename, O_RDONLY);
506     if (fd < 0) 
507         error("can't open file '%s'", filename);
508     
509     /* Read ELF header.  */
510     if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
511         error("unable to read file header");
512
513     /* Check ELF identification.  */
514     if (ehdr.e_ident[EI_MAG0] != ELFMAG0
515      || ehdr.e_ident[EI_MAG1] != ELFMAG1
516      || ehdr.e_ident[EI_MAG2] != ELFMAG2
517      || ehdr.e_ident[EI_MAG3] != ELFMAG3
518      || ehdr.e_ident[EI_CLASS] != ELFCLASS32
519      || ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
520         error("bad ELF header");
521     }
522
523     do_swap = elf_must_swap(&ehdr);
524     if (do_swap)
525         elf_swap_ehdr(&ehdr);
526     if (ehdr.e_type != ET_REL)
527         error("ELF object file expected");
528     if (ehdr.e_version != EV_CURRENT)
529         error("Invalid ELF version");
530     e_machine = ehdr.e_machine;
531
532     /* read section headers */
533     shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(Elf32_Shdr));
534     if (do_swap) {
535         for(i = 0; i < ehdr.e_shnum; i++) {
536             elf_swap_shdr(&shdr[i]);
537         }
538     }
539
540     sec = &shdr[ehdr.e_shstrndx];
541     shstr = load_data(fd, sec->sh_offset, sec->sh_size);
542
543     /* text section */
544
545     text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
546     if (!text_sec)
547         error("could not find .text section");
548     text = load_data(fd, text_sec->sh_offset, text_sec->sh_size);
549
550     /* find text relocations, if any */
551     nb_relocs = 0;
552     relocs = NULL;
553     reloc_sh_type = 0;
554     for(i = 0; i < ehdr.e_shnum; i++) {
555         sec = &shdr[i];
556         if ((sec->sh_type == SHT_REL || sec->sh_type == SHT_RELA) &&
557             sec->sh_info == (text_sec - shdr)) {
558             reloc_sh_type = sec->sh_type;
559             relocs = load_data(fd, sec->sh_offset, sec->sh_size);
560             nb_relocs = sec->sh_size / sec->sh_entsize;
561             if (do_swap) {
562                 if (sec->sh_type == SHT_REL) {
563                     Elf32_Rel *rel = relocs;
564                     for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
565                         swab32s(&rel->r_offset);
566                         swab32s(&rel->r_info);
567                     }
568                 } else {
569                     Elf32_Rela *rel = relocs;
570                     for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) {
571                         swab32s(&rel->r_offset);
572                         swab32s(&rel->r_info);
573                         swab32s(&rel->r_addend);
574                     }
575                 }
576             }
577             break;
578         }
579     }
580
581     symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
582     if (!symtab_sec)
583         error("could not find .symtab section");
584     strtab_sec = &shdr[symtab_sec->sh_link];
585
586     symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size);
587     strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size);
588     
589     nb_syms = symtab_sec->sh_size / sizeof(Elf32_Sym);
590     if (do_swap) {
591         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
592             swab32s(&sym->st_name);
593             swab32s(&sym->st_value);
594             swab32s(&sym->st_size);
595             swab16s(&sym->st_shndx);
596         }
597     }
598
599     switch(e_machine) {
600     case EM_386:
601         cpu_name = "i386";
602         break;
603     case EM_PPC:
604         cpu_name = "ppc";
605         break;
606     case EM_MIPS:
607         cpu_name = "mips";
608         break;
609     case EM_ARM:
610         cpu_name = "arm";
611         break;
612     case EM_SPARC:
613         cpu_name = "sparc";
614         break;
615     case EM_S390:
616         cpu_name = "s390";
617         break;
618     default:
619         error("unsupported CPU (e_machine=%d)", e_machine);
620     }
621
622     if (do_print_enum) {
623         fprintf(outfile, "DEF(end, 0)\n");
624         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
625             const char *name, *p;
626             name = strtab + sym->st_name;
627             if (strstart(name, OP_PREFIX, &p)) {
628                 gen_code(name, sym->st_value, sym->st_size, outfile, 
629                          text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 2);
630             }
631         }
632     } else {
633         /* generate big code generation switch */
634 fprintf(outfile,
635 "int dyngen_code(uint8_t *gen_code_buf,\n"
636 "                const uint16_t *opc_buf, const uint32_t *opparam_buf)\n"
637 "{\n"
638 "    uint8_t *gen_code_ptr;\n"
639 "    const uint16_t *opc_ptr;\n"
640 "    const uint32_t *opparam_ptr;\n"
641 "    gen_code_ptr = gen_code_buf;\n"
642 "    opc_ptr = opc_buf;\n"
643 "    opparam_ptr = opparam_buf;\n"
644 "    for(;;) {\n"
645 "        switch(*opc_ptr++) {\n"
646 );
647
648         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
649             const char *name;
650             name = strtab + sym->st_name;
651             if (strstart(name, OP_PREFIX, NULL)) {
652 #if 0
653                 printf("%4d: %s pos=0x%08x len=%d\n", 
654                        i, name, sym->st_value, sym->st_size);
655 #endif
656                 if (sym->st_shndx != (text_sec - shdr))
657                     error("invalid section for opcode (0x%x)", sym->st_shndx);
658                 gen_code(name, sym->st_value, sym->st_size, outfile, 
659                          text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 1);
660             }
661         }
662
663 fprintf(outfile,
664 "        default:\n"
665 "            goto the_end;\n"
666 "        }\n"
667 "    }\n"
668 " the_end:\n"
669 );
670
671 /* generate a return */ 
672     switch(e_machine) {
673     case EM_386:
674         fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
675         break;
676     case EM_PPC:
677         fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n");
678         break;
679     case EM_S390:
680         fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n");
681         break;
682     default:
683         error("no return generation for cpu '%s'", cpu_name);
684     }
685     
686     fprintf(outfile, "return gen_code_ptr -  gen_code_buf;\n");
687     fprintf(outfile, "}\n\n");
688
689 /* generate gen_xxx functions */
690 /* XXX: suppress the use of these functions to simplify code */
691         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
692             const char *name;
693             name = strtab + sym->st_name;
694             if (strstart(name, OP_PREFIX, NULL)) {
695                 if (sym->st_shndx != (text_sec - shdr))
696                     error("invalid section for opcode (0x%x)", sym->st_shndx);
697                 gen_code(name, sym->st_value, sym->st_size, outfile, 
698                          text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 0);
699             }
700         }
701     }
702
703     close(fd);
704     return 0;
705 }
706
707 void usage(void)
708 {
709     printf("dyngen (c) 2003 Fabrice Bellard\n"
710            "usage: dyngen [-o outfile] [-c] objfile\n"
711            "Generate a dynamic code generator from an object file\n"
712            "-c     output enum of operations\n"
713            );
714     exit(1);
715 }
716
717 int main(int argc, char **argv)
718 {
719     int c, do_print_enum;
720     const char *filename, *outfilename;
721     FILE *outfile;
722
723     outfilename = "out.c";
724     do_print_enum = 0;
725     for(;;) {
726         c = getopt(argc, argv, "ho:c");
727         if (c == -1)
728             break;
729         switch(c) {
730         case 'h':
731             usage();
732             break;
733         case 'o':
734             outfilename = optarg;
735             break;
736         case 'c':
737             do_print_enum = 1;
738             break;
739         }
740     }
741     if (optind >= argc)
742         usage();
743     filename = argv[optind];
744     outfile = fopen(outfilename, "w");
745     if (!outfile)
746         error("could not open '%s'", outfilename);
747     load_elf(filename, outfile, do_print_enum);
748     fclose(outfile);
749     return 0;
750 }