Statistics
| Branch: | Revision:

root / dyngen.c @ 8d7b0fbb

History | View | Annotate | Download (87.7 kB)

1
/*
2
 *  Generic Dynamic compiler generator
3
 * 
4
 *  Copyright (c) 2003 Fabrice Bellard
5
 *
6
 *  The COFF object format support was extracted from Kazu's QEMU port
7
 *  to Win32.
8
 *
9
 *  Mach-O Support by Matt Reda and Pierre d'Herbemont
10
 *
11
 *  This program is free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 2 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  This program is distributed in the hope that it will be useful,
17
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 *  GNU General Public License for more details.
20
 *
21
 *  You should have received a copy of the GNU General Public License
22
 *  along with this program; if not, write to the Free Software
23
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
 */
25
#include <stdlib.h>
26
#include <stdio.h>
27
#include <string.h>
28
#include <stdarg.h>
29
#include <inttypes.h>
30
#include <unistd.h>
31
#include <fcntl.h>
32

    
33
#include "config-host.h"
34

    
35
/* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross
36
   compilation */
37
#if defined(CONFIG_WIN32)
38
#define CONFIG_FORMAT_COFF
39
#elif defined(CONFIG_DARWIN)
40
#define CONFIG_FORMAT_MACH
41
#else
42
#define CONFIG_FORMAT_ELF
43
#endif
44

    
45
#ifdef CONFIG_FORMAT_ELF
46

    
47
/* elf format definitions. We use these macros to test the CPU to
48
   allow cross compilation (this tool must be ran on the build
49
   platform) */
50
#if defined(HOST_I386)
51

    
52
#define ELF_CLASS        ELFCLASS32
53
#define ELF_ARCH        EM_386
54
#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
55
#undef ELF_USES_RELOCA
56

    
57
#elif defined(HOST_X86_64)
58

    
59
#define ELF_CLASS        ELFCLASS64
60
#define ELF_ARCH        EM_X86_64
61
#define elf_check_arch(x) ((x) == EM_X86_64)
62
#define ELF_USES_RELOCA
63

    
64
#elif defined(HOST_PPC)
65

    
66
#define ELF_CLASS        ELFCLASS32
67
#define ELF_ARCH        EM_PPC
68
#define elf_check_arch(x) ((x) == EM_PPC)
69
#define ELF_USES_RELOCA
70

    
71
#elif defined(HOST_S390)
72

    
73
#define ELF_CLASS        ELFCLASS32
74
#define ELF_ARCH        EM_S390
75
#define elf_check_arch(x) ((x) == EM_S390)
76
#define ELF_USES_RELOCA
77

    
78
#elif defined(HOST_ALPHA)
79

    
80
#define ELF_CLASS        ELFCLASS64
81
#define ELF_ARCH        EM_ALPHA
82
#define elf_check_arch(x) ((x) == EM_ALPHA)
83
#define ELF_USES_RELOCA
84

    
85
#elif defined(HOST_IA64)
86

    
87
#define ELF_CLASS        ELFCLASS64
88
#define ELF_ARCH        EM_IA_64
89
#define elf_check_arch(x) ((x) == EM_IA_64)
90
#define ELF_USES_RELOCA
91

    
92
#elif defined(HOST_SPARC)
93

    
94
#define ELF_CLASS        ELFCLASS32
95
#define ELF_ARCH        EM_SPARC
96
#define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS)
97
#define ELF_USES_RELOCA
98

    
99
#elif defined(HOST_SPARC64)
100

    
101
#define ELF_CLASS        ELFCLASS64
102
#define ELF_ARCH        EM_SPARCV9
103
#define elf_check_arch(x) ((x) == EM_SPARCV9)
104
#define ELF_USES_RELOCA
105

    
106
#elif defined(HOST_ARM)
107

    
108
#define ELF_CLASS        ELFCLASS32
109
#define ELF_ARCH        EM_ARM
110
#define elf_check_arch(x) ((x) == EM_ARM)
111
#define ELF_USES_RELOC
112

    
113
#elif defined(HOST_M68K)
114

    
115
#define ELF_CLASS        ELFCLASS32
116
#define ELF_ARCH        EM_68K
117
#define elf_check_arch(x) ((x) == EM_68K)
118
#define ELF_USES_RELOCA
119

    
120
#else
121
#error unsupported CPU - please update the code
122
#endif
123

    
124
#include "elf.h"
125

    
126
#if ELF_CLASS == ELFCLASS32
127
typedef int32_t host_long;
128
typedef uint32_t host_ulong;
129
#define swabls(x) swab32s(x)
130
#else
131
typedef int64_t host_long;
132
typedef uint64_t host_ulong;
133
#define swabls(x) swab64s(x)
134
#endif
135

    
136
#ifdef ELF_USES_RELOCA
137
#define SHT_RELOC SHT_RELA
138
#else
139
#define SHT_RELOC SHT_REL
140
#endif
141

    
142
#define EXE_RELOC ELF_RELOC
143
#define EXE_SYM ElfW(Sym)
144

    
145
#endif /* CONFIG_FORMAT_ELF */
146

    
147
#ifdef CONFIG_FORMAT_COFF
148

    
149
#include "a.out.h"
150

    
151
typedef int32_t host_long;
152
typedef uint32_t host_ulong;
153

    
154
#define FILENAMELEN 256
155

    
156
typedef struct coff_sym {
157
    struct external_syment *st_syment;
158
    char st_name[FILENAMELEN];
159
    uint32_t st_value;
160
    int  st_size;
161
    uint8_t st_type;
162
    uint8_t st_shndx;
163
} coff_Sym;
164

    
165
typedef struct coff_rel {
166
    struct external_reloc *r_reloc;
167
    int  r_offset;
168
    uint8_t r_type;
169
} coff_Rel;
170

    
171
#define EXE_RELOC struct coff_rel
172
#define EXE_SYM struct coff_sym
173

    
174
#endif /* CONFIG_FORMAT_COFF */
175

    
176
#ifdef CONFIG_FORMAT_MACH
177

    
178
#include <mach-o/loader.h>
179
#include <mach-o/nlist.h>
180
#include <mach-o/reloc.h>
181
#include <mach-o/ppc/reloc.h>
182

    
183
# define check_mach_header(x) (x.magic == MH_MAGIC)
184
typedef int32_t host_long;
185
typedef uint32_t host_ulong;
186

    
187
struct nlist_extended
188
{
189
   union {
190
   char *n_name; 
191
   long  n_strx; 
192
   } n_un;
193
   unsigned char n_type; 
194
   unsigned char n_sect; 
195
   short st_desc;
196
   unsigned long st_value;
197
   unsigned long st_size;
198
};
199

    
200
#define EXE_RELOC struct relocation_info
201
#define EXE_SYM struct nlist_extended
202

    
203
#endif /* CONFIG_FORMAT_MACH */
204

    
205
#include "bswap.h"
206

    
207
enum {
208
    OUT_GEN_OP,
209
    OUT_CODE,
210
    OUT_INDEX_OP,
211
};
212

    
213
/* all dynamically generated functions begin with this code */
214
#define OP_PREFIX "op_"
215

    
216
int do_swap;
217

    
218
void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
219
{
220
    va_list ap;
221
    va_start(ap, fmt);
222
    fprintf(stderr, "dyngen: ");
223
    vfprintf(stderr, fmt, ap);
224
    fprintf(stderr, "\n");
225
    va_end(ap);
226
    exit(1);
227
}
228

    
229
void *load_data(int fd, long offset, unsigned int size)
230
{
231
    char *data;
232

    
233
    data = malloc(size);
234
    if (!data)
235
        return NULL;
236
    lseek(fd, offset, SEEK_SET);
237
    if (read(fd, data, size) != size) {
238
        free(data);
239
        return NULL;
240
    }
241
    return data;
242
}
243

    
244
int strstart(const char *str, const char *val, const char **ptr)
245
{
246
    const char *p, *q;
247
    p = str;
248
    q = val;
249
    while (*q != '\0') {
250
        if (*p != *q)
251
            return 0;
252
        p++;
253
        q++;
254
    }
255
    if (ptr)
256
        *ptr = p;
257
    return 1;
258
}
259

    
260
void pstrcpy(char *buf, int buf_size, const char *str)
261
{
262
    int c;
263
    char *q = buf;
264

    
265
    if (buf_size <= 0)
266
        return;
267

    
268
    for(;;) {
269
        c = *str++;
270
        if (c == 0 || q >= buf + buf_size - 1)
271
            break;
272
        *q++ = c;
273
    }
274
    *q = '\0';
275
}
276

    
277
void swab16s(uint16_t *p)
278
{
279
    *p = bswap16(*p);
280
}
281

    
282
void swab32s(uint32_t *p)
283
{
284
    *p = bswap32(*p);
285
}
286

    
287
void swab64s(uint64_t *p)
288
{
289
    *p = bswap64(*p);
290
}
291

    
292
uint16_t get16(uint16_t *p)
293
{
294
    uint16_t val;
295
    val = *p;
296
    if (do_swap)
297
        val = bswap16(val);
298
    return val;
299
}
300

    
301
uint32_t get32(uint32_t *p)
302
{
303
    uint32_t val;
304
    val = *p;
305
    if (do_swap)
306
        val = bswap32(val);
307
    return val;
308
}
309

    
310
void put16(uint16_t *p, uint16_t val)
311
{
312
    if (do_swap)
313
        val = bswap16(val);
314
    *p = val;
315
}
316

    
317
void put32(uint32_t *p, uint32_t val)
318
{
319
    if (do_swap)
320
        val = bswap32(val);
321
    *p = val;
322
}
323

    
324
/* executable information */
325
EXE_SYM *symtab;
326
int nb_syms;
327
int text_shndx;
328
uint8_t *text;
329
EXE_RELOC *relocs;
330
int nb_relocs;
331

    
332
#ifdef CONFIG_FORMAT_ELF
333

    
334
/* ELF file info */
335
struct elf_shdr *shdr;
336
uint8_t **sdata;
337
struct elfhdr ehdr;
338
char *strtab;
339

    
340
int elf_must_swap(struct elfhdr *h)
341
{
342
  union {
343
      uint32_t i;
344
      uint8_t b[4];
345
  } swaptest;
346

    
347
  swaptest.i = 1;
348
  return (h->e_ident[EI_DATA] == ELFDATA2MSB) != 
349
      (swaptest.b[0] == 0);
350
}
351
  
352
void elf_swap_ehdr(struct elfhdr *h)
353
{
354
    swab16s(&h->e_type);                        /* Object file type */
355
    swab16s(&h->        e_machine);                /* Architecture */
356
    swab32s(&h->        e_version);                /* Object file version */
357
    swabls(&h->        e_entry);                /* Entry point virtual address */
358
    swabls(&h->        e_phoff);                /* Program header table file offset */
359
    swabls(&h->        e_shoff);                /* Section header table file offset */
360
    swab32s(&h->        e_flags);                /* Processor-specific flags */
361
    swab16s(&h->        e_ehsize);                /* ELF header size in bytes */
362
    swab16s(&h->        e_phentsize);                /* Program header table entry size */
363
    swab16s(&h->        e_phnum);                /* Program header table entry count */
364
    swab16s(&h->        e_shentsize);                /* Section header table entry size */
365
    swab16s(&h->        e_shnum);                /* Section header table entry count */
366
    swab16s(&h->        e_shstrndx);                /* Section header string table index */
367
}
368

    
369
void elf_swap_shdr(struct elf_shdr *h)
370
{
371
  swab32s(&h->        sh_name);                /* Section name (string tbl index) */
372
  swab32s(&h->        sh_type);                /* Section type */
373
  swabls(&h->        sh_flags);                /* Section flags */
374
  swabls(&h->        sh_addr);                /* Section virtual addr at execution */
375
  swabls(&h->        sh_offset);                /* Section file offset */
376
  swabls(&h->        sh_size);                /* Section size in bytes */
377
  swab32s(&h->        sh_link);                /* Link to another section */
378
  swab32s(&h->        sh_info);                /* Additional section information */
379
  swabls(&h->        sh_addralign);                /* Section alignment */
380
  swabls(&h->        sh_entsize);                /* Entry size if section holds table */
381
}
382

    
383
void elf_swap_phdr(struct elf_phdr *h)
384
{
385
    swab32s(&h->p_type);                        /* Segment type */
386
    swabls(&h->p_offset);                /* Segment file offset */
387
    swabls(&h->p_vaddr);                /* Segment virtual address */
388
    swabls(&h->p_paddr);                /* Segment physical address */
389
    swabls(&h->p_filesz);                /* Segment size in file */
390
    swabls(&h->p_memsz);                /* Segment size in memory */
391
    swab32s(&h->p_flags);                /* Segment flags */
392
    swabls(&h->p_align);                /* Segment alignment */
393
}
394

    
395
void elf_swap_rel(ELF_RELOC *rel)
396
{
397
    swabls(&rel->r_offset);
398
    swabls(&rel->r_info);
399
#ifdef ELF_USES_RELOCA
400
    swabls(&rel->r_addend);
401
#endif
402
}
403

    
404
struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr, 
405
                                  const char *name)
