Statistics
| Branch: | Revision:

root / dyngen.c @ abcd5da7

History | View | Annotate | Download (45.7 kB)

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 <unistd.h>
26
#include <fcntl.h>
27

    
28
#include "config-host.h"
29

    
30
/* elf format definitions. We use these macros to test the CPU to
31
   allow cross compilation (this tool must be ran on the build
32
   platform) */
33
#if defined(HOST_I386)
34

    
35
#define ELF_CLASS        ELFCLASS32
36
#define ELF_ARCH        EM_386
37
#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
38
#undef ELF_USES_RELOCA
39

    
40
#elif defined(HOST_PPC)
41

    
42
#define ELF_CLASS        ELFCLASS32
43
#define ELF_ARCH        EM_PPC
44
#define elf_check_arch(x) ((x) == EM_PPC)
45
#define ELF_USES_RELOCA
46

    
47
#elif defined(HOST_S390)
48

    
49
#define ELF_CLASS        ELFCLASS32
50
#define ELF_ARCH        EM_S390
51
#define elf_check_arch(x) ((x) == EM_S390)
52
#define ELF_USES_RELOCA
53

    
54
#elif defined(HOST_ALPHA)
55

    
56
#define ELF_CLASS        ELFCLASS64
57
#define ELF_ARCH        EM_ALPHA
58
#define elf_check_arch(x) ((x) == EM_ALPHA)
59
#define ELF_USES_RELOCA
60

    
61
#elif defined(HOST_IA64)
62

    
63
#define ELF_CLASS        ELFCLASS64
64
#define ELF_ARCH        EM_IA_64
65
#define elf_check_arch(x) ((x) == EM_IA_64)
66
#define ELF_USES_RELOCA
67

    
68
#elif defined(HOST_SPARC)
69

    
70
#define ELF_CLASS        ELFCLASS32
71
#define ELF_ARCH        EM_SPARC
72
#define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS)
73
#define ELF_USES_RELOCA
74

    
75
#elif defined(HOST_SPARC64)
76

    
77
#define ELF_CLASS        ELFCLASS64
78
#define ELF_ARCH        EM_SPARCV9
79
#define elf_check_arch(x) ((x) == EM_SPARCV9)
80
#define ELF_USES_RELOCA
81

    
82
#elif defined(HOST_ARM)
83

    
84
#define ELF_CLASS        ELFCLASS32
85
#define ELF_ARCH        EM_ARM
86
#define elf_check_arch(x) ((x) == EM_ARM)
87
#define ELF_USES_RELOC
88

    
89
#else
90
#error unsupported CPU - please update the code
91
#endif
92

    
93
#include "elf.h"
94

    
95
#if ELF_CLASS == ELFCLASS32
96
typedef int32_t host_long;
97
typedef uint32_t host_ulong;
98
#define swabls(x) swab32s(x)
99
#else
100
typedef int64_t host_long;
101
typedef uint64_t host_ulong;
102
#define swabls(x) swab64s(x)
103
#endif
104

    
105
#ifdef ELF_USES_RELOCA
106
#define SHT_RELOC SHT_RELA
107
#else
108
#define SHT_RELOC SHT_REL
109
#endif
110

    
111
#include "bswap.h"
112

    
113
enum {
114
    OUT_GEN_OP,
115
    OUT_CODE,
116
    OUT_INDEX_OP,
117
};
118

    
119
/* all dynamically generated functions begin with this code */
120
#define OP_PREFIX "op_"
121

    
122
int elf_must_swap(struct elfhdr *h)
123
{
124
  union {
125
      uint32_t i;
126
      uint8_t b[4];
127
  } swaptest;
128

    
129
  swaptest.i = 1;
130
  return (h->e_ident[EI_DATA] == ELFDATA2MSB) != 
131
      (swaptest.b[0] == 0);
132
}
133
  
