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