406
{
407
    int i;
408
    const char *shname;
409
    struct elf_shdr *sec;
410

    
411
    for(i = 0; i < shnum; i++) {
412
        sec = &shdr[i];
413
        if (!sec->sh_name)
414
            continue;
415
        shname = shstr + sec->sh_name;
416
        if (!strcmp(shname, name))
417
            return sec;
418
    }
419
    return NULL;
420
}
421

    
422
int find_reloc(int sh_index)
423
{
424
    struct elf_shdr *sec;
425
    int i;
426

    
427
    for(i = 0; i < ehdr.e_shnum; i++) {
428
        sec = &shdr[i];
429
        if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) 
430
            return i;
431
    }
432
    return 0;
433
}
434

    
435
static host_ulong get_rel_offset(EXE_RELOC *rel)
436
{
437
    return rel->r_offset;
438
}
439

    
440
static char *get_rel_sym_name(EXE_RELOC *rel)
441
{
442
    return strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
443
}
444

    
445
static char *get_sym_name(EXE_SYM *sym)
446
{
447
    return strtab + sym->st_name;
448
}
449

    
450
/* load an elf object file */
451
int load_object(const char *filename)
452
{
453
    int fd;
454
    struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec;
455
    int i, j;
456
    ElfW(Sym) *sym;
457
    char *shstr;
458
    ELF_RELOC *rel;
459
    
460
    fd = open(filename, O_RDONLY);
461
    if (fd < 0) 
462
        error("can't open file '%s'", filename);
463
    
464
    /* Read ELF header.  */
465
    if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
466
        error("unable to read file header");
467

    
468
    /* Check ELF identification.  */
469
    if (ehdr.e_ident[EI_MAG0] != ELFMAG0
470
     || ehdr.e_ident[EI_MAG1] != ELFMAG1
471
     || ehdr.e_ident[EI_MAG2] != ELFMAG2
472
     || ehdr.e_ident[EI_MAG3] != ELFMAG3
473
     || ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
474
        error("bad ELF header");
475
    }
476

    
477
    do_swap = elf_must_swap(&ehdr);
478
    if (do_swap)
479
        elf_swap_ehdr(&ehdr);
480
    if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
481
        error("Unsupported ELF class");
482
    if (ehdr.e_type != ET_REL)
483
        error("ELF object file expected");
484
    if (ehdr.e_version != EV_CURRENT)
485
        error("Invalid ELF version");
486
    if (!elf_check_arch(ehdr.e_machine))
487
        error("Unsupported CPU (e_machine=%d)", ehdr.e_machine);
488

    
489
    /* read section headers */
490
    shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(struct elf_shdr));
491
    if (do_swap) {
492
        for(i = 0; i < ehdr.e_shnum; i++) {
493
            elf_swap_shdr(&shdr[i]);
494
        }
495
    }
496

    
497
    /* read all section data */
498
    sdata = malloc(sizeof(void *) * ehdr.e_shnum);
499
    memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
500
    
501
    for(i = 0;i < ehdr.e_shnum; i++) {
502
        sec = &shdr[i];
503
        if (sec->sh_type != SHT_NOBITS)
504
            sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size);
505
    }
506

    
507
    sec = &shdr[ehdr.e_shstrndx];
508
    shstr = sdata[ehdr.e_shstrndx];
509

    
510
    /* swap relocations */
511
    for(i = 0; i < ehdr.e_shnum; i++) {
512
        sec = &shdr[i];
513
        if (sec->sh_type == SHT_RELOC) {
514
            nb_relocs = sec->sh_size / sec->sh_entsize;
515
            if (do_swap) {
516
                for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++)
517
                    elf_swap_rel(rel);
518
            }
519
        }
520
    }
521
    /* text section */
522

    
523
    text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
524
    if (!text_sec)
525
        error("could not find .text section");
526
    text_shndx = text_sec - shdr;
527
    text = sdata[text_shndx];
528

    
529
    /* find text relocations, if any */
530
    relocs = NULL;
531
    nb_relocs = 0;
532
    i = find_reloc(text_shndx);
533
    if (i != 0) {
534
        relocs = (ELF_RELOC *)sdata[i];
535
        nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize;
536
    }
537

    
538
    symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
539
    if (!symtab_sec)
540
        error("could not find .symtab section");
541
    strtab_sec = &shdr[symtab_sec->sh_link];
542

    
543
    symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
544
    strtab = sdata[symtab_sec->sh_link];
545
    
546
    nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
547
    if (do_swap) {
548
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
549
            swab32s(&sym->st_name);
550
            swabls(&sym->st_value);
551
            swabls(&sym->st_size);
552
            swab16s(&sym->st_shndx);
553
        }
554
    }
555
    close(fd);
556
    return 0;
557
}
558

    
559
#endif /* CONFIG_FORMAT_ELF */
560

    
561
#ifdef CONFIG_FORMAT_COFF
562

    
563
/* COFF file info */
564
struct external_scnhdr *shdr;
565
uint8_t **sdata;
566
struct external_filehdr fhdr;
567
struct external_syment *coff_symtab;
568
char *strtab;
569
int coff_text_shndx, coff_data_shndx;
570

    
571
int data_shndx;
572

    
573
#define STRTAB_SIZE 4
574

    
575
#define DIR32   0x06
576
#define DISP32  0x14
577

    
578
#define T_FUNCTION  0x20
579
#define C_EXTERNAL  2
580

    
581
void sym_ent_name(struct external_syment *ext_sym, EXE_SYM *sym)
582
{
583
    char *q;
584
    int c, i, len;
585
    
586
    if (ext_sym->e.e.e_zeroes != 0) {
587
        q = sym->st_name;
588
        for(i = 0; i < 8; i++) {
589
            c = ext_sym->e.e_name[i];
590
            if (c == '\0')
591
                break;
592
            *q++ = c;
593
        }
594
        *q = '\0';
595
    } else {
596
        pstrcpy(sym->st_name, sizeof(sym->st_name), strtab + ext_sym->e.e.e_offset);
597
    }
598

    
599
    /* now convert the name to a C name (suppress the leading '_') */
600
    if (sym->st_name[0] == '_') {
601
        len = strlen(sym->st_name);
602
        memmove(sym->st_name, sym->st_name + 1, len - 1);
603
        sym->st_name[len - 1] = '\0';
604
    }
605
}
606

    
607
char *name_for_dotdata(struct coff_rel *rel)
608
{
609
        int i;
610
        struct coff_sym *sym;
611
        uint32_t text_data;
612

    
613
        text_data = *(uint32_t *)(text + rel->r_offset);
614

    
615
        for (i = 0, sym = symtab; i < nb_syms; i++, sym++) {
616
                if (sym->st_syment->e_scnum == data_shndx &&
617
                    text_data >= sym->st_value &&
618
                    text_data < sym->st_value + sym->st_size) {
619
                    
620
                    return sym->st_name;
621

    
622
                }
623
        }
624
        return NULL;
625
}
626

    
627
static char *get_sym_name(EXE_SYM *sym)
628
{
629
    return sym->st_name;
630
}
631

    
632
static char *get_rel_sym_name(EXE_RELOC *rel)
633
{
634
    char *name;
635
    name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
636
    if (!strcmp(name, ".data"))
637
        name = name_for_dotdata(rel);
638
    if (name[0] == '.')
639
        return NULL;
640
    return name;
641
}
642

    
643
static host_ulong get_rel_offset(EXE_RELOC *rel)
644
{
645
    return rel->r_offset;
646
}
647

    
648
struct external_scnhdr *find_coff_section(struct external_scnhdr *shdr, int shnum, const char *name)
649
{
650
    int i;
651
    const char *shname;
652
    struct external_scnhdr *sec;
653

    
654
    for(i = 0; i < shnum; i++) {
655
        sec = &shdr[i];
656
        if (!sec->s_name)
657
            continue;
658
        shname = sec->s_name;
659
        if (!strcmp(shname, name))
660
            return sec;
661
    }
662
    return NULL;
663
}
664

    
665
/* load a coff object file */
666
int load_object(const char *filename)
667
{
668
    int fd;
669
    struct external_scnhdr *sec, *text_sec, *data_sec;
670
    int i;
671
    struct external_syment *ext_sym;
672
    struct external_reloc *coff_relocs;
673
    struct external_reloc *ext_rel;
674
    uint32_t *n_strtab;
675
    EXE_SYM *sym;
676
    EXE_RELOC *rel;
677
        
678
    fd = open(filename, O_RDONLY 
679
#ifdef _WIN32
680
              | O_BINARY
681
#endif
682
              );
683
    if (fd < 0) 
684
        error("can't open file '%s'", filename);
685
    
686
    /* Read COFF header.  */
687
    if (read(fd, &fhdr, sizeof (fhdr)) != sizeof (fhdr))
688
        error("unable to read file header");
689

    
690
    /* Check COFF identification.  */
691
    if (fhdr.f_magic != I386MAGIC) {
692
        error("bad COFF header");
693
    }
694
    do_swap = 0;
695

    
696
    /* read section headers */
697
    shdr = load_data(fd, sizeof(struct external_filehdr) + fhdr.f_opthdr, fhdr.f_nscns * sizeof(struct external_scnhdr));
698
        
699
    /* read all section data */
700
    sdata = malloc(sizeof(void *) * fhdr.f_nscns);
701
    memset(sdata, 0, sizeof(void *) * fhdr.f_nscns);
702
    
703
    const char *p;
704
    for(i = 0;i < fhdr.f_nscns; i++) {
705
        sec = &shdr[i];
706
        if (!strstart(sec->s_name,  ".bss", &p))
707
            sdata[i] = load_data(fd, sec->s_scnptr, sec->s_size);
708
    }
709

    
710

    
711
    /* text section */
712
    text_sec = find_coff_section(shdr, fhdr.f_nscns, ".text");
713
    if (!text_sec)
714
        error("could not find .text section");
715
    coff_text_shndx = text_sec - shdr;
716
    text = sdata[coff_text_shndx];
717

    
718
    /* data section */
719
    data_sec = find_coff_section(shdr, fhdr.f_nscns, ".data");
720
    if (!data_sec)
721
        error("could not find .data section");
722
    coff_data_shndx = data_sec - shdr;
723
    
724
    coff_symtab = load_data(fd, fhdr.f_symptr, fhdr.f_nsyms*SYMESZ);
725
    for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
726
        for(i=0;i<8;i++)
727
            printf(" %02x", ((uint8_t *)ext_sym->e.e_name)[i]);
728
        printf("\n");
729
    }
730

    
731

    
732
    n_strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), STRTAB_SIZE);
733
    strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab); 
734
    
735
    nb_syms = fhdr.f_nsyms;
736

    
737
    for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
738
      if (strstart(ext_sym->e.e_name, ".text", NULL))
739
                  text_shndx = ext_sym->e_scnum;
740
          if (strstart(ext_sym->e.e_name, ".data", NULL))
741
                  data_shndx = ext_sym->e_scnum;
742
    }
743

    
744
        /* set coff symbol */
745
        symtab = malloc(sizeof(struct coff_sym) * nb_syms);
746

    
747
        int aux_size, j;
748
        for (i = 0, ext_sym = coff_symtab, sym = symtab; i < nb_syms; i++, ext_sym++, sym++) {
749
                memset(sym, 0, sizeof(*sym));
750
                sym->st_syment = ext_sym;
751
                sym_ent_name(ext_sym, sym);
752
                sym->st_value = ext_sym->e_value;
753

    
754
                aux_size = *(int8_t *)ext_sym->e_numaux;
755
                if (ext_sym->e_scnum == text_shndx && ext_sym->e_type == T_FUNCTION) {
756
                        for (j = aux_size + 1; j < nb_syms - i; j++) {
757
                                if ((ext_sym + j)->e_scnum == text_shndx &&
758
                                        (ext_sym + j)->e_type == T_FUNCTION ){
759
                                        sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
760
                                        break;
761
                                } else if (j == nb_syms - i - 1) {
762
                                        sec = &shdr[coff_text_shndx];
763
                                        sym->st_size = sec->s_size - ext_sym->e_value;
764
                                        break;
765
                                }
766
                        }
767
                } else if (ext_sym->e_scnum == data_shndx && *(uint8_t *)ext_sym->e_sclass == C_EXTERNAL) {
768
                        for (j = aux_size + 1; j < nb_syms - i; j++) {
769
                                if ((ext_sym + j)->e_scnum == data_shndx) {
770
                                        sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
771
                                        break;
772
                                } else if (j == nb_syms - i - 1) {
773
                                        sec = &shdr[coff_data_shndx];
774
                                        sym->st_size = sec->s_size - ext_sym->e_value;
775
                                        break;
776
                                }
777
                        }
778
                } else {
779
                        sym->st_size = 0;
780
                }
781
                
782
                sym->st_type = ext_sym->e_type;
783
                sym->st_shndx = ext_sym->e_scnum;
784
        }