134
void swab16s(uint16_t *p)
135
{
136
    *p = bswap16(*p);
137
}
138

    
139
void swab32s(uint32_t *p)
140
{
141
    *p = bswap32(*p);
142
}
143

    
144
void swab64s(uint64_t *p)
145
{
146
    *p = bswap64(*p);
147
}
148

    
149
void elf_swap_ehdr(struct elfhdr *h)
150
{
151
    swab16s(&h->e_type);                        /* Object file type */
152
    swab16s(&h->        e_machine);                /* Architecture */
153
    swab32s(&h->        e_version);                /* Object file version */
154
    swabls(&h->        e_entry);                /* Entry point virtual address */
155
    swabls(&h->        e_phoff);                /* Program header table file offset */
156
    swabls(&h->        e_shoff);                /* Section header table file offset */
157
    swab32s(&h->        e_flags);                /* Processor-specific flags */
158
    swab16s(&h->        e_ehsize);                /* ELF header size in bytes */
159
    swab16s(&h->        e_phentsize);                /* Program header table entry size */
160
    swab16s(&h->        e_phnum);                /* Program header table entry count */
161
    swab16s(&h->        e_shentsize);                /* Section header table entry size */
162
    swab16s(&h->        e_shnum);                /* Section header table entry count */
163
    swab16s(&h->        e_shstrndx);                /* Section header string table index */
164
}
165

    
166
void elf_swap_shdr(struct elf_shdr *h)
167
{
168
  swab32s(&h->        sh_name);                /* Section name (string tbl index) */
169
  swab32s(&h->        sh_type);                /* Section type */
170
  swabls(&h->        sh_flags);                /* Section flags */
171
  swabls(&h->        sh_addr);                /* Section virtual addr at execution */
172
  swabls(&h->        sh_offset);                /* Section file offset */
173
  swabls(&h->        sh_size);                /* Section size in bytes */
174
  swab32s(&h->        sh_link);                /* Link to another section */
175
  swab32s(&h->        sh_info);                /* Additional section information */
176
  swabls(&h->        sh_addralign);                /* Section alignment */
177
  swabls(&h->        sh_entsize);                /* Entry size if section holds table */
178
}
179

    
180
void elf_swap_phdr(struct elf_phdr *h)
181
{
182
    swab32s(&h->p_type);                        /* Segment type */
183
    swabls(&h->p_offset);                /* Segment file offset */
184
    swabls(&h->p_vaddr);                /* Segment virtual address */
185
    swabls(&h->p_paddr);                /* Segment physical address */
186
    swabls(&h->p_filesz);                /* Segment size in file */
187
    swabls(&h->p_memsz);                /* Segment size in memory */
188
    swab32s(&h->p_flags);                /* Segment flags */
189
    swabls(&h->p_align);                /* Segment alignment */
190
}
191

    
192
void elf_swap_rel(ELF_RELOC *rel)
193
{
194
    swabls(&rel->r_offset);
195
    swabls(&rel->r_info);
196
#ifdef ELF_USES_RELOCA
197
    swabls(&rel->r_addend);
198
#endif
199
}
200

    
201
/* ELF file info */
202
int do_swap;
203
struct elf_shdr *shdr;
204
uint8_t **sdata;
205
struct elfhdr ehdr;
206
ElfW(Sym) *symtab;
207
int nb_syms;
208
char *strtab;
209
int text_shndx;
210

    
211
uint16_t get16(uint16_t *p)
212
{
213
    uint16_t val;
214
    val = *p;
215
    if (do_swap)
216
        val = bswap16(val);
217
    return val;
218
}
219

    
220
uint32_t get32(uint32_t *p)
221
{
222
    uint32_t val;
223
    val = *p;
224
    if (do_swap)
225
        val = bswap32(val);
226
    return val;
227
}
228

    
229
void put16(uint16_t *p, uint16_t val)
230
{
231
    if (do_swap)
232
        val = bswap16(val);
233
    *p = val;
234
}
235

    
236
void put32(uint32_t *p, uint32_t val)
237
{
238
    if (do_swap)
239
        val = bswap32(val);
240
    *p = val;
241
}
242

    
243
void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
244
{
245
    va_list ap;
246
    va_start(ap, fmt);
247
    fprintf(stderr, "dyngen: ");
248
    vfprintf(stderr, fmt, ap);
249
    fprintf(stderr, "\n");
250
    va_end(ap);
251
    exit(1);
252
}
253

    
254

    
255
struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr, 
256
                                  const char *name)
257
{
258
    int i;
259
    const char *shname;
260
    struct elf_shdr *sec;
261

    
262
    for(i = 0; i < shnum; i++) {
263
        sec = &shdr[i];
264
        if (!sec->sh_name)
265
            continue;
266
        shname = shstr + sec->sh_name;
267
        if (!strcmp(shname, name))
268
            return sec;
269
    }
270
    return NULL;
271
}
272

    
273
int find_reloc(int sh_index)
274
{
275
    struct elf_shdr *sec;
276
    int i;
277

    
278
    for(i = 0; i < ehdr.e_shnum; i++) {
279
        sec = &shdr[i];
280
        if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) 
281
            return i;
282
    }
283
    return 0;
284
}
285

    
286
void *load_data(int fd, long offset, unsigned int size)
287
{
288
    char *data;
289

    
290
    data = malloc(size);
291
    if (!data)
292
        return NULL;
293
    lseek(fd, offset, SEEK_SET);
294
    if (read(fd, data, size) != size) {
295
        free(data);
296
        return NULL;
297
    }
298
    return data;
299
}
300

    
301
int strstart(const char *str, const char *val, const char **ptr)
302
{
303
    const char *p, *q;
304
    p = str;
305
    q = val;
306
    while (*q != '\0') {
307
        if (*p != *q)
308
            return 0;
309
        p++;
310
        q++;
311
    }
312
    if (ptr)
313
        *ptr = p;
314
    return 1;
315
}
316

    
317
#ifdef HOST_ARM
318

    
319
int arm_emit_ldr_info(const char *name, unsigned long start_offset,
320
                      FILE *outfile, uint8_t *p_start, uint8_t *p_end,
321
                      ELF_RELOC *relocs, int nb_relocs)
322
{
323
    uint8_t *p;
324
    uint32_t insn;
325
    int offset, min_offset, pc_offset, data_size;
326
    uint8_t data_allocated[1024];
327
    unsigned int data_index;
328
    
329
    memset(data_allocated, 0, sizeof(data_allocated));
330
    
331
    p = p_start;
332
    min_offset = p_end - p_start;
333
    while (p < p_start + min_offset) {
334
        insn = get32((uint32_t *)p);
335
        if ((insn & 0x0d5f0000) == 0x051f0000) {
336
            /* ldr reg, [pc, #im] */
337
            offset = insn & 0xfff;
338
            if (!(insn & 0x00800000))
339
                        offset = -offset;
340
            if ((offset & 3) !=0)
341
                error("%s:%04x: ldr pc offset must be 32 bit aligned", 
342
                      name, start_offset + p - p_start);
343
            pc_offset = p - p_start + offset + 8;
344
            if (pc_offset <= (p - p_start) || 
345
                pc_offset >= (p_end - p_start))
346
                error("%s:%04x: ldr pc offset must point inside the function code", 
347
                      name, start_offset + p - p_start);
348
            if (pc_offset < min_offset)
349
                min_offset = pc_offset;
350
            if (outfile) {
351
                /* ldr position */
352
                fprintf(outfile, "    arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", 
353
                        p - p_start);
354
                /* ldr data index */
355
                data_index = ((p_end - p_start) - pc_offset - 4) >> 2;
356
                fprintf(outfile, "    arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n", 
357
                        data_index);
358
                fprintf(outfile, "    arm_ldr_ptr++;\n");
359
                if (data_index >= sizeof(data_allocated))
360
                    error("%s: too many data", name);
361
                if (!data_allocated[data_index]) {
362
                    ELF_RELOC *rel;
363
                    int i, addend, type;
364
                    const char *sym_name, *p;
365
                    char relname[1024];
366

    
367
                    data_allocated[data_index] = 1;
368

    
369
                    /* data value */
370
                    addend = get32((uint32_t *)(p_start + pc_offset));
371
                    relname[0] = '\0';
372
                    for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
373
                        if (rel->r_offset == (pc_offset + start_offset)) {
374
                            sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
375
                            /* the compiler leave some unnecessary references to the code */
376
                            if (strstart(sym_name, "__op_param", &p)) {
377
                                snprintf(relname, sizeof(relname), "param%s", p);
378
                            } else {
379
                                snprintf(relname, sizeof(relname), "(long)(&%s)", sym_name);
380
                            }
381
                            type = ELF32_R_TYPE(rel->r_info);
382
                            if (type != R_ARM_ABS32)
383
                                error("%s: unsupported data relocation", name);
384
                            break;
385
                        }
386
                    }
387
                    fprintf(outfile, "    arm_data_ptr[%d] = 0x%x",
388
                            data_index, addend);
389
                    if (relname[0] != '\0')
390
                        fprintf(outfile, " + %s", relname);
391
                    fprintf(outfile, ";\n");
392
                }
393
            }
394
        }
395
        p += 4;
396
    }