785

    
786
                
787
    /* find text relocations, if any */
788
    sec = &shdr[coff_text_shndx];
789
    coff_relocs = load_data(fd, sec->s_relptr, sec->s_nreloc*RELSZ);
790
    nb_relocs = sec->s_nreloc;
791

    
792
    /* set coff relocation */
793
    relocs = malloc(sizeof(struct coff_rel) * nb_relocs);
794
    for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs; 
795
         i++, ext_rel++, rel++) {
796
        memset(rel, 0, sizeof(*rel));
797
        rel->r_reloc = ext_rel;
798
        rel->r_offset = *(uint32_t *)ext_rel->r_vaddr;
799
        rel->r_type = *(uint16_t *)ext_rel->r_type;
800
    }
801
    return 0;
802
}
803

    
804
#endif /* CONFIG_FORMAT_COFF */
805

    
806
#ifdef CONFIG_FORMAT_MACH
807

    
808
/* File Header */
809
struct mach_header         mach_hdr;
810

    
811
/* commands */
812
struct segment_command         *segment = 0;
813
struct dysymtab_command *dysymtabcmd = 0;
814
struct symtab_command         *symtabcmd = 0;
815

    
816
/* section */
817
struct section         *section_hdr;
818
struct section *text_sec_hdr;
819
uint8_t         **sdata;
820

    
821
/* relocs */
822
struct relocation_info *relocs;
823
        
824
/* symbols */
825
EXE_SYM                        *symtab;
826
struct nlist         *symtab_std;
827
char                        *strtab;
828

    
829
/* indirect symbols */
830
uint32_t         *tocdylib;
831

    
832
/* Utility functions */
833

    
834
static inline char *find_str_by_index(int index)
835
{
836
    return strtab+index;
837
}
838

    
839
/* Used by dyngen common code */
840
static char *get_sym_name(EXE_SYM *sym)
841
{
842
        char *name = find_str_by_index(sym->n_un.n_strx);
843
        
844
        if ( sym->n_type & N_STAB ) /* Debug symbols are ignored */
845
                return "debug";
846
                        
847
        if(!name)
848
                return name;
849
        if(name[0]=='_')
850
                return name + 1;
851
        else
852
                return name;
853
}
854

    
855
/* find a section index given its segname, sectname */
856
static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname, 
857
                                  const char *sectname)
858
{
859
    int i;
860
    struct section *sec = section_hdr;
861

    
862
    for(i = 0; i < shnum; i++, sec++) {
863
        if (!sec->segname || !sec->sectname)
864
            continue;
865
        if (!strcmp(sec->sectname, sectname) && !strcmp(sec->segname, segname))
866
            return i;
867
    }
868
    return -1;
869
}
870

    
871
/* find a section header given its segname, sectname */
872
struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname, 
873
                                  const char *sectname)
874
{
875
    int index = find_mach_sec_index(section_hdr, shnum, segname, sectname);
876
        if(index == -1)
877
                return NULL;
878
        return section_hdr+index;
879
}
880

    
881

    
882
static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned int *value)
883
{
884
    struct scattered_relocation_info * scarel;
885
        
886
    if(R_SCATTERED & rel->r_address) {
887
        scarel = (struct scattered_relocation_info*)rel;
888
        if(scarel->r_type != PPC_RELOC_PAIR)
889
            error("fetch_next_pair_value: looking for a pair which was not found (1)");
890
        *value = scarel->r_value;
891
    } else {
892
                if(rel->r_type != PPC_RELOC_PAIR)
893
                        error("fetch_next_pair_value: looking for a pair which was not found (2)");
894
                *value = rel->r_address;
895
        }
896
}
897

    
898
/* find a sym name given its value, in a section number */
899
static const char * find_sym_with_value_and_sec_number( int value, int sectnum, int * offset )
900
{
901
        int i, ret = -1;
902
        
903
        for( i = 0 ; i < nb_syms; i++ )
904
        {
905
            if( !(symtab[i].n_type & N_STAB) && (symtab[i].n_type & N_SECT) &&
906
                         (symtab[i].n_sect ==  sectnum) && (symtab[i].st_value <= value) )
907
                {
908
                        if( (ret<0) || (symtab[i].st_value >= symtab[ret].st_value) )
909
                                ret = i;
910
                }
911
        }
912
        if( ret < 0 ) {
913
                *offset = 0;
914
                return 0;
915
        } else {
916
                *offset = value - symtab[ret].st_value;
917
                return get_sym_name(&symtab[ret]);
918
        }
919
}
920

    
921
/* 
922
 *  Find symbol name given a (virtual) address, and a section which is of type 
923
 *  S_NON_LAZY_SYMBOL_POINTERS or S_LAZY_SYMBOL_POINTERS or S_SYMBOL_STUBS
924
 */
925
static const char * find_reloc_name_in_sec_ptr(int address, struct section * sec_hdr)
926
{
927
    unsigned int tocindex, symindex, size;
928
    const char *name = 0;
929
    
930
    /* Sanity check */
931
    if(!( address >= sec_hdr->addr && address < (sec_hdr->addr + sec_hdr->size) ) )
932
        return (char*)0;
933
                
934
        if( sec_hdr->flags & S_SYMBOL_STUBS ){
935
                size = sec_hdr->reserved2;
936
                if(size == 0)
937
                    error("size = 0");
938
                
939
        }
940
        else if( sec_hdr->flags & S_LAZY_SYMBOL_POINTERS ||
941
                    sec_hdr->flags & S_NON_LAZY_SYMBOL_POINTERS)
942
                size = sizeof(unsigned long);
943
        else
944
                return 0;
945
                
946
    /* Compute our index in toc */
947
        tocindex = (address - sec_hdr->addr)/size;
948
        symindex = tocdylib[sec_hdr->reserved1 + tocindex];
949
        
950
        name = get_sym_name(&symtab[symindex]);
951

    
952
    return name;
953
}
954

    
955
static const char * find_reloc_name_given_its_address(int address)
956
{
957
    unsigned int i;
958
    for(i = 0; i < segment->nsects ; i++)
959
    {
960
        const char * name = find_reloc_name_in_sec_ptr(address, &section_hdr[i]);
961
        if((long)name != -1)
962
            return name;
963
    }
964
    return 0;
965
}
966

    
967
static const char * get_reloc_name(EXE_RELOC * rel, int * sslide)
968
{
969
        char * name = 0;
970
        struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
971
        int sectnum = rel->r_symbolnum;
972
        int sectoffset;
973
        int other_half=0;
974
        
975
        /* init the slide value */
976
        *sslide = 0;
977
        
978
        if(R_SCATTERED & rel->r_address)
979
                return (char *)find_reloc_name_given_its_address(sca_rel->r_value);
980

    
981
        if(rel->r_extern)
982
        {
983
                /* ignore debug sym */
984
                if ( symtab[rel->r_symbolnum].n_type & N_STAB ) 
985
                        return 0;
986
                return get_sym_name(&symtab[rel->r_symbolnum]);
987
        }
988

    
989
        /* Intruction contains an offset to the symbols pointed to, in the rel->r_symbolnum section */
990
        sectoffset = *(uint32_t *)(text + rel->r_address) & 0xffff;
991
                        
992
        if(sectnum==0xffffff)
993
                return 0;
994

    
995
        /* Sanity Check */
996
        if(sectnum > segment->nsects)
997
                error("sectnum > segment->nsects");
998

    
999
        switch(rel->r_type)
1000
        {
1001
                case PPC_RELOC_LO16: fetch_next_pair_value(rel+1, &other_half); sectoffset |= (other_half << 16);
1002
                        break;
1003
                case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) | (uint16_t)(other_half & 0xffff);
1004
                        break;
1005
                case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) + (int16_t)(other_half & 0xffff);
1006
                        break;
1007
                case PPC_RELOC_BR24:
1008
                        sectoffset = ( *(uint32_t *)(text + rel->r_address) & 0x03fffffc );
1009
                        if (sectoffset & 0x02000000) sectoffset |= 0xfc000000;
1010
                        break;
1011
                default:
1012
                        error("switch(rel->type) not found");
1013
        }
1014

    
1015
        if(rel->r_pcrel)
1016
                sectoffset += rel->r_address;
1017
                        
1018
        if (rel->r_type == PPC_RELOC_BR24)
1019
                name = (char *)find_reloc_name_in_sec_ptr((int)sectoffset, &section_hdr[sectnum-1]);
1020

    
1021
        /* search it in the full symbol list, if not found */
1022
        if(!name)
1023
                name = (char *)find_sym_with_value_and_sec_number(sectoffset, sectnum, sslide);
1024
        
1025
        return name;
1026
}
1027

    
1028
/* Used by dyngen common code */
1029
static const char * get_rel_sym_name(EXE_RELOC * rel)
1030
{
1031
        int sslide;
1032
        return get_reloc_name( rel, &sslide);
1033
}
1034

    
1035
/* Used by dyngen common code */
1036
static host_ulong get_rel_offset(EXE_RELOC *rel)
1037
{
1038
        struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
1039
    if(R_SCATTERED & rel->r_address)
1040
                return sca_rel->r_address;
1041
        else
1042
                return rel->r_address;
1043
}
1044

    
1045
/* load a mach-o object file */
1046
int load_object(const char *filename)
1047
{
1048
        int fd;
1049
        unsigned int offset_to_segment = 0;
1050
    unsigned int offset_to_dysymtab = 0;
1051
    unsigned int offset_to_symtab = 0;
1052
    struct load_command lc;
1053
    unsigned int i, j;
1054
        EXE_SYM *sym;
1055
        struct nlist *syment;
1056
    
1057
        fd = open(filename, O_RDONLY);
1058
    if (fd < 0) 
1059
        error("can't open file '%s'", filename);
1060
                
1061
    /* Read Mach header.  */
1062
    if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
1063
        error("unable to read file header");
1064

    
1065
    /* Check Mach identification.  */
1066
    if (!check_mach_header(mach_hdr)) {
1067
        error("bad Mach header");
1068
    }
1069
    
1070
    if (mach_hdr.cputype != CPU_TYPE_POWERPC)
1071
        error("Unsupported CPU");
1072
        
1073
    if (mach_hdr.filetype != MH_OBJECT)
1074
        error("Unsupported Mach Object");
1075
    
1076
    /* read segment headers */
1077
    for(i=0, j=sizeof(mach_hdr); i<mach_hdr.ncmds ; i++)
1078
    {
1079
        if(read(fd, &lc, sizeof(struct load_command)) != sizeof(struct load_command))
1080
            error("unable to read load_command");
1081
        if(lc.cmd == LC_SEGMENT)
1082
        {
1083
            offset_to_segment = j;
1084
            lseek(fd, offset_to_segment, SEEK_SET);
1085
            segment = malloc(sizeof(struct segment_command));
1086
            if(read(fd, segment, sizeof(struct segment_command)) != sizeof(struct segment_command))
1087
                error("unable to read LC_SEGMENT");
1088
        }
1089
        if(lc.cmd == LC_DYSYMTAB)
1090
        {
1091
            offset_to_dysymtab = j;
1092
            lseek(fd, offset_to_dysymtab, SEEK_SET);
1093
            dysymtabcmd = malloc(sizeof(struct dysymtab_command));
1094
            if(read(fd, dysymtabcmd, sizeof(struct dysymtab_command)) != sizeof(struct dysymtab_command))
1095
                error("unable to read LC_DYSYMTAB");
1096
        }
1097
        if(lc.cmd == LC_SYMTAB)
1098
        {
1099
            offset_to_symtab = j;
1100
            lseek(fd, offset_to_symtab, SEEK_SET);
1101
            symtabcmd = malloc(sizeof(struct symtab_command));
1102
            if(read(fd, symtabcmd, sizeof(struct symtab_command)) != sizeof(struct symtab_command))
1103
                error("unable to read LC_SYMTAB");
1104
        }
1105
        j+=lc.cmdsize;
1106

    
1107
        lseek(fd, j, SEEK_SET);
1108
    }
1109

    
1110
    if(!segment)
1111
        error("unable to find LC_SEGMENT");
1112

    
1113
    /* read section headers */
1114
    section_hdr = load_data(fd, offset_to_segment + sizeof(struct segment_command), segment->nsects * sizeof(struct section));
1115

    
1116
    /* read all section data */
1117
    sdata = (uint8_t **)malloc(sizeof(void *) * segment->nsects);
1118
    memset(sdata, 0, sizeof(void *) * segment->nsects);
1119
    
1120
        /* Load the data in section data */
1121
        for(i = 0; i < segment->nsects; i++) {
1122
        sdata[i] = load_data(fd, section_hdr[i].offset, section_hdr[i].size);
1123
    }
1124
        
1125
    /* text section */
1126
        text_sec_hdr = find_mach_sec_hdr(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
1127
        i = find_mach_sec_index(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
1128
        if (i == -1 || !text_sec_hdr)
1129
        error("could not find __TEXT,__text section");
1130
    text = sdata[i];
1131
        
1132
    /* Make sure dysym was loaded */
1133
    if(!(int)dysymtabcmd)
1134
        error("could not find __DYSYMTAB segment");
1135
    
1136
    /* read the table of content of the indirect sym */
1137
    tocdylib = load_data( fd, dysymtabcmd->indirectsymoff, dysymtabcmd->nindirectsyms * sizeof(uint32_t) );
1138
    
1139
    /* Make sure symtab was loaded  */
1140
    if(!(int)symtabcmd)
1141
        error("could not find __SYMTAB segment");
1142
    nb_syms = symtabcmd->nsyms;
1143

    
1144
    symtab_std = load_data(fd, symtabcmd->symoff, symtabcmd->nsyms * sizeof(struct nlist));
1145
    strtab = load_data(fd, symtabcmd->stroff, symtabcmd->strsize);
1146
        
1147
        symtab = malloc(sizeof(EXE_SYM) * nb_syms);
1148
        
1149
        /* Now transform the symtab, to an extended version, with the sym size, and the C name */
1150
        for(i = 0, sym = symtab, syment = symtab_std; i < nb_syms; i++, sym++, syment++) {
1151
        struct nlist *sym_follow, *sym_next = 0;
1152
        unsigned int j;
1153
                memset(sym, 0, sizeof(*sym));
1154
                
1155
                if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
1156
            continue;
1157
                        
1158
                memcpy(sym, syment, sizeof(*syment));
1159
                        
1160
                /* Find the following symbol in order to get the current symbol size */
1161
        for(j = 0, sym_follow = symtab_std; j < nb_syms; j++, sym_follow++) {
1162
            if ( sym_follow->n_sect != 1 || sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value))
1163
                continue;
1164
            if(!sym_next) {
1165
                sym_next = sym_follow;
1166
                continue;
1167
            }
1168
            if(!(sym_next->n_value > sym_follow->n_value))
1169
                continue;
1170
            sym_next = sym_follow;
1171
        }
1172
                if(sym_next)
1173
            sym->st_size = sym_next->n_value - sym->st_value;
1174
                else
1175
            sym->st_size = text_sec_hdr->size - sym->st_value;
1176
        }
1177
        
1178
    /* Find Reloc */
1179
    relocs = load_data(fd, text_sec_hdr->reloff, text_sec_hdr->nreloc * sizeof(struct relocation_info));
1180
    nb_relocs = text_sec_hdr->nreloc;
1181

    
1182
        close(fd);
1183
        return 0;
1184
}
1185

    
1186
#endif /* CONFIG_FORMAT_MACH */
1187

    
1188
void get_reloc_expr(char *name, int name_size, const char *sym_name)
1189
{
1190
    const char *p;
1191

    
1192
    if (strstart(sym_name, "__op_param", &p)) {
1193
        snprintf(name, name_size, "param%s", p);
1194
    } else if (strstart(sym_name, "__op_gen_label", &p)) {
1195
        snprintf(name, name_size, "gen_labels[param%s]", p);
1196
    } else {
1197
#ifdef HOST_SPARC
1198
        if (sym_name[0] == '.')
1199
            snprintf(name, name_size,
1200
                     "(long)(&__dot_%s)",
1201
                     sym_name + 1);
1202
        else
1203
#endif
1204
            snprintf(name, name_size, "(long)(&%s)", sym_name);
1205
    }
1206
}
1207

    
1208
#ifdef HOST_IA64
1209

    
1210
#define PLT_ENTRY_SIZE        16        /* 1 bundle containing "brl" */
1211

    
1212
struct plt_entry {
1213
    struct plt_entry *next;
1214
    const char *name;
1215
    unsigned long addend;
1216
} *plt_list;
1217

    
1218
static int
1219
get_plt_index (const char *name, unsigned long addend)
1220
{
1221
    struct plt_entry *plt, *prev= NULL;
1222
    int index = 0;
1223

    
1224
    /* see if we already have an entry for this target: */
1225
    for (plt = plt_list; plt; ++index, prev = plt, plt = plt->next)
1226
        if (strcmp(plt->name, name) == 0 && plt->addend == addend)
1227
            return index;
1228

    
1229
    /* nope; create a new PLT entry: */
1230

    
1231
    plt = malloc(sizeof(*plt));
1232
    if (!plt) {
1233
        perror("malloc");
1234
        exit(1);
1235
    }
1236
    memset(plt, 0, sizeof(*plt));
1237
    plt->name = strdup(name);
1238
    plt->addend = addend;
1239

    
1240
    /* append to plt-list: */
1241
    if (prev)
1242
        prev->next = plt;
1243
    else
1244
        plt_list = plt;
1245
    return index;
1246
}
1247

    
1248
#endif
1249

    
1250
#ifdef HOST_ARM
1251

    
1252
int arm_emit_ldr_info(const char *name, unsigned long start_offset,
1253
                      FILE *outfile, uint8_t *p_start, uint8_t *p_end,
1254
                      ELF_RELOC *relocs, int nb_relocs)
1255
{
1256
    uint8_t *p;
1257
    uint32_t insn;
1258
    int offset, min_offset, pc_offset, data_size, spare, max_pool;
1259
    uint8_t data_allocated[1024];
1260
    unsigned int data_index;
1261
    int type;
1262
    
1263
    memset(data_allocated, 0, sizeof(data_allocated));
1264
    
1265
    p = p_start;
1266
    min_offset = p_end - p_start;
1267
    spare = 0x7fffffff;
1268
    while (p < p_start + min_offset) {
1269
        insn = get32((uint32_t *)p);
1270
        /* TODO: Armv5e ldrd.  */
1271
        /* TODO: VFP load.  */
1272
        if ((insn & 0x0d5f0000) == 0x051f0000) {
1273
            /* ldr reg, [pc, #im] */
1274
            offset = insn & 0xfff;
1275
            if (!(insn & 0x00800000))
1276
                offset = -offset;
1277
            max_pool = 4096;
1278
            type = 0;
1279
        } else if ((insn & 0x0e5f0f00) == 0x0c1f0100) {
1280
            /* FPA ldf.  */
1281
            offset = (insn & 0xff) << 2;
1282
            if (!(insn & 0x00800000))
1283
                offset = -offset;
1284
            max_pool = 1024;
1285
            type = 1;
1286
        } else if ((insn & 0x0fff0000) == 0x028f0000) {
1287
            /* Some gcc load a doubleword immediate with
1288
               add regN, pc, #imm
1289
               ldmia regN, {regN, regM}
1290
               Hope and pray the compiler never generates somethin like
1291
               add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */
1292
            int r;
1293

    
1294
            r = (insn & 0xf00) >> 7;
1295
            offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r));
1296
            max_pool = 1024;
1297
            type = 2;
1298
        } else {
1299
            max_pool = 0;
1300
            type = -1;
1301
        }
1302
        if (type >= 0) {
1303
            /* PC-relative load needs fixing up.  */
1304
            if (spare > max_pool - offset)
1305
                spare = max_pool - offset;
1306
            if ((offset & 3) !=0)
1307
                error("%s:%04x: pc offset must be 32 bit aligned", 
1308
                      name, start_offset + p - p_start);
1309
            if (offset < 0)
1310
                error("%s:%04x: Embedded literal value",
1311
                      name, start_offset + p - p_start);
1312
            pc_offset = p - p_start + offset + 8;
1313
            if (pc_offset <= (p - p_start) || 
1314
                pc_offset >= (p_end - p_start))
1315
                error("%s:%04x: pc offset must point inside the function code", 
1316
                      name, start_offset + p - p_start);
1317
            if (pc_offset < min_offset)
1318
                min_offset = pc_offset;
1319
            if (outfile) {
1320
                /* The intruction position */
1321
                fprintf(outfile, "    arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", 
1322
                        p - p_start);
1323
                /* The position of the constant pool data.  */
1324
                data_index = ((p_end - p_start) - pc_offset) >> 2;
1325
                fprintf(outfile, "    arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n", 
1326
                        data_index);
1327
                fprintf(outfile, "    arm_ldr_ptr->type = %d;\n", type);
1328
                fprintf(outfile, "    arm_ldr_ptr++;\n");
1329
            }
1330
        }
1331
        p += 4;
1332
    }
1333

    
1334
    /* Copy and relocate the constant pool data.  */
1335
    data_size = (p_end - p_start) - min_offset;
1336
    if (data_size > 0 && outfile) {
1337
        spare += min_offset;
1338
        fprintf(outfile, "    arm_data_ptr -= %d;\n", data_size >> 2);
1339
        fprintf(outfile, "    arm_pool_ptr -= %d;\n", data_size);
1340
        fprintf(outfile, "    if (arm_pool_ptr > gen_code_ptr + %d)\n"
1341
                         "        arm_pool_ptr = gen_code_ptr + %d;\n",
1342
                         spare, spare);
1343

    
1344
        data_index = 0;
1345
        for (pc_offset = min_offset;
1346
             pc_offset < p_end - p_start;
1347
             pc_offset += 4) {
1348

    
1349
            ELF_RELOC *rel;
1350
            int i, addend, type;
1351
            const char *sym_name;
1352
            char relname[1024];
1353

    
1354
            /* data value */
1355
            addend = get32((uint32_t *)(p_start + pc_offset));
1356
            relname[0] = '\0';
1357
            for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1358
                if (rel->r_offset == (pc_offset + start_offset)) {
1359
                    sym_name = get_rel_sym_name(rel);
1360
                    /* the compiler leave some unnecessary references to the code */
1361
                    get_reloc_expr(relname, sizeof(relname), sym_name);
1362
                    type = ELF32_R_TYPE(rel->r_info);
1363
                    if (type != R_ARM_ABS32)
1364
                        error("%s: unsupported data relocation", name);
1365
                    break;
1366
                }
1367
            }
1368
            fprintf(outfile, "    arm_data_ptr[%d] = 0x%x",
1369
                    data_index, addend);
1370
            if (relname[0] != '\0')
1371
                fprintf(outfile, " + %s", relname);
1372
            fprintf(outfile, ";\n");
1373

    
1374
            data_index++;
1375
        }
1376
    }
1377

    
1378
    if (p == p_start)
1379
        goto arm_ret_error;
1380
    p -= 4;
1381
    insn = get32((uint32_t *)p);
1382
    /* The last instruction must be an ldm instruction.  There are several
1383
       forms generated by gcc:
1384
        ldmib sp, {..., pc}  (implies a sp adjustment of +4)
1385
        ldmia sp, {..., pc}
1386
        ldmea fp, {..., pc} */
1387
    if ((insn & 0xffff8000) == 0xe99d8000) {
1388
        if (outfile) {
1389
            fprintf(outfile,
1390
                    "    *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n",
1391
                    p - p_start);
1392
        }
1393
        p += 4;
1394
    } else if ((insn & 0xffff8000) != 0xe89d8000
1395
        && (insn & 0xffff8000) != 0xe91b8000) {
1396
    arm_ret_error:
1397
        if (!outfile)
1398
            printf("%s: invalid epilog\n", name);
1399
    }
1400
    return p - p_start;
1401
}
1402
#endif
1403

    
1404

    
1405
#define MAX_ARGS 3
1406

    
1407
/* generate op code */
1408
void gen_code(const char *name, host_ulong offset, host_ulong size, 
1409
              FILE *outfile, int gen_switch)