397
    data_size = (p_end - p_start) - min_offset;
398
    if (data_size > 0 && outfile) {
399
        fprintf(outfile, "    arm_data_ptr += %d;\n", data_size >> 2);
400
    }
401

    
402
    /* the last instruction must be a mov pc, lr */
403
    if (p == p_start)
404
        goto arm_ret_error;
405
    p -= 4;
406
    insn = get32((uint32_t *)p);
407
    if ((insn & 0xffff0000) != 0xe91b0000) {
408
    arm_ret_error:
409
        if (!outfile)
410
            printf("%s: invalid epilog\n", name);
411
    }
412
    return p - p_start;            
413
}
414
#endif
415

    
416

    
417
#define MAX_ARGS 3
418

    
419
/* generate op code */
420
void gen_code(const char *name, host_ulong offset, host_ulong size, 
421
              FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs,
422
              int gen_switch)
423
{
424
    int copy_size = 0;
425
    uint8_t *p_start, *p_end;
426
    host_ulong start_offset;
427
    int nb_args, i, n;
428
    uint8_t args_present[MAX_ARGS];
429
    const char *sym_name, *p;
430
    ELF_RELOC *rel;
431

    
432
    /* Compute exact size excluding prologue and epilogue instructions.
433
     * Increment start_offset to skip epilogue instructions, then compute
434
     * copy_size the indicate the size of the remaining instructions (in
435
     * bytes).
436
     */
437
    p_start = text + offset;
438
    p_end = p_start + size;
439
    start_offset = offset;
440
    switch(ELF_ARCH) {
441
    case EM_386:
442
        {
443
            int len;
444
            len = p_end - p_start;
445
            if (len == 0)
446
                error("empty code for %s", name);
447
            if (p_end[-1] == 0xc3) {
448
                len--;
449
            } else {
450
                error("ret or jmp expected at the end of %s", name);
451
            }
452
            copy_size = len;
453
        }
454
        break;
455
    case EM_PPC:
456
        {
457
            uint8_t *p;
458
            p = (void *)(p_end - 4);
459
            if (p == p_start)
460
                error("empty code for %s", name);
461
            if (get32((uint32_t *)p) != 0x4e800020)
462
                error("blr expected at the end of %s", name);
463
            copy_size = p - p_start;
464
        }
465
        break;
466
    case EM_S390:
467
        {
468
            uint8_t *p;
469
            p = (void *)(p_end - 2);
470
            if (p == p_start)
471
                error("empty code for %s", name);
472
            if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
473
                error("br %%r14 expected at the end of %s", name);
474
            copy_size = p - p_start;
475
        }
476
        break;
477
    case EM_ALPHA:
478
        {
479
            uint8_t *p;
480
            p = p_end - 4;
481
            if (p == p_start)
482
                error("empty code for %s", name);
483
            if (get32((uint32_t *)p) != 0x6bfa8001)
484
                error("ret expected at the end of %s", name);
485
            copy_size = p - p_start;            
486
        }
487
        break;
488
    case EM_IA_64:
489
        {
490
            uint8_t *p;
491
            p = (void *)(p_end - 4);
492
            if (p == p_start)
493
                error("empty code for %s", name);
494
            /* br.ret.sptk.many b0;; */
495
            /* 08 00 84 00 */
496
            if (get32((uint32_t *)p) != 0x00840008)
497
                error("br.ret.sptk.many b0;; expected at the end of %s", name);
498
            copy_size = p - p_start;
499
        }
500
        break;
501
    case EM_SPARC:
502
    case EM_SPARC32PLUS:
503
        {
504
            uint32_t start_insn, end_insn1, end_insn2;
505
            uint8_t *p;
506
            p = (void *)(p_end - 8);
507
            if (p <= p_start)
508
                error("empty code for %s", name);
509
            start_insn = get32((uint32_t *)(p_start + 0x0));
510
            end_insn1 = get32((uint32_t *)(p + 0x0));
511
            end_insn2 = get32((uint32_t *)(p + 0x4));
512
            if ((start_insn & ~0x1fff) == 0x9de3a000) {
513
                p_start += 0x4;
514
                start_offset += 0x4;
515
                if ((int)(start_insn | ~0x1fff) < -128)
516
                    error("Found bogus save at the start of %s", name);
517
                if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
518
                    error("ret; restore; not found at end of %s", name);
519
            } else {
520
                error("No save at the beginning of %s", name);
521
            }
522
#if 0
523
            /* Skip a preceeding nop, if present.  */
524
            if (p > p_start) {
525
                skip_insn = get32((uint32_t *)(p - 0x4));
526
                if (skip_insn == 0x01000000)
527
                    p -= 4;
528
            }
529
#endif
530
            copy_size = p - p_start;
531
        }
532
        break;
533
    case EM_SPARCV9:
534
        {
535
            uint32_t start_insn, end_insn1, end_insn2, skip_insn;
536
            uint8_t *p;
537
            p = (void *)(p_end - 8);
538
            if (p <= p_start)
539
                error("empty code for %s", name);
540
            start_insn = get32((uint32_t *)(p_start + 0x0));
541
            end_insn1 = get32((uint32_t *)(p + 0x0));
542
            end_insn2 = get32((uint32_t *)(p + 0x4));
543
            if ((start_insn & ~0x1fff) == 0x9de3a000) {
544
                p_start += 0x4;
545
                start_offset += 0x4;
546
                if ((int)(start_insn | ~0x1fff) < -256)
547
                    error("Found bogus save at the start of %s", name);
548
                if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
549
                    error("ret; restore; not found at end of %s", name);
550
            } else {
551
                error("No save at the beginning of %s", name);
552
            }
553

    
554
            /* Skip a preceeding nop, if present.  */
555
            if (p > p_start) {
556
                skip_insn = get32((uint32_t *)(p - 0x4));
557
                if (skip_insn == 0x01000000)
558
                    p -= 4;
559
            }
560

    
561
            copy_size = p - p_start;
562
        }
563
        break;
564
#ifdef HOST_ARM
565
    case EM_ARM:
566
        if ((p_end - p_start) <= 16)
567
            error("%s: function too small", name);
568
        if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
569
            (get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 ||
570
            get32((uint32_t *)(p_start + 8)) != 0xe24cb004)
571
            error("%s: invalid prolog", name);
572
        p_start += 12;
573
        start_offset += 12;
574
        copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, 
575
                                      relocs, nb_relocs);
576
        break;
577
#endif
578
    default:
579
        error("unknown ELF architecture");
580
    }