1410
{
1411
    int copy_size = 0;
1412
    uint8_t *p_start, *p_end;
1413
    host_ulong start_offset;
1414
    int nb_args, i, n;
1415
    uint8_t args_present[MAX_ARGS];
1416
    const char *sym_name, *p;
1417
    EXE_RELOC *rel;
1418

    
1419
    /* Compute exact size excluding prologue and epilogue instructions.
1420
     * Increment start_offset to skip epilogue instructions, then compute
1421
     * copy_size the indicate the size of the remaining instructions (in
1422
     * bytes).
1423
     */
1424
    p_start = text + offset;
1425
    p_end = p_start + size;
1426
    start_offset = offset;
1427
#if defined(HOST_I386) || defined(HOST_X86_64)
1428
#ifdef CONFIG_FORMAT_COFF
1429
    {
1430
        uint8_t *p;
1431
        p = p_end - 1;
1432
        if (p == p_start)
1433
            error("empty code for %s", name);
1434
        while (*p != 0xc3) {
1435
            p--;
1436
            if (p <= p_start)
1437
                error("ret or jmp expected at the end of %s", name);
1438
        }
1439
        copy_size = p - p_start;
1440
    }
1441
#else
1442
    {
1443
        int len;
1444
        len = p_end - p_start;
1445
        if (len == 0)
1446
            error("empty code for %s", name);
1447
        if (p_end[-1] == 0xc3) {
1448
            len--;
1449
        } else {
1450
            error("ret or jmp expected at the end of %s", name);
1451
        }
1452
        copy_size = len;
1453
    }
1454
#endif    
1455
#elif defined(HOST_PPC)
1456
    {
1457
        uint8_t *p;
1458
        p = (void *)(p_end - 4);
1459
        if (p == p_start)
1460
            error("empty code for %s", name);
1461
        if (get32((uint32_t *)p) != 0x4e800020)
1462
            error("blr expected at the end of %s", name);
1463
        copy_size = p - p_start;
1464
    }
1465
#elif defined(HOST_S390)
1466
    {
1467
        uint8_t *p;
1468
        p = (void *)(p_end - 2);
1469
        if (p == p_start)
1470
            error("empty code for %s", name);
1471
        if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
1472
            error("br %%r14 expected at the end of %s", name);
1473
        copy_size = p - p_start;
1474
    }
1475
#elif defined(HOST_ALPHA)
1476
    {
1477
        uint8_t *p;
1478
        p = p_end - 4;
1479
#if 0
1480
        /* XXX: check why it occurs */
1481
        if (p == p_start)
1482
            error("empty code for %s", name);
1483
#endif
1484
        if (get32((uint32_t *)p) != 0x6bfa8001)
1485
            error("ret expected at the end of %s", name);
1486
        copy_size = p - p_start;            
1487
    }
1488
#elif defined(HOST_IA64)
1489
    {
1490
        uint8_t *p;
1491
        p = (void *)(p_end - 4);
1492
        if (p == p_start)
1493
            error("empty code for %s", name);
1494
        /* br.ret.sptk.many b0;; */
1495
        /* 08 00 84 00 */
1496
        if (get32((uint32_t *)p) != 0x00840008)
1497
            error("br.ret.sptk.many b0;; expected at the end of %s", name);
1498
        copy_size = p_end - p_start;
1499
    }
1500
#elif defined(HOST_SPARC)
1501
    {
1502
#define INSN_SAVE       0x9de3a000
1503
#define INSN_RET        0x81c7e008
1504
#define INSN_RETL       0x81c3e008
1505
#define INSN_RESTORE    0x81e80000
1506
#define INSN_RETURN     0x81cfe008
1507
#define INSN_NOP        0x01000000
1508
#define INSN_ADD_SP     0x9c03a000 // add %sp, nn, %sp
1509
#define INSN_SUB_SP     0x9c23a000 // sub %sp, nn, %sp
1510

    
1511
        uint32_t start_insn, end_insn1, end_insn2;
1512
        uint8_t *p;
1513
        p = (void *)(p_end - 8);
1514
        if (p <= p_start)
1515
            error("empty code for %s", name);
1516
        start_insn = get32((uint32_t *)(p_start + 0x0));
1517
        end_insn1 = get32((uint32_t *)(p + 0x0));
1518
        end_insn2 = get32((uint32_t *)(p + 0x4));
1519
        if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1520
            (start_insn & ~0x1fff) == INSN_ADD_SP) {
1521
            p_start += 0x4;
1522
            start_offset += 0x4;
1523
            if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
1524
                /* SPARC v7: ret; restore; */ ;
1525
            else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
1526
                /* SPARC v9: return; nop; */ ;
1527
            else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
1528
                /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
1529
            else
1530

    
1531
                error("ret; restore; not found at end of %s", name);
1532
        } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1533
            ;
1534
        } else {
1535
            error("No save at the beginning of %s", name);
1536
        }
1537
#if 0
1538
        /* Skip a preceeding nop, if present.  */
1539
        if (p > p_start) {
1540
            skip_insn = get32((uint32_t *)(p - 0x4));
1541
            if (skip_insn == INSN_NOP)
1542
                p -= 4;
1543
        }
1544
#endif
1545
        copy_size = p - p_start;
1546
    }
1547
#elif defined(HOST_SPARC64)
1548
    {
1549
#define INSN_SAVE       0x9de3a000
1550
#define INSN_RET        0x81c7e008
1551
#define INSN_RETL       0x81c3e008
1552
#define INSN_RESTORE    0x81e80000
1553
#define INSN_RETURN     0x81cfe008
1554
#define INSN_NOP        0x01000000
1555
#define INSN_ADD_SP     0x9c03a000 // add %sp, nn, %sp
1556
#define INSN_SUB_SP     0x9c23a000 // sub %sp, nn, %sp
1557

    
1558
        uint32_t start_insn, end_insn1, end_insn2, skip_insn;
1559
        uint8_t *p;
1560
        p = (void *)(p_end - 8);
1561
#if 0
1562
        /* XXX: check why it occurs */
1563
        if (p <= p_start)
1564
            error("empty code for %s", name);
1565
#endif
1566
        start_insn = get32((uint32_t *)(p_start + 0x0));
1567
        end_insn1 = get32((uint32_t *)(p + 0x0));
1568
        end_insn2 = get32((uint32_t *)(p + 0x4));
1569
        if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1570
            (start_insn & ~0x1fff) == INSN_ADD_SP) {
1571
            p_start += 0x4;
1572
            start_offset += 0x4;
1573
            if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
1574
                /* SPARC v7: ret; restore; */ ;
1575
            else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
1576
                /* SPARC v9: return; nop; */ ;
1577
            else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
1578
                /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
1579
            else
1580

    
1581
                error("ret; restore; not found at end of %s", name);
1582
        } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1583
            ;
1584
        } else {
1585
            error("No save at the beginning of %s", name);
1586
        }
1587
        
1588
        /* Skip a preceeding nop, if present.  */
1589
        if (p > p_start) {
1590
            skip_insn = get32((uint32_t *)(p - 0x4));
1591
            if (skip_insn == 0x01000000)
1592
                p -= 4;
1593
        }
1594
        
1595
        copy_size = p - p_start;
1596
    }
1597
#elif defined(HOST_ARM)
1598
    {
1599
        uint32_t insn;
1600

    
1601
        if ((p_end - p_start) <= 16)
1602
            error("%s: function too small", name);
1603
        if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
1604
            (get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 ||
1605
            get32((uint32_t *)(p_start + 8)) != 0xe24cb004)
1606
            error("%s: invalid prolog", name);
1607
        p_start += 12;
1608
        start_offset += 12;
1609
        insn = get32((uint32_t *)p_start);
1610
        if ((insn & 0xffffff00) == 0xe24dd000) {
1611
            /* Stack adjustment.  Assume op uses the frame pointer.  */
1612
            p_start -= 4;
1613
            start_offset -= 4;
1614
        }
1615
        copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, 
1616
                                      relocs, nb_relocs);
1617
    }
1618
#elif defined(HOST_M68K)
1619
    {
1620
        uint8_t *p;
1621
        p = (void *)(p_end - 2);
1622
        if (p == p_start)
1623
            error("empty code for %s", name);
1624
        // remove NOP's, probably added for alignment
1625
        while ((get16((uint16_t *)p) == 0x4e71) &&
1626
               (p>p_start)) 
1627
            p -= 2;
1628
        if (get16((uint16_t *)p) != 0x4e75)
1629
            error("rts expected at the end of %s", name);
1630
        copy_size = p - p_start;
1631
    }
1632
#else
1633
#error unsupported CPU
1634
#endif
1635

    
1636
    /* compute the number of arguments by looking at the relocations */
1637
    for(i = 0;i < MAX_ARGS; i++)
1638
        args_present[i] = 0;
1639

    
1640
    for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1641
        host_ulong offset = get_rel_offset(rel);
1642
        if (offset >= start_offset &&
1643
            offset < start_offset + (p_end - p_start)) {
1644
            sym_name = get_rel_sym_name(rel);
1645
            if(!sym_name)
1646
                continue;
1647
            if (strstart(sym_name, "__op_param", &p) ||
1648
                strstart(sym_name, "__op_gen_label", &p)) {
1649
                n = strtoul(p, NULL, 10);
1650
                if (n > MAX_ARGS)
1651
                    error("too many arguments in %s", name);
1652
                args_present[n - 1] = 1;
1653
            }
1654
        }
1655
    }
1656
    
1657
    nb_args = 0;
1658
    while (nb_args < MAX_ARGS && args_present[nb_args])
1659
        nb_args++;
1660
    for(i = nb_args; i < MAX_ARGS; i++) {
1661
        if (args_present[i])
1662
            error("inconsistent argument numbering in %s", name);
1663
    }
1664

    
1665
    if (gen_switch == 2) {
1666
        fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
1667
    } else if (gen_switch == 1) {
1668

    
1669
        /* output C code */
1670
        fprintf(outfile, "case INDEX_%s: {\n", name);
1671
        if (nb_args > 0) {
1672
            fprintf(outfile, "    long ");
1673
            for(i = 0; i < nb_args; i++) {
1674
                if (i != 0)
1675
                    fprintf(outfile, ", ");
1676
                fprintf(outfile, "param%d", i + 1);
1677
            }
1678
            fprintf(outfile, ";\n");
1679
        }
1680
#if defined(HOST_IA64)
1681
        fprintf(outfile, "    extern char %s;\n", name);
1682
#else
1683
        fprintf(outfile, "    extern void %s();\n", name);
1684
#endif
1685

    
1686
        for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1687
            host_ulong offset = get_rel_offset(rel);
1688
            if (offset >= start_offset &&
1689
                offset < start_offset + (p_end - p_start)) {
1690
                sym_name = get_rel_sym_name(rel);
1691
                if(!sym_name)
1692
                    continue;
1693
                if (*sym_name && 
1694
                    !strstart(sym_name, "__op_param", NULL) &&
1695
                    !strstart(sym_name, "__op_jmp", NULL) &&
1696
                    !strstart(sym_name, "__op_gen_label", NULL)) {
1697
#if defined(HOST_SPARC)
1698
                    if (sym_name[0] == '.') {
1699
                        fprintf(outfile,
1700
                                "extern char __dot_%s __asm__(\"%s\");\n",
1701
                                sym_name+1, sym_name);
1702
                        continue;
1703
                    }
1704
#endif
1705
#if defined(__APPLE__)
1706
/* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */
1707
                    fprintf(outfile, "extern char %s __attribute__((unused));\n", sym_name);
1708
#elif defined(HOST_IA64)
1709
                        if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
1710
                                /*
1711
                                 * PCREL21 br.call targets generally
1712
                                 * are out of range and need to go
1713
                                 * through an "import stub".
1714
                                 */
1715
                                fprintf(outfile, "    extern char %s;\n",
1716
                                        sym_name);
1717
#else
1718
                    fprintf(outfile, "extern char %s;\n", sym_name);
1719
#endif
1720
                }
1721
            }
1722
        }
1723

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

    
1727
        /* emit code offset information */
1728
        {
1729
            EXE_SYM *sym;
1730
            const char *sym_name, *p;
1731
            unsigned long val;
1732
            int n;
1733

    
1734
            for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
1735
                sym_name = get_sym_name(sym);
1736
                if (strstart(sym_name, "__op_label", &p)) {
1737
                    uint8_t *ptr;
1738
                    unsigned long offset;
1739
                    
1740
                    /* test if the variable refers to a label inside
1741
                       the code we are generating */
1742
#ifdef CONFIG_FORMAT_COFF
1743
                    if (sym->st_shndx == text_shndx) {
1744
                        ptr = sdata[coff_text_shndx];
1745
                    } else if (sym->st_shndx == data_shndx) {
1746
                        ptr = sdata[coff_data_shndx];
1747
                    } else {
1748
                        ptr = NULL;
1749
                    }
1750
#elif defined(CONFIG_FORMAT_MACH)
1751
                    if(!sym->n_sect)
1752
                        continue;
1753
                    ptr = sdata[sym->n_sect-1];
1754
#else
1755
                    ptr = sdata[sym->st_shndx];
1756
#endif
1757
                    if (!ptr)
1758
                        error("__op_labelN in invalid section");
1759
                    offset = sym->st_value;
1760
#ifdef CONFIG_FORMAT_MACH
1761
                    offset -= section_hdr[sym->n_sect-1].addr;
1762
#endif
1763
                    val = *(unsigned long *)(ptr + offset);
1764
#ifdef ELF_USES_RELOCA
1765
                    {
1766
                        int reloc_shndx, nb_relocs1, j;
1767

    
1768
                        /* try to find a matching relocation */
1769
                        reloc_shndx = find_reloc(sym->st_shndx);
1770
                        if (reloc_shndx) {
1771
                            nb_relocs1 = shdr[reloc_shndx].sh_size / 
1772
                                shdr[reloc_shndx].sh_entsize;
1773
                            rel = (ELF_RELOC *)sdata[reloc_shndx];
1774
                            for(j = 0; j < nb_relocs1; j++) {
1775
                                if (rel->r_offset == offset) {
1776
                                    val = rel->r_addend;
1777
                                    break;
1778
                                }
1779
                                rel++;
1780
                            }
1781
                        }
1782
                    }
1783
#endif                    
1784
                    if (val >= start_offset && val <= start_offset + copy_size) {
1785
                        n = strtol(p, NULL, 10);
1786
                        fprintf(outfile, "    label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset));
1787
                    }
1788
                }
1789
            }
1790
        }
1791

    
1792
        /* load parameres in variables */
1793
        for(i = 0; i < nb_args; i++) {
1794
            fprintf(outfile, "    param%d = *opparam_ptr++;\n", i + 1);
1795
        }
1796

    
1797
        /* patch relocations */
1798
#if defined(HOST_I386)
1799
            {
1800
                char name[256];
1801
                int type;
1802
                int addend;
1803
                int reloc_offset;
1804
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1805
                if (rel->r_offset >= start_offset &&
1806
                    rel->r_offset < start_offset + copy_size) {
1807
                    sym_name = get_rel_sym_name(rel);
1808
                    if (!sym_name)
1809
                        continue;
1810
                    reloc_offset = rel->r_offset - start_offset;
1811
                    if (strstart(sym_name, "__op_jmp", &p)) {
1812
                        int n;
1813
                        n = strtol(p, NULL, 10);
1814
                        /* __op_jmp relocations are done at
1815
                           runtime to do translated block
1816
                           chaining: the offset of the instruction
1817
                           needs to be stored */
1818
                        fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
1819
                                n, reloc_offset);
1820
                        continue;
1821
                    }
1822

    
1823
                    get_reloc_expr(name, sizeof(name), sym_name);
1824
                    addend = get32((uint32_t *)(text + rel->r_offset));
1825
#ifdef CONFIG_FORMAT_ELF
1826
                    type = ELF32_R_TYPE(rel->r_info);
1827
                    switch(type) {
1828
                    case R_386_32:
1829
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
1830
                                reloc_offset, name, addend);
1831
                        break;
1832
                    case R_386_PC32:
1833
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", 
1834
                                reloc_offset, name, reloc_offset, addend);
1835
                        break;
1836
                    default:
1837
                        error("unsupported i386 relocation (%d)", type);
1838
                    }
1839
#elif defined(CONFIG_FORMAT_COFF)
1840
                    {
1841
                        char *temp_name;
1842
                        int j;
1843
                        EXE_SYM *sym;
1844
                        temp_name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
1845
                        if (!strcmp(temp_name, ".data")) {
1846
                            for (j = 0, sym = symtab; j < nb_syms; j++, sym++) {
1847
                                if (strstart(sym->st_name, sym_name, NULL)) {
1848
                                    addend -= sym->st_value;
1849
                                }
1850
                            }
1851
                        }
1852
                    }
1853
                    type = rel->r_type;
1854
                    switch(type) {
1855
                    case DIR32:
1856
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
1857
                                reloc_offset, name, addend);
1858
                        break;
1859
                    case DISP32:
1860
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", 
1861
                                reloc_offset, name, reloc_offset, addend);
1862
                        break;
1863
                    default:
1864
                        error("unsupported i386 relocation (%d)", type);
1865
                    }
1866
#else
1867
#error unsupport object format
1868
#endif
1869
                }
1870
                }
1871
            }
1872
#elif defined(HOST_X86_64)
1873
            {
1874
                char name[256];
1875
                int type;
1876
                int addend;
1877
                int reloc_offset;
1878
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1879
                if (rel->r_offset >= start_offset &&
1880
                    rel->r_offset < start_offset + copy_size) {
1881
                    sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1882
                    get_reloc_expr(name, sizeof(name), sym_name);
1883
                    type = ELF32_R_TYPE(rel->r_info);
1884
                    addend = rel->r_addend;
1885
                    reloc_offset = rel->r_offset - start_offset;
1886
                    switch(type) {
1887
                    case R_X86_64_32:
1888
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n", 
1889
                                reloc_offset, name, addend);
1890
                        break;
1891
                    case R_X86_64_32S:
1892
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", 
1893
                                reloc_offset, name, addend);
1894
                        break;
1895
                    case R_X86_64_PC32:
1896
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", 
1897
                                reloc_offset, name, reloc_offset, addend);
1898
                        break;
1899
                    default:
1900
                        error("unsupported X86_64 relocation (%d)", type);
1901
                    }
1902
                }
1903
                }
1904
            }
1905
#elif defined(HOST_PPC)
1906
            {
1907
#ifdef CONFIG_FORMAT_ELF
1908
                char name[256];
1909
                int type;
1910
                int addend;
1911
                int reloc_offset;
1912
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1913
                    if (rel->r_offset >= start_offset &&
1914
                        rel->r_offset < start_offset + copy_size) {
1915
                        sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1916
                        reloc_offset = rel->r_offset - start_offset;
1917
                        if (strstart(sym_name, "__op_jmp", &p)) {
1918
                            int n;
1919
                            n = strtol(p, NULL, 10);
1920
                            /* __op_jmp relocations are done at
1921
                               runtime to do translated block
1922
                               chaining: the offset of the instruction
1923
                               needs to be stored */
1924
                            fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
1925
                                    n, reloc_offset);
1926
                            continue;
1927
                        }
1928
                        
1929
                        get_reloc_expr(name, sizeof(name), sym_name);
1930
                        type = ELF32_R_TYPE(rel->r_info);
1931
                        addend = rel->r_addend;
1932
                        switch(type) {
1933
                        case R_PPC_ADDR32:
1934
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
1935
                                    reloc_offset, name, addend);
1936
                            break;
1937
                        case R_PPC_ADDR16_LO:
1938
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", 
1939
                                    reloc_offset, name, addend);
1940
                            break;
1941
                        case R_PPC_ADDR16_HI:
1942
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", 
1943
                                    reloc_offset, name, addend);
1944
                            break;
1945
                        case R_PPC_ADDR16_HA:
1946
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", 
1947
                                    reloc_offset, name, addend);
1948
                            break;
1949
                        case R_PPC_REL24:
1950
                            /* warning: must be at 32 MB distancy */
1951
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n", 
1952
                                    reloc_offset, reloc_offset, name, reloc_offset, addend);
1953
                            break;
1954
                        default:
1955
                            error("unsupported powerpc relocation (%d)", type);
1956
                        }
1957
                    }
1958
                }
1959
#elif defined(CONFIG_FORMAT_MACH)
1960
                                struct scattered_relocation_info *scarel;
1961
                                struct relocation_info * rel;
1962
                                char final_sym_name[256];
1963
                                const char *sym_name;
1964
                                const char *p;
1965
                                int slide, sslide;
1966
                                int i;
1967
        
1968
                                for(i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
1969
                                        unsigned int offset, length, value = 0;
1970
                                        unsigned int type, pcrel, isym = 0;
1971
                                        unsigned int usesym = 0;
1972
                                
1973
                                        if(R_SCATTERED & rel->r_address) {
1974
                                                scarel = (struct scattered_relocation_info*)rel;
1975
                                                offset = (unsigned int)scarel->r_address;
1976
                                                length = scarel->r_length;
1977
                                                pcrel = scarel->r_pcrel;
1978
                                                type = scarel->r_type;
1979
                                                value = scarel->r_value;
1980
                                        } else {
1981
                                                value = isym = rel->r_symbolnum;
1982
                                                usesym = (rel->r_extern);
1983
                                                offset = rel->r_address;
1984
                                                length = rel->r_length;
1985
                                                pcrel = rel->r_pcrel;
1986
                                                type = rel->r_type;
1987
                                        }
1988
                                
1989
                                        slide = offset - start_offset;
1990
                
1991
                                        if (!(offset >= start_offset && offset < start_offset + size)) 
1992
                                                continue;  /* not in our range */
1993

    
1994
                                        sym_name = get_reloc_name(rel, &sslide);
1995
                                        
1996
                                        if(usesym && symtab[isym].n_type & N_STAB)
1997
                                                continue; /* don't handle STAB (debug sym) */
1998
                                        
1999
                                        if (sym_name && strstart(sym_name, "__op_jmp", &p)) {
2000
                                                int n;
2001
                                                n = strtol(p, NULL, 10);
2002
                                                fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
2003
                                                        n, slide);
2004
                                                continue; /* Nothing more to do */
2005
                                        }
2006
                                        
2007
                                        if(!sym_name)
2008
                                        {
2009
                                                fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n",
2010
                                                           name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type);
2011
                                                continue; /* dunno how to handle without final_sym_name */
2012
                                        }
2013
                                                                                                           
2014
                                        get_reloc_expr(final_sym_name, sizeof(final_sym_name), 
2015
                                                       sym_name);
2016
                                        switch(type) {
2017
                                        case PPC_RELOC_BR24:
2018
                                            if (!strstart(sym_name,"__op_gen_label",&p)) {
2019
                                                    fprintf(outfile, "{\n");
2020
                                                    fprintf(outfile, "    uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
2021
                                                    fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n", 
2022
                                                                                        slide, slide, name, sslide );
2023
                                                    fprintf(outfile, "}\n");
2024
                                            } else {
2025
                                                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
2026
                                                                                        slide, slide, final_sym_name, slide);
2027
                                            }
2028
                                                break;
2029
                                        case PPC_RELOC_HI16:
2030
                                                fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n", 
2031
                                                        slide, final_sym_name, sslide);
2032
                                                break;
2033
                                        case PPC_RELOC_LO16:
2034
                                                fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n", 
2035
                                        slide, final_sym_name, sslide);
2036
                            break;
2037
                                        case PPC_RELOC_HA16:
2038
                                                fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n", 
2039
                                                        slide, final_sym_name, sslide);
2040
                                                break;
2041
                                default:
2042
                                        error("unsupported powerpc relocation (%d)", type);
2043
                                }
2044
                        }
2045
#else
2046
#error unsupport object format
2047
#endif
2048
            }
2049
#elif defined(HOST_S390)
2050
            {
2051
                char name[256];
2052
                int type;
2053
                int addend;
2054
                int reloc_offset;
2055
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2056
                    if (rel->r_offset >= start_offset &&
2057
                        rel->r_offset < start_offset + copy_size) {
2058
                        sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2059
                        get_reloc_expr(name, sizeof(name), sym_name);
2060
                        type = ELF32_R_TYPE(rel->r_info);
2061
                        addend = rel->r_addend;
2062
                        reloc_offset = rel->r_offset - start_offset;
2063
                        switch(type) {
2064
                        case R_390_32:
2065
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
2066
                                    reloc_offset, name, addend);
2067
                            break;
2068
                        case R_390_16:
2069
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", 
2070
                                    reloc_offset, name, addend);
2071
                            break;
2072
                        case R_390_8:
2073
                            fprintf(outfile, "    *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", 
2074
                                    reloc_offset, name, addend);
2075
                            break;
2076
                        default:
2077
                            error("unsupported s390 relocation (%d)", type);
2078
                        }
2079
                    }
2080
                }
2081
            }