581

    
582
    /* compute the number of arguments by looking at the relocations */
583
    for(i = 0;i < MAX_ARGS; i++)
584
        args_present[i] = 0;
585

    
586
    for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
587
        if (rel->r_offset >= start_offset &&
588
            rel->r_offset < start_offset + (p_end - p_start)) {
589
            sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
590
            if (strstart(sym_name, "__op_param", &p)) {
591
                n = strtoul(p, NULL, 10);
592
                if (n > MAX_ARGS)
593
                    error("too many arguments in %s", name);
594
                args_present[n - 1] = 1;
595
            }
596
        }
597
    }
598
    
599
    nb_args = 0;
600
    while (nb_args < MAX_ARGS && args_present[nb_args])
601
        nb_args++;
602
    for(i = nb_args; i < MAX_ARGS; i++) {
603
        if (args_present[i])
604
            error("inconsistent argument numbering in %s", name);
605
    }
606

    
607
    if (gen_switch == 2) {
608
        fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
609
    } else if (gen_switch == 1) {
610

    
611
        /* output C code */
612
        fprintf(outfile, "case INDEX_%s: {\n", name);
613
        if (nb_args > 0) {
614
            fprintf(outfile, "    long ");
615
            for(i = 0; i < nb_args; i++) {
616
                if (i != 0)
617
                    fprintf(outfile, ", ");
618
                fprintf(outfile, "param%d", i + 1);
619
            }
620
            fprintf(outfile, ";\n");
621
        }
622
        fprintf(outfile, "    extern void %s();\n", name);
623

    
624
        for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
625
            if (rel->r_offset >= start_offset &&
626
                rel->r_offset < start_offset + (p_end - p_start)) {
627
                sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
628
                if (*sym_name && 
629
                    !strstart(sym_name, "__op_param", NULL) &&
630
                    !strstart(sym_name, "__op_jmp", NULL)) {
631
#if defined(HOST_SPARC)
632
                    if (sym_name[0] == '.') {
633
                        fprintf(outfile,
634
                                "extern char __dot_%s __asm__(\"%s\");\n",
635
                                sym_name+1, sym_name);
636
                        continue;
637
                    }
638
#endif
639
                    fprintf(outfile, "extern char %s;\n", sym_name);
640
                }
641
            }
642
        }
643

    
644
        fprintf(outfile, "    memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", name, start_offset - offset, copy_size);
645

    
646
        /* emit code offset information */
647
        {
648
            ElfW(Sym) *sym;
649
            const char *sym_name, *p;
650
            unsigned long val;
651
            int n;
652

    
653
            for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
654
                sym_name = strtab + sym->st_name;
655
                if (strstart(sym_name, "__op_label", &p)) {
656
                    uint8_t *ptr;
657
                    unsigned long offset;
658
                    
659
                    /* test if the variable refers to a label inside
660
                       the code we are generating */
661
                    ptr = sdata[sym->st_shndx];
662
                    if (!ptr)
663
                        error("__op_labelN in invalid section");
664
                    offset = sym->st_value;
665
                    val = *(unsigned long *)(ptr + offset);
666
#ifdef ELF_USES_RELOCA
667
                    {
668
                        int reloc_shndx, nb_relocs1, j;
669

    
670
                        /* try to find a matching relocation */
671
                        reloc_shndx = find_reloc(sym->st_shndx);
672
                        if (reloc_shndx) {
673
                            nb_relocs1 = shdr[reloc_shndx].sh_size / 
674
                                shdr[reloc_shndx].sh_entsize;
675
                            rel = (ELF_RELOC *)sdata[reloc_shndx];
676
                            for(j = 0; j < nb_relocs1; j++) {
677
                                if (rel->r_offset == offset) {
678
                                    val = rel->r_addend;
679
                                    break;
680
                                }
681
                                rel++;
682
                            }
683
                        }
684
                    }
685
#endif                    
686

    
687
                    if (val >= start_offset && val < start_offset + copy_size) {
688
                        n = strtol(p, NULL, 10);
689
                        fprintf(outfile, "    label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
690
                    }
691
                }
692
            }
693
        }
694

    
695
        /* load parameres in variables */
696
        for(i = 0; i < nb_args; i++) {
697
            fprintf(outfile, "    param%d = *opparam_ptr++;\n", i + 1);
698
        }
699

    
700
        /* patch relocations */