2082
#elif defined(HOST_ALPHA)
2083
            {
2084
                for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
2085
                    if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
2086
                        int type;
2087
                        long reloc_offset;
2088

    
2089
                        type = ELF64_R_TYPE(rel->r_info);
2090
                        sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
2091
                        reloc_offset = rel->r_offset - start_offset;
2092
                        switch (type) {
2093
                        case R_ALPHA_GPDISP:
2094
                            /* The gp is just 32 bit, and never changes, so it's easiest to emit it
2095
                               as an immediate instead of constructing it from the pv or ra.  */
2096
                            fprintf(outfile, "    immediate_ldah(gen_code_ptr + %ld, gp);\n",
2097
                                    reloc_offset);
2098
                            fprintf(outfile, "    immediate_lda(gen_code_ptr + %ld, gp);\n",
2099
                                    reloc_offset + (int)rel->r_addend);
2100
                            break;
2101
                        case R_ALPHA_LITUSE:
2102
                            /* jsr to literal hint. Could be used to optimize to bsr. Ignore for
2103
                               now, since some called functions (libc) need pv to be set up.  */
2104
                            break;
2105
                        case R_ALPHA_HINT:
2106
                            /* Branch target prediction hint. Ignore for now.  Should be already
2107
                               correct for in-function jumps.  */
2108
                            break;
2109
                        case R_ALPHA_LITERAL:
2110
                            /* Load a literal from the GOT relative to the gp.  Since there's only a
2111
                               single gp, nothing is to be done.  */
2112
                            break;
2113
                        case R_ALPHA_GPRELHIGH:
2114
                            /* Handle fake relocations against __op_param symbol.  Need to emit the
2115
                               high part of the immediate value instead.  Other symbols need no
2116
                               special treatment.  */
2117
                            if (strstart(sym_name, "__op_param", &p))
2118
                                fprintf(outfile, "    immediate_ldah(gen_code_ptr + %ld, param%s);\n",
2119
                                        reloc_offset, p);
2120
                            break;
2121
                        case R_ALPHA_GPRELLOW:
2122
                            if (strstart(sym_name, "__op_param", &p))
2123
                                fprintf(outfile, "    immediate_lda(gen_code_ptr + %ld, param%s);\n",
2124
                                        reloc_offset, p);
2125
                            break;
2126
                        case R_ALPHA_BRSGP:
2127
                            /* PC-relative jump. Tweak offset to skip the two instructions that try to
2128
                               set up the gp from the pv.  */
2129
                            fprintf(outfile, "    fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
2130
                                    reloc_offset, sym_name, reloc_offset);
2131
                            break;
2132
                        default:
2133
                            error("unsupported Alpha relocation (%d)", type);
2134
                        }
2135
                    }
2136
                }
2137
            }
2138
#elif defined(HOST_IA64)
2139
            {
2140
                unsigned long sym_idx;
2141
                long code_offset;
2142
                char name[256];
2143
                int type;
2144
                long addend;
2145

    
2146
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2147
                    sym_idx = ELF64_R_SYM(rel->r_info);
2148
                    if (rel->r_offset < start_offset
2149
                        || rel->r_offset >= start_offset + copy_size)
2150
                        continue;
2151
                    sym_name = (strtab + symtab[sym_idx].st_name);
2152
                    code_offset = rel->r_offset - start_offset;
2153
                    if (strstart(sym_name, "__op_jmp", &p)) {
2154
                        int n;
2155
                        n = strtol(p, NULL, 10);
2156
                        /* __op_jmp relocations are done at
2157
                           runtime to do translated block
2158
                           chaining: the offset of the instruction
2159
                           needs to be stored */
2160
                        fprintf(outfile, "    jmp_offsets[%d] ="
2161
                                "%ld + (gen_code_ptr - gen_code_buf);\n",
2162
                                n, code_offset);
2163
                        continue;
2164
                    }
2165
                    get_reloc_expr(name, sizeof(name), sym_name);
2166
                    type = ELF64_R_TYPE(rel->r_info);
2167
                    addend = rel->r_addend;
2168
                    switch(type) {
2169
                      case R_IA64_IMM64:
2170
                          fprintf(outfile,
2171
                                  "    ia64_imm64(gen_code_ptr + %ld, "
2172
                                  "%s + %ld);\n",
2173
                                  code_offset, name, addend);
2174
                          break;
2175
                      case R_IA64_LTOFF22X:
2176
                      case R_IA64_LTOFF22:
2177
                          fprintf(outfile, "    IA64_LTOFF(gen_code_ptr + %ld,"
2178
                                  " %s + %ld, %d);\n",
2179
                                  code_offset, name, addend,
2180
                                  (type == R_IA64_LTOFF22X));
2181
                          break;
2182
                      case R_IA64_LDXMOV:
2183
                          fprintf(outfile,
2184
                                  "    ia64_ldxmov(gen_code_ptr + %ld,"
2185
                                  " %s + %ld);\n", code_offset, name, addend);
2186
                          break;
2187

    
2188
                      case R_IA64_PCREL21B:
2189
                          if (strstart(sym_name, "__op_gen_label", NULL)) {
2190
                              fprintf(outfile,
2191
                                      "    ia64_imm21b(gen_code_ptr + %ld,"
2192
                                      " (long) (%s + %ld -\n\t\t"
2193
                                      "((long) gen_code_ptr + %ld)) >> 4);\n",
2194
                                      code_offset, name, addend,
2195
                                      code_offset & ~0xfUL);
2196
                          } else {
2197
                              fprintf(outfile,
2198
                                      "    IA64_PLT(gen_code_ptr + %ld, "
2199
                                      "%d);\t/* %s + %ld */\n",
2200
                                      code_offset,
2201
                                      get_plt_index(sym_name, addend),
2202
                                      sym_name, addend);
2203
                          }
2204
                          break;
2205
                      default:
2206
                          error("unsupported ia64 relocation (0x%x)",
2207
                                type);
2208
                    }
2209
                }
2210
                fprintf(outfile, "    ia64_nop_b(gen_code_ptr + %d);\n",
2211
                        copy_size - 16 + 2);
2212
            }
2213
#elif defined(HOST_SPARC)
2214
            {
2215
                char name[256];
2216
                int type;
2217
                int addend;
2218
                int reloc_offset;
2219
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2220
                    if (rel->r_offset >= start_offset &&
2221
                        rel->r_offset < start_offset + copy_size) {
2222
                        sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
2223
                        get_reloc_expr(name, sizeof(name), sym_name);
2224
                        type = ELF32_R_TYPE(rel->r_info);
2225
                        addend = rel->r_addend;
2226
                        reloc_offset = rel->r_offset - start_offset;
2227
                        switch(type) {
2228
                        case R_SPARC_32:
2229
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
2230
                                    reloc_offset, name, addend);
2231
                            break;
2232
                        case R_SPARC_HI22:
2233
                            fprintf(outfile,
2234
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2235
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2236
                                    " & ~0x3fffff) "
2237
                                    " | (((%s + %d) >> 10) & 0x3fffff);\n",
2238
                                    reloc_offset, reloc_offset, name, addend);
2239
                            break;
2240
                        case R_SPARC_LO10:
2241
                            fprintf(outfile,
2242
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2243
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2244
                                    " & ~0x3ff) "
2245
                                    " | ((%s + %d) & 0x3ff);\n",
2246
                                    reloc_offset, reloc_offset, name, addend);
2247
                            break;
2248
                        case R_SPARC_WDISP30:
2249
                            fprintf(outfile,
2250
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2251
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2252
                                    " & ~0x3fffffff) "
2253
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2254
                                    "    & 0x3fffffff);\n",
2255
                                    reloc_offset, reloc_offset, name, addend,
2256
                                    reloc_offset);
2257
                            break;
2258
                        case R_SPARC_WDISP22:
2259
                            fprintf(outfile,
2260
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2261
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2262
                                    " & ~0x3fffff) "
2263
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2264
                                    "    & 0x3fffff);\n",
2265
                                    rel->r_offset - start_offset,
2266
                                    rel->r_offset - start_offset,
2267
                                    name, addend,
2268
                                    rel->r_offset - start_offset);
2269
                            break;
2270
                        default:
2271
                            error("unsupported sparc relocation (%d)", type);
2272
                        }
2273
                    }
2274
                }
2275
            }
2276
#elif defined(HOST_SPARC64)
2277
            {
2278
                char name[256];
2279
                int type;
2280
                int addend;
2281
                int reloc_offset;
2282
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2283
                    if (rel->r_offset >= start_offset &&
2284
                        rel->r_offset < start_offset + copy_size) {
2285
                        sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
2286
                        get_reloc_expr(name, sizeof(name), sym_name);
2287
                        type = ELF32_R_TYPE(rel->r_info);
2288
                        addend = rel->r_addend;
2289
                        reloc_offset = rel->r_offset - start_offset;
2290
                        switch(type) {
2291
                        case R_SPARC_32:
2292
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2293
                                    reloc_offset, name, addend);
2294
                            break;
2295
                        case R_SPARC_HI22:
2296
                            fprintf(outfile,
2297
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2298
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2299
                                    " & ~0x3fffff) "
2300
                                    " | (((%s + %d) >> 10) & 0x3fffff);\n",
2301
                                    reloc_offset, reloc_offset, name, addend);
2302
                            break;
2303
                        case R_SPARC_LO10:
2304
                            fprintf(outfile,
2305
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2306
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2307
                                    " & ~0x3ff) "
2308
                                    " | ((%s + %d) & 0x3ff);\n",
2309
                                    reloc_offset, reloc_offset, name, addend);
2310
                            break;
2311
                        case R_SPARC_OLO10:
2312
                            addend += ELF64_R_TYPE_DATA (rel->r_info);
2313
                            fprintf(outfile,
2314
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2315
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2316
                                    " & ~0x3ff) "
2317
                                    " | ((%s + %d) & 0x3ff);\n",
2318
                                    reloc_offset, reloc_offset, name, addend);
2319
                            break;
2320
                        case R_SPARC_WDISP30:
2321
                            fprintf(outfile,
2322
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2323
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2324
                                    " & ~0x3fffffff) "
2325
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2326
                                    "    & 0x3fffffff);\n",
2327
                                    reloc_offset, reloc_offset, name, addend,
2328
                                    reloc_offset);
2329
                            break;
2330
                        case R_SPARC_WDISP22:
2331
                            fprintf(outfile,
2332
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2333
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2334
                                    " & ~0x3fffff) "
2335
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2336
                                    "    & 0x3fffff);\n",
2337
                                    reloc_offset, reloc_offset, name, addend,
2338
                                    reloc_offset);
2339
                            break;
2340
                        default:
2341
                            error("unsupported sparc64 relocation (%d) for symbol %s", type, name);
2342
                        }
2343
                    }
2344
                }
2345
            }
2346
#elif defined(HOST_ARM)
2347
            {
2348
                char name[256];
2349
                int type;
2350
                int addend;
2351
                int reloc_offset;
2352
                uint32_t insn;
2353

    
2354
                insn = get32((uint32_t *)(p_start + 4));
2355
                /* If prologue ends in sub sp, sp, #const then assume
2356
                   op has a stack frame and needs the frame pointer.  */
2357
                if ((insn & 0xffffff00) == 0xe24dd000) {
2358
                    int i;
2359
                    uint32_t opcode;
2360
                    opcode = 0xe28db000; /* add fp, sp, #0.  */
2361
#if 0
2362
/* ??? Need to undo the extra stack adjustment at the end of the op.
2363
   For now just leave the stack misaligned and hope it doesn't break anything
2364
   too important.  */
2365
                    if ((insn & 4) != 0) {
2366
                        /* Preserve doubleword stack alignment.  */
2367
                        fprintf(outfile,
2368
                                "    *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n",
2369
                                insn + 4);
2370
                        opcode -= 4;
2371
                    }
2372
#endif
2373
                    insn = get32((uint32_t *)(p_start - 4));
2374
                    /* Calculate the size of the saved registers,
2375
                       excluding pc.  */
2376
                    for (i = 0; i < 15; i++) {
2377
                        if (insn & (1 << i))
2378
                            opcode += 4;
2379
                    }
2380
                    fprintf(outfile,
2381
                            "    *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
2382
                }
2383
                arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
2384
                                  relocs, nb_relocs);
2385

    
2386
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2387
                if (rel->r_offset >= start_offset &&
2388
                    rel->r_offset < start_offset + copy_size) {
2389
                    sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2390
                    /* the compiler leave some unnecessary references to the code */
2391
                    if (sym_name[0] == '\0')
2392
                        continue;
2393
                    get_reloc_expr(name, sizeof(name), sym_name);
2394
                    type = ELF32_R_TYPE(rel->r_info);
2395
                    addend = get32((uint32_t *)(text + rel->r_offset));
2396
                    reloc_offset = rel->r_offset - start_offset;
2397
                    switch(type) {
2398
                    case R_ARM_ABS32:
2399
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
2400
                                reloc_offset, name, addend);
2401
                        break;
2402
                    case R_ARM_PC24:
2403
                    case R_ARM_JUMP24:
2404
                    case R_ARM_CALL:
2405
                        fprintf(outfile, "    arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", 
2406
                                reloc_offset, addend, name);
2407
                        break;
2408
                    default:
2409
                        error("unsupported arm relocation (%d)", type);
2410
                    }
2411
                }
2412
                }
2413
            }