701
#if defined(HOST_I386)
702
            {
703
                char name[256];
704
                int type;
705
                int addend;
706
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
707
                if (rel->r_offset >= start_offset &&
708
                    rel->r_offset < start_offset + copy_size) {
709
                    sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
710
                    if (strstart(sym_name, "__op_param", &p)) {
711
                        snprintf(name, sizeof(name), "param%s", p);
712
                    } else {
713
                        snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
714
                    }
715
                    type = ELF32_R_TYPE(rel->r_info);
716
                    addend = get32((uint32_t *)(text + rel->r_offset));
717
                    switch(type) {
718
                    case R_386_32:
719
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
720
                                rel->r_offset - start_offset, name, addend);
721
                        break;
722
                    case R_386_PC32:
723
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", 
724
                                rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
725
                        break;
726
                    default:
727
                        error("unsupported i386 relocation (%d)", type);
728
                    }
729
                }
730
                }
731
            }
732
#elif defined(HOST_PPC)
733
            {
734
                char name[256];
735
                int type;
736
                int addend;
737
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
738
                    if (rel->r_offset >= start_offset &&
739
                        rel->r_offset < start_offset + copy_size) {
740
                        sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
741
                        if (strstart(sym_name, "__op_jmp", &p)) {
742
                            int n;
743
                            n = strtol(p, NULL, 10);
744
                            /* __op_jmp relocations are done at
745
                               runtime to do translated block
746
                               chaining: the offset of the instruction
747
                               needs to be stored */
748
                            fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
749
                                    n, rel->r_offset - start_offset);
750
                            continue;
751
                        }
752
                        
753
                        if (strstart(sym_name, "__op_param", &p)) {
754
                            snprintf(name, sizeof(name), "param%s", p);
755
                        } else {
756
                            snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
757
                        }
758
                        type = ELF32_R_TYPE(rel->r_info);
759
                        addend = rel->r_addend;
760
                        switch(type) {
761
                        case R_PPC_ADDR32:
762
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
763
                                    rel->r_offset - start_offset, name, addend);
764
                            break;
765
                        case R_PPC_ADDR16_LO:
766
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", 
767
                                    rel->r_offset - start_offset, name, addend);
768
                            break;
769
                        case R_PPC_ADDR16_HI:
770
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", 
771
                                    rel->r_offset - start_offset, name, addend);
772
                            break;
773
                        case R_PPC_ADDR16_HA:
774
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", 
775
                                    rel->r_offset - start_offset, name, addend);
776
                            break;
777
                        case R_PPC_REL24:
778
                            /* warning: must be at 32 MB distancy */
779
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n", 
780
                                    rel->r_offset - start_offset, rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
781
                            break;
782
                        default:
783
                            error("unsupported powerpc relocation (%d)", type);
784
                        }
785
                    }
786
                }
787
            }
788
#elif defined(HOST_S390)
789
            {
790
                char name[256];
791
                int type;
792
                int addend;
793
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
794
                    if (rel->r_offset >= start_offset &&
795
                        rel->r_offset < start_offset + copy_size) {
796
                        sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
797
                        if (strstart(sym_name, "__op_param", &p)) {
798
                            snprintf(name, sizeof(name), "param%s", p);
799
                        } else {
800
                            snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
801
                        }
802
                        type = ELF32_R_TYPE(rel->r_info);
803
                        addend = rel->r_addend;
804
                        switch(type) {
805
                        case R_390_32:
806
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
807
                                    rel->r_offset - start_offset, name, addend);
808
                            break;
809
                        case R_390_16:
810
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", 
811
                                    rel->r_offset - start_offset, name, addend);
812
                            break;
813
                        case R_390_8:
814
                            fprintf(outfile, "    *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", 
815
                                    rel->r_offset - start_offset, name, addend);
816
                            break;
817
                        default:
818
                            error("unsupported s390 relocation (%d)", type);
819
                        }
820
                    }
821
                }
822
            }
823
#elif defined(HOST_ALPHA)
824
            {
825
                for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
826
                    if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
827
                        int type;
828

    
829
                        type = ELF64_R_TYPE(rel->r_info);
830
                        sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
831
                        switch (type) {
832
                        case R_ALPHA_GPDISP:
833
                            /* The gp is just 32 bit, and never changes, so it's easiest to emit it
834
                               as an immediate instead of constructing it from the pv or ra.  */
835
                            fprintf(outfile, "    immediate_ldah(gen_code_ptr + %ld, gp);\n",
836
                                    rel->r_offset - start_offset);
837
                            fprintf(outfile, "    immediate_lda(gen_code_ptr + %ld, gp);\n",
838
                                    rel->r_offset - start_offset + rel->r_addend);
839
                            break;
840
                        case R_ALPHA_LITUSE:
841
                            /* jsr to literal hint. Could be used to optimize to bsr. Ignore for
842
                               now, since some called functions (libc) need pv to be set up.  */
843
                            break;
844
                        case R_ALPHA_HINT:
845
                            /* Branch target prediction hint. Ignore for now.  Should be already
846
                               correct for in-function jumps.  */
847
                            break;
848
                        case R_ALPHA_LITERAL:
849
                            /* Load a literal from the GOT relative to the gp.  Since there's only a
850
                               single gp, nothing is to be done.  */
851
                            break;
852
                        case R_ALPHA_GPRELHIGH:
853
                            /* Handle fake relocations against __op_param symbol.  Need to emit the
854
                               high part of the immediate value instead.  Other symbols need no
855
                               special treatment.  */
856
                            if (strstart(sym_name, "__op_param", &p))
857
                                fprintf(outfile, "    immediate_ldah(gen_code_ptr + %ld, param%s);\n",
858
                                        rel->r_offset - start_offset, p);
859
                            break;
860
                        case R_ALPHA_GPRELLOW:
861
                            if (strstart(sym_name, "__op_param", &p))
862
                                fprintf(outfile, "    immediate_lda(gen_code_ptr + %ld, param%s);\n",
863
                                        rel->r_offset - start_offset, p);
864
                            break;
865
                        case R_ALPHA_BRSGP:
866
                            /* PC-relative jump. Tweak offset to skip the two instructions that try to
867
                               set up the gp from the pv.  */
868
                            fprintf(outfile, "    fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
869
                                    rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset);
870
                            break;
871
                        default:
872
                            error("unsupported Alpha relocation (%d)", type);
873
                        }
874
                    }
875
                }
876
            }
877
#elif defined(HOST_IA64)
878
            {
879
                char name[256];
880
                int type;
881
                int addend;
882
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
883
                    if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
884
                        sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
885
                        if (strstart(sym_name, "__op_param", &p)) {
886
                            snprintf(name, sizeof(name), "param%s", p);
887
                        } else {
888
                            snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
889
                        }
890
                        type = ELF64_R_TYPE(rel->r_info);
891
                        addend = rel->r_addend;
892
                        switch(type) {
893
                        case R_IA64_LTOFF22:
894
                            error("must implemnt R_IA64_LTOFF22 relocation");
895
                        case R_IA64_PCREL21B:
896
                            error("must implemnt R_IA64_PCREL21B relocation");
897
                        default:
898
                            error("unsupported ia64 relocation (%d)", type);
899
                        }
900
                    }
901
                }
902
            }
903
#elif defined(HOST_SPARC)
904
            {
905
                char name[256];
906
                int type;
907
                int addend;
908
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
909
                    if (rel->r_offset >= start_offset &&
910
                        rel->r_offset < start_offset + copy_size) {
911
                        sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
912
                        if (strstart(sym_name, "__op_param", &p)) {
913
                            snprintf(name, sizeof(name), "param%s", p);
914
                        } else {
915
                                if (sym_name[0] == '.')
916
                                        snprintf(name, sizeof(name),
917
                                                 "(long)(&__dot_%s)",
918
                                                 sym_name + 1);
919
                                else
920
                                        snprintf(name, sizeof(name),
921
                                                 "(long)(&%s)", sym_name);
922
                        }
923
                        type = ELF32_R_TYPE(rel->r_info);
924
                        addend = rel->r_addend;
925
                        switch(type) {
926
                        case R_SPARC_32:
927
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
928
                                    rel->r_offset - start_offset, name, addend);
929
                            break;
930
                        case R_SPARC_HI22:
931
                            fprintf(outfile,
932
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
933
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
934
                                    " & ~0x3fffff) "
935
                                    " | (((%s + %d) >> 10) & 0x3fffff);\n",
936
                                    rel->r_offset - start_offset,
937
                                    rel->r_offset - start_offset,
938
                                    name, addend);
939
                            break;
940
                        case R_SPARC_LO10:
941
                            fprintf(outfile,
942
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
943
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
944
                                    " & ~0x3ff) "
945
                                    " | ((%s + %d) & 0x3ff);\n",
946
                                    rel->r_offset - start_offset,
947
                                    rel->r_offset - start_offset,
948
                                    name, addend);
949
                            break;
950
                        case R_SPARC_WDISP30:
951
                            fprintf(outfile,
952
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
953
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
954
                                    " & ~0x3fffffff) "
955
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
956
                                    "    & 0x3fffffff);\n",
957
                                    rel->r_offset - start_offset,
958
                                    rel->r_offset - start_offset,
959
                                    name, addend,
960
                                    rel->r_offset - start_offset);
961
                            break;
962
                        default:
963
                            error("unsupported sparc relocation (%d)", type);
964
                        }
965
                    }
966
                }
967
            }
968
#elif defined(HOST_SPARC64)
969
            {
970
                char name[256];
971
                int type;
972
                int addend;
973
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
974
                    if (rel->r_offset >= start_offset &&
975
                        rel->r_offset < start_offset + copy_size) {
976
                        sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
977
                        if (strstart(sym_name, "__op_param", &p)) {
978
                            snprintf(name, sizeof(name), "param%s", p);
979
                        } else {
980
                            snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
981
                        }
982
                        type = ELF64_R_TYPE(rel->r_info);
983
                        addend = rel->r_addend;
984
                        switch(type) {
985
                        case R_SPARC_32:
986
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
987
                                    rel->r_offset - start_offset, name, addend);
988
                            break;
989
                        case R_SPARC_HI22:
990
                            fprintf(outfile,
991
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
992
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
993
                                    " & ~0x3fffff) "
994
                                    " | (((%s + %d) >> 10) & 0x3fffff);\n",
995
                                    rel->r_offset - start_offset,
996
                                    rel->r_offset - start_offset,
997
                                    name, addend);
998
                            break;
999
                        case R_SPARC_LO10:
1000
                            fprintf(outfile,
1001
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
1002
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
1003
                                    " & ~0x3ff) "
1004
                                    " | ((%s + %d) & 0x3ff);\n",
1005
                                    rel->r_offset - start_offset,
1006
                                    rel->r_offset - start_offset,
1007
                                    name, addend);
1008
                            break;
1009
                        case R_SPARC_WDISP30:
1010
                            fprintf(outfile,
1011
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
1012
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
1013
                                    " & ~0x3fffffff) "
1014
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
1015
                                    "    & 0x3fffffff);\n",
1016
                                    rel->r_offset - start_offset,
1017
                                    rel->r_offset - start_offset,
1018
                                    name, addend,
1019
                                    rel->r_offset - start_offset);
1020
                            break;
1021
                        default:
1022
                            error("unsupported sparc64 relocation (%d)", type);
1023
                        }
1024
                    }
1025
                }
1026
            }
1027
#elif defined(HOST_ARM)
1028
            {
1029
                char name[256];
1030
                int type;
1031
                int addend;
1032

    
1033
                arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
1034
                                  relocs, nb_relocs);
1035

    
1036
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1037
                if (rel->r_offset >= start_offset &&
1038
                    rel->r_offset < start_offset + copy_size) {
1039
                    sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1040
                    /* the compiler leave some unnecessary references to the code */
1041
                    if (sym_name[0] == '\0')
1042
                        continue;
1043
                    if (strstart(sym_name, "__op_param", &p)) {
1044
                        snprintf(name, sizeof(name), "param%s", p);
1045
                    } else {
1046
                        snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
1047
                    }
1048
                    type = ELF32_R_TYPE(rel->r_info);
1049
                    addend = get32((uint32_t *)(text + rel->r_offset));
1050
                    switch(type) {
1051
                    case R_ARM_ABS32:
1052
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
1053
                                rel->r_offset - start_offset, name, addend);
1054
                        break;
1055
                    case R_ARM_PC24:
1056
                        fprintf(outfile, "    arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", 
1057
                                rel->r_offset - start_offset, addend, name);
1058
                        break;
1059
                    default:
1060
                        error("unsupported arm relocation (%d)", type);
1061
                    }