2414
#elif defined(HOST_M68K)
2415
            {
2416
                char name[256];
2417
                int type;
2418
                int addend;
2419
                int reloc_offset;
2420
                Elf32_Sym *sym;
2421
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2422
                if (rel->r_offset >= start_offset &&
2423
                    rel->r_offset < start_offset + copy_size) {
2424
                    sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
2425
                    sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2426
                    get_reloc_expr(name, sizeof(name), sym_name);
2427
                    type = ELF32_R_TYPE(rel->r_info);
2428
                    addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
2429
                    reloc_offset = rel->r_offset - start_offset;
2430
                    switch(type) {
2431
                    case R_68K_32:
2432
                        fprintf(outfile, "    /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
2433
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n", 
2434
                                reloc_offset, name, addend );
2435
                        break;
2436
                    case R_68K_PC32:
2437
                        fprintf(outfile, "    /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
2438
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n", 
2439
                                reloc_offset, name, reloc_offset, /*sym->st_value+*/ addend);
2440
                        break;
2441
                    default:
2442
                        error("unsupported m68k relocation (%d)", type);
2443
                    }
2444
                }
2445
                }
2446
            }
2447
#else
2448
#error unsupported CPU
2449
#endif
2450
        fprintf(outfile, "    gen_code_ptr += %d;\n", copy_size);
2451
        fprintf(outfile, "}\n");
2452
        fprintf(outfile, "break;\n\n");
2453
    } else {
2454
        fprintf(outfile, "static inline void gen_%s(", name);
2455
        if (nb_args == 0) {
2456
            fprintf(outfile, "void");
2457
        } else {
2458
            for(i = 0; i < nb_args; i++) {
2459
                if (i != 0)
2460
                    fprintf(outfile, ", ");
2461
                fprintf(outfile, "long param%d", i + 1);
2462
            }
2463
        }
2464
        fprintf(outfile, ")\n");
2465
        fprintf(outfile, "{\n");
2466
        for(i = 0; i < nb_args; i++) {
2467
            fprintf(outfile, "    *gen_opparam_ptr++ = param%d;\n", i + 1);
2468
        }
2469
        fprintf(outfile, "    *gen_opc_ptr++ = INDEX_%s;\n", name);
2470
        fprintf(outfile, "}\n\n");
2471
    }
2472
}
2473

    
2474
int gen_file(FILE *outfile, int out_type)
2475
{
2476
    int i;
2477
    EXE_SYM *sym;
2478

    
2479
    if (out_type == OUT_INDEX_OP) {
2480
        fprintf(outfile, "DEF(end, 0, 0)\n");
2481
        fprintf(outfile, "DEF(nop, 0, 0)\n");
2482
        fprintf(outfile, "DEF(nop1, 1, 0)\n");
2483
        fprintf(outfile, "DEF(nop2, 2, 0)\n");
2484
        fprintf(outfile, "DEF(nop3, 3, 0)\n");
2485
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2486
            const char *name;
2487
            name = get_sym_name(sym);
2488
            if (strstart(name, OP_PREFIX, NULL)) {
2489
                gen_code(name, sym->st_value, sym->st_size, outfile, 2);
2490
            }
2491
        }
2492
    } else if (out_type == OUT_GEN_OP) {
2493
        /* generate gen_xxx functions */
2494
        fprintf(outfile, "#include \"dyngen-op.h\"\n");
2495
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2496
            const char *name;
2497
            name = get_sym_name(sym);
2498
            if (strstart(name, OP_PREFIX, NULL)) {
2499
#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
2500
                if (sym->st_shndx != text_shndx)
2501
                    error("invalid section for opcode (0x%x)", sym->st_shndx);
2502
#endif
2503
                gen_code(name, sym->st_value, sym->st_size, outfile, 0);
2504
            }
2505
        }
2506
        
2507
    } else {
2508
        /* generate big code generation switch */
2509

    
2510
#ifdef HOST_ARM
2511
        /* We need to know the size of all the ops so we can figure out when
2512
           to emit constant pools.  This must be consistent with opc.h.  */
2513
fprintf(outfile,
2514
"static const uint32_t arm_opc_size[] = {\n"
2515
"  0,\n" /* end */
2516
"  0,\n" /* nop */
2517
"  0,\n" /* nop1 */
2518
"  0,\n" /* nop2 */
2519
"  0,\n"); /* nop3 */
2520
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2521
            const char *name;
2522
            name = get_sym_name(sym);
2523
            if (strstart(name, OP_PREFIX, NULL)) {
2524
                fprintf(outfile, "  %d,\n", sym->st_size);
2525
            }
2526
        }
2527
fprintf(outfile,
2528
"};\n");
2529
#endif
2530

    
2531
fprintf(outfile,
2532
"int dyngen_code(uint8_t *gen_code_buf,\n"
2533
"                uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
2534
"                const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n"
2535
"{\n"
2536
"    uint8_t *gen_code_ptr;\n"
2537
"    const uint16_t *opc_ptr;\n"
2538
"    const uint32_t *opparam_ptr;\n");
2539

    
2540
#ifdef HOST_ARM
2541
/* Arm is tricky because it uses constant pools for loading immediate values.
2542
   We assume (and require) each function is code followed by a constant pool.
2543
   All the ops are small so this should be ok.  For each op we figure
2544
   out how much "spare" range we have in the load instructions.  This allows
2545
   us to insert subsequent ops in between the op and the constant pool,
2546
   eliminating the neeed to jump around the pool.
2547

2548
   We currently generate:
2549
   
2550
   [ For this example we assume merging would move op1_pool out of range.
2551
     In practice we should be able to combine many ops before the offset
2552
     limits are reached. ]
2553
   op1_code;
2554
   op2_code;
2555
   goto op3;
2556
   op2_pool;
2557
   op1_pool;
2558
op3:
2559
   op3_code;
2560
   ret;
2561
   op3_pool;
2562

2563
   Ideally we'd put op1_pool before op2_pool, but that requires two passes.
2564
 */
2565
fprintf(outfile,
2566
"    uint8_t *last_gen_code_ptr = gen_code_buf;\n"
2567
"    LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
2568
"    uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
2569
/* Initialise the parmissible pool offset to an arbitary large value.  */
2570
"    uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
2571
#endif
2572
#ifdef HOST_IA64
2573
    {
2574
        long addend, not_first = 0;
2575
        unsigned long sym_idx;
2576
        int index, max_index;
2577
        const char *sym_name;
2578
        EXE_RELOC *rel;
2579

    
2580
        max_index = -1;
2581
        for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2582
            sym_idx = ELF64_R_SYM(rel->r_info);
2583
            sym_name = (strtab + symtab[sym_idx].st_name);
2584
            if (strstart(sym_name, "__op_gen_label", NULL))
2585
                continue;
2586
            if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
2587
                continue;
2588

    
2589
            addend = rel->r_addend;
2590
            index = get_plt_index(sym_name, addend);
2591
            if (index <= max_index)
2592
                continue;
2593
            max_index = index;
2594
            fprintf(outfile, "    extern void %s(void);\n", sym_name);
2595
        }
2596

    
2597
        fprintf(outfile,
2598
                "    struct ia64_fixup *plt_fixes = NULL, "
2599
                "*ltoff_fixes = NULL;\n"
2600
                "    static long plt_target[] = {\n\t");
2601

    
2602
        max_index = -1;
2603
        for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2604
            sym_idx = ELF64_R_SYM(rel->r_info);
2605
            sym_name = (strtab + symtab[sym_idx].st_name);
2606
            if (strstart(sym_name, "__op_gen_label", NULL))
2607
                continue;
2608
            if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
2609
                continue;
2610

    
2611
            addend = rel->r_addend;
2612
            index = get_plt_index(sym_name, addend);
2613
            if (index <= max_index)
2614
                continue;
2615
            max_index = index;
2616

    
2617
            if (not_first)
2618
                fprintf(outfile, ",\n\t");
2619
            not_first = 1;
2620
            if (addend)
2621
                fprintf(outfile, "(long) &%s + %ld", sym_name, addend);
2622
            else
2623
                fprintf(outfile, "(long) &%s", sym_name);
2624
        }
2625
        fprintf(outfile, "\n    };\n"
2626
            "    unsigned int plt_offset[%u] = { 0 };\n", max_index + 1);
2627
    }
2628
#endif
2629

    
2630
fprintf(outfile,
2631
"\n"
2632
"    gen_code_ptr = gen_code_buf;\n"
2633
"    opc_ptr = opc_buf;\n"
2634
"    opparam_ptr = opparam_buf;\n");
2635

    
2636
        /* Generate prologue, if needed. */ 
2637

    
2638
fprintf(outfile,
2639
"    for(;;) {\n");
2640

    
2641
#ifdef HOST_ARM
2642
/* Generate constant pool if needed */
2643
fprintf(outfile,
2644
"            if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
2645
"                gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
2646
"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n"
2647
"                last_gen_code_ptr = gen_code_ptr;\n"
2648
"                arm_ldr_ptr = arm_ldr_table;\n"
2649
"                arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
2650
"                arm_pool_ptr = gen_code_ptr + 0x1000000;\n"
2651
"            }\n");
2652
#endif
2653

    
2654
fprintf(outfile,
2655
"        switch(*opc_ptr++) {\n");
2656

    
2657
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2658
            const char *name;
2659
            name = get_sym_name(sym);
2660
            if (strstart(name, OP_PREFIX, NULL)) {
2661
#if 0
2662
                printf("%4d: %s pos=0x%08x len=%d\n", 
2663
                       i, name, sym->st_value, sym->st_size);
2664
#endif
2665
#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
2666
                if (sym->st_shndx != text_shndx)
2667
                    error("invalid section for opcode (0x%x)", sym->st_shndx);
2668
#endif
2669
                gen_code(name, sym->st_value, sym->st_size, outfile, 1);
2670
            }
2671
        }
2672

    
2673
fprintf(outfile,
2674
"        case INDEX_op_nop:\n"
2675
"            break;\n"
2676
"        case INDEX_op_nop1:\n"
2677
"            opparam_ptr++;\n"
2678
"            break;\n"
2679
"        case INDEX_op_nop2:\n"
2680
"            opparam_ptr += 2;\n"
2681
"            break;\n"
2682
"        case INDEX_op_nop3:\n"
2683
"            opparam_ptr += 3;\n"
2684
"            break;\n"
2685
"        default:\n"
2686
"            goto the_end;\n"
2687
"        }\n");
2688

    
2689

    
2690
fprintf(outfile,
2691
"    }\n"
2692
" the_end:\n"
2693
);
2694
#ifdef HOST_IA64
2695
    fprintf(outfile,
2696
            "    {\n"
2697
            "      extern char code_gen_buffer[];\n"
2698
            "      ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
2699
            "(uint64_t) code_gen_buffer + 2*(1<<20), plt_fixes,\n\t\t\t"
2700
            "sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t"
2701
            "plt_target, plt_offset);\n    }\n");
2702
#endif
2703

    
2704
/* generate some code patching */ 
2705
#ifdef HOST_ARM
2706
fprintf(outfile,
2707
"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
2708
"    gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
2709
"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");
2710
#endif
2711
    /* flush instruction cache */
2712
    fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
2713

    
2714
    fprintf(outfile, "return gen_code_ptr -  gen_code_buf;\n");
2715
    fprintf(outfile, "}\n\n");
2716

    
2717
    }
2718

    
2719
    return 0;
2720
}
2721

    
2722
void usage(void)
2723
{
2724
    printf("dyngen (c) 2003 Fabrice Bellard\n"
2725
           "usage: dyngen [-o outfile] [-c] objfile\n"
2726
           "Generate a dynamic code generator from an object file\n"
2727
           "-c     output enum of operations\n"
2728
           "-g     output gen_op_xx() functions\n"
2729
           );
2730
    exit(1);
2731
}
2732

    
2733
int main(int argc, char **argv)
2734
{
2735
    int c, out_type;
2736
    const char *filename, *outfilename;
2737
    FILE *outfile;
2738

    
2739
    outfilename = "out.c";
2740
    out_type = OUT_CODE;
2741
    for(;;) {
2742
        c = getopt(argc, argv, "ho:cg");
2743
        if (c == -1)
2744
            break;
2745
        switch(c) {
2746
        case 'h':
2747
            usage();
2748
            break;
2749
        case 'o':
2750
            outfilename = optarg;
2751
            break;
2752
        case 'c':
2753
            out_type = OUT_INDEX_OP;
2754
            break;
2755
        case 'g':
2756
            out_type = OUT_GEN_OP;
2757
            break;
2758
        }
2759
    }
2760
    if (optind >= argc)
2761
        usage();
2762
    filename = argv[optind];
2763
    outfile = fopen(outfilename, "w");
2764
    if (!outfile)
2765
        error("could not open '%s'", outfilename);
2766

    
2767
    load_object(filename);
2768
    gen_file(outfile, out_type);
2769
    fclose(outfile);
2770
    return 0;
2771
}