1062
                }
1063
                }
1064
            }
1065
#else
1066
#error unsupported CPU
1067
#endif
1068
        fprintf(outfile, "    gen_code_ptr += %d;\n", copy_size);
1069
        fprintf(outfile, "}\n");
1070
        fprintf(outfile, "break;\n\n");
1071
    } else {
1072
        fprintf(outfile, "static inline void gen_%s(", name);
1073
        if (nb_args == 0) {
1074
            fprintf(outfile, "void");
1075
        } else {
1076
            for(i = 0; i < nb_args; i++) {
1077
                if (i != 0)
1078
                    fprintf(outfile, ", ");
1079
                fprintf(outfile, "long param%d", i + 1);
1080
            }
1081
        }
1082
        fprintf(outfile, ")\n");
1083
        fprintf(outfile, "{\n");
1084
        for(i = 0; i < nb_args; i++) {
1085
            fprintf(outfile, "    *gen_opparam_ptr++ = param%d;\n", i + 1);
1086
        }
1087
        fprintf(outfile, "    *gen_opc_ptr++ = INDEX_%s;\n", name);
1088
        fprintf(outfile, "}\n\n");
1089
    }
1090
}
1091

    
1092
/* load an elf object file */
1093
int load_elf(const char *filename, FILE *outfile, int out_type)
1094
{
1095
    int fd;
1096
    struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec;
1097
    int i, j;
1098
    ElfW(Sym) *sym;
1099
    char *shstr;
1100
    uint8_t *text;
1101
    ELF_RELOC *relocs;
1102
    int nb_relocs;
1103
    ELF_RELOC *rel;
1104
    
1105
    fd = open(filename, O_RDONLY);
1106
    if (fd < 0) 
1107
        error("can't open file '%s'", filename);
1108
    
1109
    /* Read ELF header.  */
1110
    if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
1111
        error("unable to read file header");
1112

    
1113
    /* Check ELF identification.  */
1114
    if (ehdr.e_ident[EI_MAG0] != ELFMAG0
1115
     || ehdr.e_ident[EI_MAG1] != ELFMAG1
1116
     || ehdr.e_ident[EI_MAG2] != ELFMAG2
1117
     || ehdr.e_ident[EI_MAG3] != ELFMAG3
1118
     || ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
1119
        error("bad ELF header");
1120
    }
1121

    
1122
    do_swap = elf_must_swap(&ehdr);
1123
    if (do_swap)
1124
        elf_swap_ehdr(&ehdr);
1125
    if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
1126
        error("Unsupported ELF class");
1127
    if (ehdr.e_type != ET_REL)
1128
        error("ELF object file expected");
1129
    if (ehdr.e_version != EV_CURRENT)
1130
        error("Invalid ELF version");
1131
    if (!elf_check_arch(ehdr.e_machine))
1132
        error("Unsupported CPU (e_machine=%d)", ehdr.e_machine);
1133

    
1134
    /* read section headers */
1135
    shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(struct elf_shdr));
1136
    if (do_swap) {
1137
        for(i = 0; i < ehdr.e_shnum; i++) {
1138
            elf_swap_shdr(&shdr[i]);
1139
        }
1140
    }
1141

    
1142
    /* read all section data */
1143
    sdata = malloc(sizeof(void *) * ehdr.e_shnum);
1144
    memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
1145
    
1146
    for(i = 0;i < ehdr.e_shnum; i++) {
1147
        sec = &shdr[i];
1148
        if (sec->sh_type != SHT_NOBITS)
1149
            sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size);
1150
    }
1151

    
1152
    sec = &shdr[ehdr.e_shstrndx];
1153
    shstr = sdata[ehdr.e_shstrndx];
1154

    
1155
    /* swap relocations */
1156
    for(i = 0; i < ehdr.e_shnum; i++) {
1157
        sec = &shdr[i];
1158
        if (sec->sh_type == SHT_RELOC) {
1159
            nb_relocs = sec->sh_size / sec->sh_entsize;
1160
            if (do_swap) {
1161
                for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++)
1162
                    elf_swap_rel(rel);
1163
            }
1164
        }
1165
    }
1166
    /* text section */
1167

    
1168
    text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
1169
    if (!text_sec)
1170
        error("could not find .text section");
1171
    text_shndx = text_sec - shdr;
1172
    text = sdata[text_shndx];
1173

    
1174
    /* find text relocations, if any */
1175
    relocs = NULL;
1176
    nb_relocs = 0;
1177
    i = find_reloc(text_shndx);
1178
    if (i != 0) {
1179
        relocs = (ELF_RELOC *)sdata[i];
1180
        nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize;
1181
    }
1182

    
1183
    symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
1184
    if (!symtab_sec)
1185
        error("could not find .symtab section");
1186
    strtab_sec = &shdr[symtab_sec->sh_link];
1187

    
1188
    symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
1189
    strtab = sdata[symtab_sec->sh_link];
1190
    
1191
    nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
1192
    if (do_swap) {
1193
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
1194
            swab32s(&sym->st_name);
1195
            swabls(&sym->st_value);
1196
            swabls(&sym->st_size);
1197
            swab16s(&sym->st_shndx);
1198
        }
1199
    }
1200

    
1201
    if (out_type == OUT_INDEX_OP) {
1202
        fprintf(outfile, "DEF(end, 0, 0)\n");
1203
        fprintf(outfile, "DEF(nop, 0, 0)\n");
1204
        fprintf(outfile, "DEF(nop1, 1, 0)\n");
1205
        fprintf(outfile, "DEF(nop2, 2, 0)\n");
1206
        fprintf(outfile, "DEF(nop3, 3, 0)\n");
1207
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
1208
            const char *name, *p;
1209
            name = strtab + sym->st_name;
1210
            if (strstart(name, OP_PREFIX, &p)) {
1211
                gen_code(name, sym->st_value, sym->st_size, outfile, 
1212
                         text, relocs, nb_relocs, 2);
1213
            }
1214
        }
1215
    } else if (out_type == OUT_GEN_OP) {
1216
        /* generate gen_xxx functions */
1217

    
1218
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
1219
            const char *name;
1220
            name = strtab + sym->st_name;
1221
            if (strstart(name, OP_PREFIX, NULL)) {
1222
                if (sym->st_shndx != (text_sec - shdr))
1223
                    error("invalid section for opcode (0x%x)", sym->st_shndx);
1224
                gen_code(name, sym->st_value, sym->st_size, outfile, 
1225
                         text, relocs, nb_relocs, 0);
1226
            }
1227
        }
1228
        
1229
    } else {
1230
        /* generate big code generation switch */
1231
fprintf(outfile,
1232
"int dyngen_code(uint8_t *gen_code_buf,\n"
1233
"                uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
1234
"                const uint16_t *opc_buf, const uint32_t *opparam_buf)\n"
1235
"{\n"
1236
"    uint8_t *gen_code_ptr;\n"
1237
"    const uint16_t *opc_ptr;\n"
1238
"    const uint32_t *opparam_ptr;\n");
1239

    
1240
#ifdef HOST_ARM
1241
fprintf(outfile,
1242
"    uint8_t *last_gen_code_ptr = gen_code_buf;\n"
1243
"    LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
1244
"    uint32_t *arm_data_ptr = arm_data_table;\n");
1245
#endif
1246

    
1247
fprintf(outfile,
1248
"\n"
1249
"    gen_code_ptr = gen_code_buf;\n"
1250
"    opc_ptr = opc_buf;\n"
1251
"    opparam_ptr = opparam_buf;\n");
1252

    
1253
        /* Generate prologue, if needed. */ 
1254

    
1255
fprintf(outfile,
1256
"    for(;;) {\n"
1257
"        switch(*opc_ptr++) {\n"
1258
);
1259

    
1260
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
1261
            const char *name;
1262
            name = strtab + sym->st_name;
1263
            if (strstart(name, OP_PREFIX, NULL)) {
1264
#if 0
1265
                printf("%4d: %s pos=0x%08x len=%d\n", 
1266
                       i, name, sym->st_value, sym->st_size);
1267
#endif
1268
                if (sym->st_shndx != (text_sec - shdr))
1269
                    error("invalid section for opcode (0x%x)", sym->st_shndx);
1270
                gen_code(name, sym->st_value, sym->st_size, outfile, 
1271
                         text, relocs, nb_relocs, 1);
1272
            }
1273
        }
1274

    
1275
fprintf(outfile,
1276
"        case INDEX_op_nop:\n"
1277
"            break;\n"
1278
"        case INDEX_op_nop1:\n"
1279
"            opparam_ptr++;\n"
1280
"            break;\n"
1281
"        case INDEX_op_nop2:\n"
1282
"            opparam_ptr += 2;\n"
1283
"            break;\n"
1284
"        case INDEX_op_nop3:\n"
1285
"            opparam_ptr += 3;\n"
1286
"            break;\n"
1287
"        default:\n"
1288
"            goto the_end;\n"
1289
"        }\n");
1290

    
1291
#ifdef HOST_ARM
1292
/* generate constant table if needed */
1293
fprintf(outfile,
1294
"        if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n"
1295
"            gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n"
1296
"            last_gen_code_ptr = gen_code_ptr;\n"
1297
"            arm_ldr_ptr = arm_ldr_table;\n"
1298
"            arm_data_ptr = arm_data_table;\n"
1299
"        }\n");         
1300
#endif
1301

    
1302

    
1303
fprintf(outfile,
1304
"    }\n"
1305
" the_end:\n"
1306
);
1307

    
1308
/* generate some code patching */ 
1309
#ifdef HOST_ARM
1310
fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n");
1311
#endif
1312
    /* flush instruction cache */
1313
    fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
1314

    
1315
    fprintf(outfile, "return gen_code_ptr -  gen_code_buf;\n");
1316
    fprintf(outfile, "}\n\n");
1317

    
1318
    }
1319

    
1320
    close(fd);
1321
    return 0;
1322
}
1323

    
1324
void usage(void)
1325
{
1326
    printf("dyngen (c) 2003 Fabrice Bellard\n"
1327
           "usage: dyngen [-o outfile] [-c] objfile\n"
1328
           "Generate a dynamic code generator from an object file\n"
1329
           "-c     output enum of operations\n"
1330
           "-g     output gen_op_xx() functions\n"
1331
           );
1332
    exit(1);
1333
}
1334

    
1335
int main(int argc, char **argv)
1336
{
1337
    int c, out_type;
1338
    const char *filename, *outfilename;
1339
    FILE *outfile;
1340

    
1341
    outfilename = "out.c";
1342
    out_type = OUT_CODE;
1343
    for(;;) {
1344
        c = getopt(argc, argv, "ho:cg");
1345
        if (c == -1)
1346
            break;
1347
        switch(c) {
1348
        case 'h':
1349
            usage();
1350
            break;
1351
        case 'o':
1352
            outfilename = optarg;
1353
            break;
1354
        case 'c':
1355
            out_type = OUT_INDEX_OP;
1356
            break;
1357
        case 'g':
1358
            out_type = OUT_GEN_OP;
1359
            break;
1360
        }
1361
    }
1362
    if (optind >= argc)
1363
        usage();
1364
    filename = argv[optind];
1365
    outfile = fopen(outfilename, "w");
1366
    if (!outfile)
1367
        error("could not open '%s'", outfilename);
1368
    load_elf(filename, outfile, out_type);
1369
    fclose(outfile);
1370
    return 0;
1371
}