Statistics
| Branch: | Revision:

root / dyngen.c @ 5fafdf24

History | View | Annotate | Download (94.6 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
#elif defined(HOST_MIPS)
121

    
122
#define ELF_CLASS        ELFCLASS32
123
#define ELF_ARCH        EM_MIPS
124
#define elf_check_arch(x) ((x) == EM_MIPS)
125
#define ELF_USES_RELOC
126

    
127
#elif defined(HOST_MIPS64)
128

    
129
/* Assume n32 ABI here, which is ELF32. */
130
#define ELF_CLASS        ELFCLASS32
131
#define ELF_ARCH        EM_MIPS
132
#define elf_check_arch(x) ((x) == EM_MIPS)
133
#define ELF_USES_RELOCA
134

    
135
#else
136
#error unsupported CPU - please update the code
137
#endif
138

    
139
#include "elf.h"
140

    
141
#if ELF_CLASS == ELFCLASS32
142
typedef int32_t host_long;
143
typedef uint32_t host_ulong;
144
#define swabls(x) swab32s(x)
145
#define swablss(x) swab32ss(x)
146
#else
147
typedef int64_t host_long;
148
typedef uint64_t host_ulong;
149
#define swabls(x) swab64s(x)
150
#define swablss(x) swab64ss(x)
151
#endif
152

    
153
#ifdef ELF_USES_RELOCA
154
#define SHT_RELOC SHT_RELA
155
#else
156
#define SHT_RELOC SHT_REL
157
#endif
158

    
159
#define EXE_RELOC ELF_RELOC
160
#define EXE_SYM ElfW(Sym)
161

    
162
#endif /* CONFIG_FORMAT_ELF */
163

    
164
#ifdef CONFIG_FORMAT_COFF
165

    
166
typedef int32_t host_long;
167
typedef uint32_t host_ulong;
168

    
169
#include "a.out.h"
170

    
171
#define FILENAMELEN 256
172

    
173
typedef struct coff_sym {
174
    struct external_syment *st_syment;
175
    char st_name[FILENAMELEN];
176
    uint32_t st_value;
177
    int  st_size;
178
    uint8_t st_type;
179
    uint8_t st_shndx;
180
} coff_Sym;
181

    
182
typedef struct coff_rel {
183
    struct external_reloc *r_reloc;
184
    int  r_offset;
185
    uint8_t r_type;
186
} coff_Rel;
187

    
188
#define EXE_RELOC struct coff_rel
189
#define EXE_SYM struct coff_sym
190

    
191
#endif /* CONFIG_FORMAT_COFF */
192

    
193
#ifdef CONFIG_FORMAT_MACH
194

    
195
#include <mach-o/loader.h>
196
#include <mach-o/nlist.h>
197
#include <mach-o/reloc.h>
198
#include <mach-o/ppc/reloc.h>
199

    
200
# define check_mach_header(x) (x.magic == MH_MAGIC)
201
typedef int32_t host_long;
202
typedef uint32_t host_ulong;
203

    
204
struct nlist_extended
205
{
206
   union {
207
   char *n_name;
208
   long  n_strx;
209
   } n_un;
210
   unsigned char n_type;
211
   unsigned char n_sect;
212
   short st_desc;
213
   unsigned long st_value;
214
   unsigned long st_size;
215
};
216

    
217
#define EXE_RELOC struct relocation_info
218
#define EXE_SYM struct nlist_extended
219

    
220
#endif /* CONFIG_FORMAT_MACH */
221

    
222
#include "bswap.h"
223

    
224
enum {
225
    OUT_GEN_OP,
226
    OUT_CODE,
227
    OUT_INDEX_OP,
228
};
229

    
230
/* all dynamically generated functions begin with this code */
231
#define OP_PREFIX "op_"
232

    
233
int do_swap;
234

    
235
void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
236
{
237
    va_list ap;
238
    va_start(ap, fmt);
239
    fprintf(stderr, "dyngen: ");
240
    vfprintf(stderr, fmt, ap);
241
    fprintf(stderr, "\n");
242
    va_end(ap);
243
    exit(1);
244
}
245

    
246
void *load_data(int fd, long offset, unsigned int size)
247
{
248
    char *data;
249

    
250
    data = malloc(size);
251
    if (!data)
252
        return NULL;
253
    lseek(fd, offset, SEEK_SET);
254
    if (read(fd, data, size) != size) {
255
        free(data);
256
        return NULL;
257
    }
258
    return data;
259
}
260

    
261
int strstart(const char *str, const char *val, const char **ptr)
262
{
263
    const char *p, *q;
264
    p = str;
265
    q = val;
266
    while (*q != '\0') {
267
        if (*p != *q)
268
            return 0;
269
        p++;
270
        q++;
271
    }
272
    if (ptr)
273
        *ptr = p;
274
    return 1;
275
}
276

    
277
void pstrcpy(char *buf, int buf_size, const char *str)
278
{
279
    int c;
280
    char *q = buf;
281

    
282
    if (buf_size <= 0)
283
        return;
284

    
285
    for(;;) {
286
        c = *str++;
287
        if (c == 0 || q >= buf + buf_size - 1)
288
            break;
289
        *q++ = c;
290
    }
291
    *q = '\0';
292
}
293

    
294
void swab16s(uint16_t *p)
295
{
296
    *p = bswap16(*p);
297
}
298

    
299
void swab32s(uint32_t *p)
300
{
301
    *p = bswap32(*p);
302
}
303

    
304
void swab32ss(int32_t *p)
305
{
306
    *p = bswap32(*p);
307
}
308

    
309
void swab64s(uint64_t *p)
310
{
311
    *p = bswap64(*p);
312
}
313

    
314
void swab64ss(int64_t *p)
315
{
316
    *p = bswap64(*p);
317
}
318

    
319
uint16_t get16(uint16_t *p)
320
{
321
    uint16_t val;
322
    val = *p;
323
    if (do_swap)
324
        val = bswap16(val);
325
    return val;
326
}
327

    
328
uint32_t get32(uint32_t *p)
329
{
330
    uint32_t val;
331
    val = *p;
332
    if (do_swap)
333
        val = bswap32(val);
334
    return val;
335
}
336

    
337
void put16(uint16_t *p, uint16_t val)
338
{
339
    if (do_swap)
340
        val = bswap16(val);
341
    *p = val;
342
}
343

    
344
void put32(uint32_t *p, uint32_t val)
345
{
346
    if (do_swap)
347
        val = bswap32(val);
348
    *p = val;
349
}
350

    
351
/* executable information */
352
EXE_SYM *symtab;
353
int nb_syms;
354
int text_shndx;
355
uint8_t *text;
356
EXE_RELOC *relocs;
357
int nb_relocs;
358

    
359
#ifdef CONFIG_FORMAT_ELF
360

    
361
/* ELF file info */
362
struct elf_shdr *shdr;
363
uint8_t **sdata;
364
struct elfhdr ehdr;
365
char *strtab;
366

    
367
int elf_must_swap(struct elfhdr *h)
368
{
369
  union {
370
      uint32_t i;
371
      uint8_t b[4];
372
  } swaptest;
373

    
374
  swaptest.i = 1;
375
  return (h->e_ident[EI_DATA] == ELFDATA2MSB) !=
376
      (swaptest.b[0] == 0);
377
}
378
 
379
void elf_swap_ehdr(struct elfhdr *h)
380
{
381
    swab16s(&h->e_type);                        /* Object file type */
382
    swab16s(&h->        e_machine);                /* Architecture */
383
    swab32s(&h->        e_version);                /* Object file version */
384
    swabls(&h->        e_entry);                /* Entry point virtual address */
385
    swabls(&h->        e_phoff);                /* Program header table file offset */
386
    swabls(&h->        e_shoff);                /* Section header table file offset */
387
    swab32s(&h->        e_flags);                /* Processor-specific flags */
388
    swab16s(&h->        e_ehsize);                /* ELF header size in bytes */
389
    swab16s(&h->        e_phentsize);                /* Program header table entry size */
390
    swab16s(&h->        e_phnum);                /* Program header table entry count */
391
    swab16s(&h->        e_shentsize);                /* Section header table entry size */
392
    swab16s(&h->        e_shnum);                /* Section header table entry count */
393
    swab16s(&h->        e_shstrndx);                /* Section header string table index */
394
}
395

    
396
void elf_swap_shdr(struct elf_shdr *h)
397
{
398
  swab32s(&h->        sh_name);                /* Section name (string tbl index) */
399
  swab32s(&h->        sh_type);                /* Section type */
400
  swabls(&h->        sh_flags);                /* Section flags */
401
  swabls(&h->        sh_addr);                /* Section virtual addr at execution */
402
  swabls(&h->        sh_offset);                /* Section file offset */
403
  swabls(&h->        sh_size);                /* Section size in bytes */
404
  swab32s(&h->        sh_link);                /* Link to another section */
405
  swab32s(&h->        sh_info);                /* Additional section information */
406
  swabls(&h->        sh_addralign);                /* Section alignment */
407
  swabls(&h->        sh_entsize);                /* Entry size if section holds table */
408
}
409

    
410
void elf_swap_phdr(struct elf_phdr *h)
411
{
412
    swab32s(&h->p_type);                        /* Segment type */
413
    swabls(&h->p_offset);                /* Segment file offset */
414
    swabls(&h->p_vaddr);                /* Segment virtual address */
415
    swabls(&h->p_paddr);                /* Segment physical address */
416
    swabls(&h->p_filesz);                /* Segment size in file */
417
    swabls(&h->p_memsz);                /* Segment size in memory */
418
    swab32s(&h->p_flags);                /* Segment flags */
419
    swabls(&h->p_align);                /* Segment alignment */
420
}
421

    
422
void elf_swap_rel(ELF_RELOC *rel)
423
{
424
    swabls(&rel->r_offset);
425
    swabls(&rel->r_info);
426
#ifdef ELF_USES_RELOCA
427
    swablss(&rel->r_addend);
428
#endif
429
}
430

    
431
struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr,
432
                                  const char *name)
433
{
434
    int i;
435
    const char *shname;
436
    struct elf_shdr *sec;
437

    
438
    for(i = 0; i < shnum; i++) {
439
        sec = &shdr[i];
440
        if (!sec->sh_name)
441
            continue;
442
        shname = shstr + sec->sh_name;
443
        if (!strcmp(shname, name))
444
            return sec;
445
    }
446
    return NULL;
447
}
448

    
449
int find_reloc(int sh_index)
450
{
451
    struct elf_shdr *sec;
452
    int i;
453

    
454
    for(i = 0; i < ehdr.e_shnum; i++) {
455
        sec = &shdr[i];
456
        if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index)
457
            return i;
458
    }
459
    return 0;
460
}
461

    
462
static host_ulong get_rel_offset(EXE_RELOC *rel)
463
{
464
    return rel->r_offset;
465
}
466

    
467
static char *get_rel_sym_name(EXE_RELOC *rel)
468
{
469
    return strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
470
}
471

    
472
static char *get_sym_name(EXE_SYM *sym)
473
{
474
    return strtab + sym->st_name;
475
}
476

    
477
/* load an elf object file */
478
int load_object(const char *filename)
479
{
480
    int fd;
481
    struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec;
482
    int i, j;
483
    ElfW(Sym) *sym;
484
    char *shstr;
485
    ELF_RELOC *rel;
486
   
487
    fd = open(filename, O_RDONLY);
488
    if (fd < 0)
489
        error("can't open file '%s'", filename);
490
   
491
    /* Read ELF header.  */
492
    if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
493
        error("unable to read file header");
494

    
495
    /* Check ELF identification.  */
496
    if (ehdr.e_ident[EI_MAG0] != ELFMAG0
497
     || ehdr.e_ident[EI_MAG1] != ELFMAG1
498
     || ehdr.e_ident[EI_MAG2] != ELFMAG2
499
     || ehdr.e_ident[EI_MAG3] != ELFMAG3
500
     || ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
501
        error("bad ELF header");
502
    }
503

    
504
    do_swap = elf_must_swap(&ehdr);
505
    if (do_swap)
506
        elf_swap_ehdr(&ehdr);
507
    if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
508
        error("Unsupported ELF class");
509
    if (ehdr.e_type != ET_REL)
510
        error("ELF object file expected");
511
    if (ehdr.e_version != EV_CURRENT)
512
        error("Invalid ELF version");
513
    if (!elf_check_arch(ehdr.e_machine))
514
        error("Unsupported CPU (e_machine=%d)", ehdr.e_machine);
515

    
516
    /* read section headers */
517
    shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(struct elf_shdr));
518
    if (do_swap) {
519
        for(i = 0; i < ehdr.e_shnum; i++) {
520
            elf_swap_shdr(&shdr[i]);
521
        }
522
    }
523

    
524
    /* read all section data */
525
    sdata = malloc(sizeof(void *) * ehdr.e_shnum);
526
    memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
527
   
528
    for(i = 0;i < ehdr.e_shnum; i++) {
529
        sec = &shdr[i];
530
        if (sec->sh_type != SHT_NOBITS)
531
            sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size);
532
    }
533

    
534
    sec = &shdr[ehdr.e_shstrndx];
535
    shstr = (char *)sdata[ehdr.e_shstrndx];
536

    
537
    /* swap relocations */
538
    for(i = 0; i < ehdr.e_shnum; i++) {
539
        sec = &shdr[i];
540
        if (sec->sh_type == SHT_RELOC) {
541
            nb_relocs = sec->sh_size / sec->sh_entsize;
542
            if (do_swap) {
543
                for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++)
544
                    elf_swap_rel(rel);
545
            }
546
        }
547
    }
548
    /* text section */
549

    
550
    text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
551
    if (!text_sec)
552
        error("could not find .text section");
553
    text_shndx = text_sec - shdr;
554
    text = sdata[text_shndx];
555

    
556
    /* find text relocations, if any */
557
    relocs = NULL;
558
    nb_relocs = 0;
559
    i = find_reloc(text_shndx);
560
    if (i != 0) {
561
        relocs = (ELF_RELOC *)sdata[i];
562
        nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize;
563
    }
564

    
565
    symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
566
    if (!symtab_sec)
567
        error("could not find .symtab section");
568
    strtab_sec = &shdr[symtab_sec->sh_link];
569

    
570
    symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
571
    strtab = (char *)sdata[symtab_sec->sh_link];
572
   
573
    nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
574
    if (do_swap) {
575
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
576
            swab32s(&sym->st_name);
577
            swabls(&sym->st_value);
578
            swabls(&sym->st_size);
579
            swab16s(&sym->st_shndx);
580
        }
581
    }
582
    close(fd);
583
    return 0;
584
}
585

    
586
#endif /* CONFIG_FORMAT_ELF */
587

    
588
#ifdef CONFIG_FORMAT_COFF
589

    
590
/* COFF file info */
591
struct external_scnhdr *shdr;
592
uint8_t **sdata;
593
struct external_filehdr fhdr;
594
struct external_syment *coff_symtab;
595
char *strtab;
596
int coff_text_shndx, coff_data_shndx;
597

    
598
int data_shndx;
599

    
600
#define STRTAB_SIZE 4
601

    
602
#define DIR32   0x06
603
#define DISP32  0x14
604

    
605
#define T_FUNCTION  0x20
606
#define C_EXTERNAL  2
607

    
608
void sym_ent_name(struct external_syment *ext_sym, EXE_SYM *sym)
609
{
610
    char *q;
611
    int c, i, len;
612
   
613
    if (ext_sym->e.e.e_zeroes != 0) {
614
        q = sym->st_name;
615
        for(i = 0; i < 8; i++) {
616
            c = ext_sym->e.e_name[i];
617
            if (c == '\0')
618
                break;
619
            *q++ = c;
620
        }
621
        *q = '\0';
622
    } else {
623
        pstrcpy(sym->st_name, sizeof(sym->st_name), strtab + ext_sym->e.e.e_offset);
624
    }
625

    
626
    /* now convert the name to a C name (suppress the leading '_') */
627
    if (sym->st_name[0] == '_') {
628
        len = strlen(sym->st_name);
629
        memmove(sym->st_name, sym->st_name + 1, len - 1);
630
        sym->st_name[len - 1] = '\0';
631
    }
632
}
633

    
634
char *name_for_dotdata(struct coff_rel *rel)
635
{
636
        int i;
637
        struct coff_sym *sym;
638
        uint32_t text_data;
639

    
640
        text_data = *(uint32_t *)(text + rel->r_offset);
641

    
642
        for (i = 0, sym = symtab; i < nb_syms; i++, sym++) {
643
                if (sym->st_syment->e_scnum == data_shndx &&
644
                    text_data >= sym->st_value &&
645
                    text_data < sym->st_value + sym->st_size) {
646
                   
647
                    return sym->st_name;
648

    
649
                }
650
        }
651
        return NULL;
652
}
653

    
654
static char *get_sym_name(EXE_SYM *sym)
655
{
656
    return sym->st_name;
657
}
658

    
659
static char *get_rel_sym_name(EXE_RELOC *rel)
660
{
661
    char *name;
662
    name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
663
    if (!strcmp(name, ".data"))
664
        name = name_for_dotdata(rel);
665
    if (name[0] == '.')
666
        return NULL;
667
    return name;
668
}
669

    
670
static host_ulong get_rel_offset(EXE_RELOC *rel)
671
{
672
    return rel->r_offset;
673
}
674

    
675
struct external_scnhdr *find_coff_section(struct external_scnhdr *shdr, int shnum, const char *name)
676
{
677
    int i;
678
    const char *shname;
679
    struct external_scnhdr *sec;
680

    
681
    for(i = 0; i < shnum; i++) {
682
        sec = &shdr[i];
683
        if (!sec->s_name)
684
            continue;
685
        shname = sec->s_name;
686
        if (!strcmp(shname, name))
687
            return sec;
688
    }
689
    return NULL;
690
}
691

    
692
/* load a coff object file */
693
int load_object(const char *filename)
694
{
695
    int fd;
696
    struct external_scnhdr *sec, *text_sec, *data_sec;
697
    int i;
698
    struct external_syment *ext_sym;
699
    struct external_reloc *coff_relocs;
700
    struct external_reloc *ext_rel;
701
    uint32_t *n_strtab;
702
    EXE_SYM *sym;
703
    EXE_RELOC *rel;
704

    
705
    fd = open(filename, O_RDONLY
706
#ifdef _WIN32
707
              | O_BINARY
708
#endif
709
              );
710
    if (fd < 0)
711
        error("can't open file '%s'", filename);
712
   
713
    /* Read COFF header.  */
714
    if (read(fd, &fhdr, sizeof (fhdr)) != sizeof (fhdr))
715
        error("unable to read file header");
716

    
717
    /* Check COFF identification.  */
718
    if (fhdr.f_magic != I386MAGIC) {
719
        error("bad COFF header");
720
    }
721
    do_swap = 0;
722

    
723
    /* read section headers */
724
    shdr = load_data(fd, sizeof(struct external_filehdr) + fhdr.f_opthdr, fhdr.f_nscns * sizeof(struct external_scnhdr));
725

    
726
    /* read all section data */
727
    sdata = malloc(sizeof(void *) * fhdr.f_nscns);
728
    memset(sdata, 0, sizeof(void *) * fhdr.f_nscns);
729
   
730
    const char *p;
731
    for(i = 0;i < fhdr.f_nscns; i++) {
732
        sec = &shdr[i];
733
        if (!strstart(sec->s_name,  ".bss", &p))
734
            sdata[i] = load_data(fd, sec->s_scnptr, sec->s_size);
735
    }
736

    
737

    
738
    /* text section */
739
    text_sec = find_coff_section(shdr, fhdr.f_nscns, ".text");
740
    if (!text_sec)
741
        error("could not find .text section");
742
    coff_text_shndx = text_sec - shdr;
743
    text = sdata[coff_text_shndx];
744

    
745
    /* data section */
746
    data_sec = find_coff_section(shdr, fhdr.f_nscns, ".data");
747
    if (!data_sec)
748
        error("could not find .data section");
749
    coff_data_shndx = data_sec - shdr;
750
   
751
    coff_symtab = load_data(fd, fhdr.f_symptr, fhdr.f_nsyms*SYMESZ);
752
    for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
753
        for(i=0;i<8;i++)
754
            printf(" %02x", ((uint8_t *)ext_sym->e.e_name)[i]);
755
        printf("\n");
756
    }
757

    
758

    
759
    n_strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), STRTAB_SIZE);
760
    strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab);
761
   
762
    nb_syms = fhdr.f_nsyms;
763

    
764
    for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
765
      if (strstart(ext_sym->e.e_name, ".text", NULL))
766
                  text_shndx = ext_sym->e_scnum;
767
          if (strstart(ext_sym->e.e_name, ".data", NULL))
768
                  data_shndx = ext_sym->e_scnum;
769
    }
770

    
771
        /* set coff symbol */
772
        symtab = malloc(sizeof(struct coff_sym) * nb_syms);
773

    
774
        int aux_size, j;
775
        for (i = 0, ext_sym = coff_symtab, sym = symtab; i < nb_syms; i++, ext_sym++, sym++) {
776
                memset(sym, 0, sizeof(*sym));
777
                sym->st_syment = ext_sym;
778
                sym_ent_name(ext_sym, sym);
779
                sym->st_value = ext_sym->e_value;
780

    
781
                aux_size = *(int8_t *)ext_sym->e_numaux;
782
                if (ext_sym->e_scnum == text_shndx && ext_sym->e_type == T_FUNCTION) {
783
                        for (j = aux_size + 1; j < nb_syms - i; j++) {
784
                                if ((ext_sym + j)->e_scnum == text_shndx &&
785
                                        (ext_sym + j)->e_type == T_FUNCTION ){
786
                                        sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
787
                                        break;
788
                                } else if (j == nb_syms - i - 1) {
789
                                        sec = &shdr[coff_text_shndx];
790
                                        sym->st_size = sec->s_size - ext_sym->e_value;
791
                                        break;
792
                                }
793
                        }
794
                } else if (ext_sym->e_scnum == data_shndx && *(uint8_t *)ext_sym->e_sclass == C_EXTERNAL) {
795
                        for (j = aux_size + 1; j < nb_syms - i; j++) {
796
                                if ((ext_sym + j)->e_scnum == data_shndx) {
797
                                        sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
798
                                        break;
799
                                } else if (j == nb_syms - i - 1) {
800
                                        sec = &shdr[coff_data_shndx];
801
                                        sym->st_size = sec->s_size - ext_sym->e_value;
802
                                        break;
803
                                }
804
                        }
805
                } else {
806
                        sym->st_size = 0;
807
                }
808
        
809
                sym->st_type = ext_sym->e_type;
810
                sym->st_shndx = ext_sym->e_scnum;
811
        }
812

    
813
        
814
    /* find text relocations, if any */
815
    sec = &shdr[coff_text_shndx];
816
    coff_relocs = load_data(fd, sec->s_relptr, sec->s_nreloc*RELSZ);
817
    nb_relocs = sec->s_nreloc;
818

    
819
    /* set coff relocation */
820
    relocs = malloc(sizeof(struct coff_rel) * nb_relocs);
821
    for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs;
822
         i++, ext_rel++, rel++) {
823
        memset(rel, 0, sizeof(*rel));
824
        rel->r_reloc = ext_rel;
825
        rel->r_offset = *(uint32_t *)ext_rel->r_vaddr;
826
        rel->r_type = *(uint16_t *)ext_rel->r_type;
827
    }
828
    return 0;
829
}
830

    
831
#endif /* CONFIG_FORMAT_COFF */
832

    
833
#ifdef CONFIG_FORMAT_MACH
834

    
835
/* File Header */
836
struct mach_header         mach_hdr;
837

    
838
/* commands */
839
struct segment_command         *segment = 0;
840
struct dysymtab_command *dysymtabcmd = 0;
841
struct symtab_command         *symtabcmd = 0;
842

    
843
/* section */
844
struct section         *section_hdr;
845
struct section *text_sec_hdr;
846
uint8_t         **sdata;
847

    
848
/* relocs */
849
struct relocation_info *relocs;
850

    
851
/* symbols */
852
EXE_SYM                        *symtab;
853
struct nlist         *symtab_std;
854
char                        *strtab;
855

    
856
/* indirect symbols */
857
uint32_t         *tocdylib;
858

    
859
/* Utility functions */
860

    
861
static inline char *find_str_by_index(int index)
862
{
863
    return strtab+index;
864
}
865

    
866
/* Used by dyngen common code */
867
static char *get_sym_name(EXE_SYM *sym)
868
{
869
        char *name = find_str_by_index(sym->n_un.n_strx);
870

    
871
        if ( sym->n_type & N_STAB ) /* Debug symbols are ignored */
872
                return "debug";
873
                
874
        if(!name)
875
                return name;
876
        if(name[0]=='_')
877
                return name + 1;
878
        else
879
                return name;
880
}
881

    
882
/* find a section index given its segname, sectname */
883
static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname,
884
                                  const char *sectname)
885
{
886
    int i;
887
    struct section *sec = section_hdr;
888

    
889
    for(i = 0; i < shnum; i++, sec++) {
890
        if (!sec->segname || !sec->sectname)
891
            continue;
892
        if (!strcmp(sec->sectname, sectname) && !strcmp(sec->segname, segname))
893
            return i;
894
    }
895
    return -1;
896
}
897

    
898
/* find a section header given its segname, sectname */
899
struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname,
900
                                  const char *sectname)
901
{
902
    int index = find_mach_sec_index(section_hdr, shnum, segname, sectname);
903
        if(index == -1)
904
                return NULL;
905
        return section_hdr+index;
906
}
907

    
908

    
909
static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned int *value)
910
{
911
    struct scattered_relocation_info * scarel;
912

    
913
    if(R_SCATTERED & rel->r_address) {
914
        scarel = (struct scattered_relocation_info*)rel;
915
        if(scarel->r_type != PPC_RELOC_PAIR)
916
            error("fetch_next_pair_value: looking for a pair which was not found (1)");
917
        *value = scarel->r_value;
918
    } else {
919
                if(rel->r_type != PPC_RELOC_PAIR)
920
                        error("fetch_next_pair_value: looking for a pair which was not found (2)");
921
                *value = rel->r_address;
922
        }
923
}
924

    
925
/* find a sym name given its value, in a section number */
926
static const char * find_sym_with_value_and_sec_number( int value, int sectnum, int * offset )
927
{
928
        int i, ret = -1;
929

    
930
        for( i = 0 ; i < nb_syms; i++ )
931
        {
932
            if( !(symtab[i].n_type & N_STAB) && (symtab[i].n_type & N_SECT) &&
933
                         (symtab[i].n_sect ==  sectnum) && (symtab[i].st_value <= value) )
934
                {
935
                        if( (ret<0) || (symtab[i].st_value >= symtab[ret].st_value) )
936
                                ret = i;
937
                }
938
        }
939
        if( ret < 0 ) {
940
                *offset = 0;
941
                return 0;
942
        } else {
943
                *offset = value - symtab[ret].st_value;
944
                return get_sym_name(&symtab[ret]);
945
        }
946
}
947

    
948
/*
949
 *  Find symbol name given a (virtual) address, and a section which is of type
950
 *  S_NON_LAZY_SYMBOL_POINTERS or S_LAZY_SYMBOL_POINTERS or S_SYMBOL_STUBS
951
 */
952
static const char * find_reloc_name_in_sec_ptr(int address, struct section * sec_hdr)
953
{
954
    unsigned int tocindex, symindex, size;
955
    const char *name = 0;
956
   
957
    /* Sanity check */
958
    if(!( address >= sec_hdr->addr && address < (sec_hdr->addr + sec_hdr->size) ) )
959
        return (char*)0;
960
        
961
        if( sec_hdr->flags & S_SYMBOL_STUBS ){
962
                size = sec_hdr->reserved2;
963
                if(size == 0)
964
                    error("size = 0");
965
        
966
        }
967
        else if( sec_hdr->flags & S_LAZY_SYMBOL_POINTERS ||
968
                    sec_hdr->flags & S_NON_LAZY_SYMBOL_POINTERS)
969
                size = sizeof(unsigned long);
970
        else
971
                return 0;
972
        
973
    /* Compute our index in toc */
974
        tocindex = (address - sec_hdr->addr)/size;
975
        symindex = tocdylib[sec_hdr->reserved1 + tocindex];
976

    
977
        name = get_sym_name(&symtab[symindex]);
978

    
979
    return name;
980
}
981

    
982
static const char * find_reloc_name_given_its_address(int address)
983
{
984
    unsigned int i;
985
    for(i = 0; i < segment->nsects ; i++)
986
    {
987
        const char * name = find_reloc_name_in_sec_ptr(address, &section_hdr[i]);
988
        if((long)name != -1)
989
            return name;
990
    }
991
    return 0;
992
}
993

    
994
static const char * get_reloc_name(EXE_RELOC * rel, int * sslide)
995
{
996
        char * name = 0;
997
        struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
998
        int sectnum = rel->r_symbolnum;
999
        int sectoffset;
1000
        int other_half=0;
1001

    
1002
        /* init the slide value */
1003
        *sslide = 0;
1004

    
1005
        if(R_SCATTERED & rel->r_address)
1006
                return (char *)find_reloc_name_given_its_address(sca_rel->r_value);
1007

    
1008
        if(rel->r_extern)
1009
        {
1010
                /* ignore debug sym */
1011
                if ( symtab[rel->r_symbolnum].n_type & N_STAB )
1012
                        return 0;
1013
                return get_sym_name(&symtab[rel->r_symbolnum]);
1014
        }
1015

    
1016
        /* Intruction contains an offset to the symbols pointed to, in the rel->r_symbolnum section */
1017
        sectoffset = *(uint32_t *)(text + rel->r_address) & 0xffff;
1018
                
1019
        if(sectnum==0xffffff)
1020
                return 0;
1021

    
1022
        /* Sanity Check */
1023
        if(sectnum > segment->nsects)
1024
                error("sectnum > segment->nsects");
1025

    
1026
        switch(rel->r_type)
1027
        {
1028
                case PPC_RELOC_LO16: fetch_next_pair_value(rel+1, &other_half); sectoffset |= (other_half << 16);
1029
                        break;
1030
                case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) | (uint16_t)(other_half & 0xffff);
1031
                        break;
1032
                case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) + (int16_t)(other_half & 0xffff);
1033
                        break;
1034
                case PPC_RELOC_BR24:
1035
                        sectoffset = ( *(uint32_t *)(text + rel->r_address) & 0x03fffffc );
1036
                        if (sectoffset & 0x02000000) sectoffset |= 0xfc000000;
1037
                        break;
1038
                default:
1039
                        error("switch(rel->type) not found");
1040
        }
1041

    
1042
        if(rel->r_pcrel)
1043
                sectoffset += rel->r_address;
1044
                
1045
        if (rel->r_type == PPC_RELOC_BR24)
1046
                name = (char *)find_reloc_name_in_sec_ptr((int)sectoffset, &section_hdr[sectnum-1]);
1047

    
1048
        /* search it in the full symbol list, if not found */
1049
        if(!name)
1050
                name = (char *)find_sym_with_value_and_sec_number(sectoffset, sectnum, sslide);
1051

    
1052
        return name;
1053
}
1054

    
1055
/* Used by dyngen common code */
1056
static const char * get_rel_sym_name(EXE_RELOC * rel)
1057
{
1058
        int sslide;
1059
        return get_reloc_name( rel, &sslide);
1060
}
1061

    
1062
/* Used by dyngen common code */
1063
static host_ulong get_rel_offset(EXE_RELOC *rel)
1064
{
1065
        struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
1066
    if(R_SCATTERED & rel->r_address)
1067
                return sca_rel->r_address;
1068
        else
1069
                return rel->r_address;
1070
}
1071

    
1072
/* load a mach-o object file */
1073
int load_object(const char *filename)
1074
{
1075
        int fd;
1076
        unsigned int offset_to_segment = 0;
1077
    unsigned int offset_to_dysymtab = 0;
1078
    unsigned int offset_to_symtab = 0;
1079
    struct load_command lc;
1080
    unsigned int i, j;
1081
        EXE_SYM *sym;
1082
        struct nlist *syment;
1083
   
1084
        fd = open(filename, O_RDONLY);
1085
    if (fd < 0)
1086
        error("can't open file '%s'", filename);
1087
        
1088
    /* Read Mach header.  */
1089
    if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
1090
        error("unable to read file header");
1091

    
1092
    /* Check Mach identification.  */
1093
    if (!check_mach_header(mach_hdr)) {
1094
        error("bad Mach header");
1095
    }
1096
   
1097
    if (mach_hdr.cputype != CPU_TYPE_POWERPC)
1098
        error("Unsupported CPU");
1099
       
1100
    if (mach_hdr.filetype != MH_OBJECT)
1101
        error("Unsupported Mach Object");
1102
   
1103
    /* read segment headers */
1104
    for(i=0, j=sizeof(mach_hdr); i<mach_hdr.ncmds ; i++)
1105
    {
1106
        if(read(fd, &lc, sizeof(struct load_command)) != sizeof(struct load_command))
1107
            error("unable to read load_command");
1108
        if(lc.cmd == LC_SEGMENT)
1109
        {
1110
            offset_to_segment = j;
1111
            lseek(fd, offset_to_segment, SEEK_SET);
1112
            segment = malloc(sizeof(struct segment_command));
1113
            if(read(fd, segment, sizeof(struct segment_command)) != sizeof(struct segment_command))
1114
                error("unable to read LC_SEGMENT");
1115
        }
1116
        if(lc.cmd == LC_DYSYMTAB)
1117
        {
1118
            offset_to_dysymtab = j;
1119
            lseek(fd, offset_to_dysymtab, SEEK_SET);
1120
            dysymtabcmd = malloc(sizeof(struct dysymtab_command));
1121
            if(read(fd, dysymtabcmd, sizeof(struct dysymtab_command)) != sizeof(struct dysymtab_command))
1122
                error("unable to read LC_DYSYMTAB");
1123
        }
1124
        if(lc.cmd == LC_SYMTAB)
1125
        {
1126
            offset_to_symtab = j;
1127
            lseek(fd, offset_to_symtab, SEEK_SET);
1128
            symtabcmd = malloc(sizeof(struct symtab_command));
1129
            if(read(fd, symtabcmd, sizeof(struct symtab_command)) != sizeof(struct symtab_command))
1130
                error("unable to read LC_SYMTAB");
1131
        }
1132
        j+=lc.cmdsize;
1133

    
1134
        lseek(fd, j, SEEK_SET);
1135
    }
1136

    
1137
    if(!segment)
1138
        error("unable to find LC_SEGMENT");
1139

    
1140
    /* read section headers */
1141
    section_hdr = load_data(fd, offset_to_segment + sizeof(struct segment_command), segment->nsects * sizeof(struct section));
1142

    
1143
    /* read all section data */
1144
    sdata = (uint8_t **)malloc(sizeof(void *) * segment->nsects);
1145
    memset(sdata, 0, sizeof(void *) * segment->nsects);
1146
   
1147
        /* Load the data in section data */
1148
        for(i = 0; i < segment->nsects; i++) {
1149
        sdata[i] = load_data(fd, section_hdr[i].offset, section_hdr[i].size);
1150
    }
1151

    
1152
    /* text section */
1153
        text_sec_hdr = find_mach_sec_hdr(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
1154
        i = find_mach_sec_index(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
1155
        if (i == -1 || !text_sec_hdr)
1156
        error("could not find __TEXT,__text section");
1157
    text = sdata[i];
1158

    
1159
    /* Make sure dysym was loaded */
1160
    if(!(int)dysymtabcmd)
1161
        error("could not find __DYSYMTAB segment");
1162
   
1163
    /* read the table of content of the indirect sym */
1164
    tocdylib = load_data( fd, dysymtabcmd->indirectsymoff, dysymtabcmd->nindirectsyms * sizeof(uint32_t) );
1165
   
1166
    /* Make sure symtab was loaded  */
1167
    if(!(int)symtabcmd)
1168
        error("could not find __SYMTAB segment");
1169
    nb_syms = symtabcmd->nsyms;
1170

    
1171
    symtab_std = load_data(fd, symtabcmd->symoff, symtabcmd->nsyms * sizeof(struct nlist));
1172
    strtab = load_data(fd, symtabcmd->stroff, symtabcmd->strsize);
1173

    
1174
        symtab = malloc(sizeof(EXE_SYM) * nb_syms);
1175

    
1176
        /* Now transform the symtab, to an extended version, with the sym size, and the C name */
1177
        for(i = 0, sym = symtab, syment = symtab_std; i < nb_syms; i++, sym++, syment++) {
1178
        struct nlist *sym_follow, *sym_next = 0;
1179
        unsigned int j;
1180
                memset(sym, 0, sizeof(*sym));
1181
        
1182
                if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
1183
            continue;
1184
                
1185
                memcpy(sym, syment, sizeof(*syment));
1186
                
1187
                /* Find the following symbol in order to get the current symbol size */
1188
        for(j = 0, sym_follow = symtab_std; j < nb_syms; j++, sym_follow++) {
1189
            if ( sym_follow->n_sect != 1 || sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value))
1190
                continue;
1191
            if(!sym_next) {
1192
                sym_next = sym_follow;
1193
                continue;
1194
            }
1195
            if(!(sym_next->n_value > sym_follow->n_value))
1196
                continue;
1197
            sym_next = sym_follow;
1198
        }
1199
                if(sym_next)
1200
            sym->st_size = sym_next->n_value - sym->st_value;
1201
                else
1202
            sym->st_size = text_sec_hdr->size - sym->st_value;
1203
        }
1204

    
1205
    /* Find Reloc */
1206
    relocs = load_data(fd, text_sec_hdr->reloff, text_sec_hdr->nreloc * sizeof(struct relocation_info));
1207
    nb_relocs = text_sec_hdr->nreloc;
1208

    
1209
        close(fd);
1210
        return 0;
1211
}
1212

    
1213
#endif /* CONFIG_FORMAT_MACH */
1214

    
1215
void get_reloc_expr(char *name, int name_size, const char *sym_name)
1216
{
1217
    const char *p;
1218

    
1219
    if (strstart(sym_name, "__op_param", &p)) {
1220
        snprintf(name, name_size, "param%s", p);
1221
    } else if (strstart(sym_name, "__op_gen_label", &p)) {
1222
        snprintf(name, name_size, "gen_labels[param%s]", p);
1223
    } else {
1224
#ifdef HOST_SPARC
1225
        if (sym_name[0] == '.')
1226
            snprintf(name, name_size,
1227
                     "(long)(&__dot_%s)",
1228
                     sym_name + 1);
1229
        else
1230
#endif
1231
            snprintf(name, name_size, "(long)(&%s)", sym_name);
1232
    }
1233
}
1234

    
1235
#ifdef HOST_IA64
1236

    
1237
#define PLT_ENTRY_SIZE        16        /* 1 bundle containing "brl" */
1238

    
1239
struct plt_entry {
1240
    struct plt_entry *next;
1241
    const char *name;
1242
    unsigned long addend;
1243
} *plt_list;
1244

    
1245
static int
1246
get_plt_index (const char *name, unsigned long addend)
1247
{
1248
    struct plt_entry *plt, *prev= NULL;
1249
    int index = 0;
1250

    
1251
    /* see if we already have an entry for this target: */
1252
    for (plt = plt_list; plt; ++index, prev = plt, plt = plt->next)
1253
        if (strcmp(plt->name, name) == 0 && plt->addend == addend)
1254
            return index;
1255

    
1256
    /* nope; create a new PLT entry: */
1257

    
1258
    plt = malloc(sizeof(*plt));
1259
    if (!plt) {
1260
        perror("malloc");
1261
        exit(1);
1262
    }
1263
    memset(plt, 0, sizeof(*plt));
1264
    plt->name = strdup(name);
1265
    plt->addend = addend;
1266

    
1267
    /* append to plt-list: */
1268
    if (prev)
1269
        prev->next = plt;
1270
    else
1271
        plt_list = plt;
1272
    return index;
1273
}
1274

    
1275
#endif
1276

    
1277
#ifdef HOST_ARM
1278

    
1279
int arm_emit_ldr_info(const char *name, unsigned long start_offset,
1280
                      FILE *outfile, uint8_t *p_start, uint8_t *p_end,
1281
                      ELF_RELOC *relocs, int nb_relocs)
1282
{
1283
    uint8_t *p;
1284
    uint32_t insn;
1285
    int offset, min_offset, pc_offset, data_size, spare, max_pool;
1286
    uint8_t data_allocated[1024];
1287
    unsigned int data_index;
1288
    int type;
1289
   
1290
    memset(data_allocated, 0, sizeof(data_allocated));
1291
   
1292
    p = p_start;
1293
    min_offset = p_end - p_start;
1294
    spare = 0x7fffffff;
1295
    while (p < p_start + min_offset) {
1296
        insn = get32((uint32_t *)p);
1297
        /* TODO: Armv5e ldrd.  */
1298
        /* TODO: VFP load.  */
1299
        if ((insn & 0x0d5f0000) == 0x051f0000) {
1300
            /* ldr reg, [pc, #im] */
1301
            offset = insn & 0xfff;
1302
            if (!(insn & 0x00800000))
1303
                offset = -offset;
1304
            max_pool = 4096;
1305
            type = 0;
1306
        } else if ((insn & 0x0e5f0f00) == 0x0c1f0100) {
1307
            /* FPA ldf.  */
1308
            offset = (insn & 0xff) << 2;
1309
            if (!(insn & 0x00800000))
1310
                offset = -offset;
1311
            max_pool = 1024;
1312
            type = 1;
1313
        } else if ((insn & 0x0fff0000) == 0x028f0000) {
1314
            /* Some gcc load a doubleword immediate with
1315
               add regN, pc, #imm
1316
               ldmia regN, {regN, regM}
1317
               Hope and pray the compiler never generates somethin like
1318
               add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */
1319
            int r;
1320

    
1321
            r = (insn & 0xf00) >> 7;
1322
            offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r));
1323
            max_pool = 1024;
1324
            type = 2;
1325
        } else {
1326
            max_pool = 0;
1327
            type = -1;
1328
        }
1329
        if (type >= 0) {
1330
            /* PC-relative load needs fixing up.  */
1331
            if (spare > max_pool - offset)
1332
                spare = max_pool - offset;
1333
            if ((offset & 3) !=0)
1334
                error("%s:%04x: pc offset must be 32 bit aligned",
1335
                      name, start_offset + p - p_start);
1336
            if (offset < 0)
1337
                error("%s:%04x: Embedded literal value",
1338
                      name, start_offset + p - p_start);
1339
            pc_offset = p - p_start + offset + 8;
1340
            if (pc_offset <= (p - p_start) ||
1341
                pc_offset >= (p_end - p_start))
1342
                error("%s:%04x: pc offset must point inside the function code",
1343
                      name, start_offset + p - p_start);
1344
            if (pc_offset < min_offset)
1345
                min_offset = pc_offset;
1346
            if (outfile) {
1347
                /* The intruction position */
1348
                fprintf(outfile, "    arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
1349
                        p - p_start);
1350
                /* The position of the constant pool data.  */
1351
                data_index = ((p_end - p_start) - pc_offset) >> 2;
1352
                fprintf(outfile, "    arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n",
1353
                        data_index);
1354
                fprintf(outfile, "    arm_ldr_ptr->type = %d;\n", type);
1355
                fprintf(outfile, "    arm_ldr_ptr++;\n");
1356
            }
1357
        }
1358
        p += 4;
1359
    }
1360

    
1361
    /* Copy and relocate the constant pool data.  */
1362
    data_size = (p_end - p_start) - min_offset;
1363
    if (data_size > 0 && outfile) {
1364
        spare += min_offset;
1365
        fprintf(outfile, "    arm_data_ptr -= %d;\n", data_size >> 2);
1366
        fprintf(outfile, "    arm_pool_ptr -= %d;\n", data_size);
1367
        fprintf(outfile, "    if (arm_pool_ptr > gen_code_ptr + %d)\n"
1368
                         "        arm_pool_ptr = gen_code_ptr + %d;\n",
1369
                         spare, spare);
1370

    
1371
        data_index = 0;
1372
        for (pc_offset = min_offset;
1373
             pc_offset < p_end - p_start;
1374
             pc_offset += 4) {
1375

    
1376
            ELF_RELOC *rel;
1377
            int i, addend, type;
1378
            const char *sym_name;
1379
            char relname[1024];
1380

    
1381
            /* data value */
1382
            addend = get32((uint32_t *)(p_start + pc_offset));
1383
            relname[0] = '\0';
1384
            for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1385
                if (rel->r_offset == (pc_offset + start_offset)) {
1386
                    sym_name = get_rel_sym_name(rel);
1387
                    /* the compiler leave some unnecessary references to the code */
1388
                    get_reloc_expr(relname, sizeof(relname), sym_name);
1389
                    type = ELF32_R_TYPE(rel->r_info);
1390
                    if (type != R_ARM_ABS32)
1391
                        error("%s: unsupported data relocation", name);
1392
                    break;
1393
                }
1394
            }
1395
            fprintf(outfile, "    arm_data_ptr[%d] = 0x%x",
1396
                    data_index, addend);
1397
            if (relname[0] != '\0')
1398
                fprintf(outfile, " + %s", relname);
1399
            fprintf(outfile, ";\n");
1400

    
1401
            data_index++;
1402
        }
1403
    }
1404

    
1405
    if (p == p_start)
1406
        goto arm_ret_error;
1407
    p -= 4;
1408
    insn = get32((uint32_t *)p);
1409
    /* The last instruction must be an ldm instruction.  There are several
1410
       forms generated by gcc:
1411
        ldmib sp, {..., pc}  (implies a sp adjustment of +4)
1412
        ldmia sp, {..., pc}
1413
        ldmea fp, {..., pc} */
1414
    if ((insn & 0xffff8000) == 0xe99d8000) {
1415
        if (outfile) {
1416
            fprintf(outfile,
1417
                    "    *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n",
1418
                    p - p_start);
1419
        }
1420
        p += 4;
1421
    } else if ((insn & 0xffff8000) != 0xe89d8000
1422
        && (insn & 0xffff8000) != 0xe91b8000) {
1423
    arm_ret_error:
1424
        if (!outfile)
1425
            printf("%s: invalid epilog\n", name);
1426
    }
1427
    return p - p_start;
1428
}
1429
#endif
1430

    
1431

    
1432
#define MAX_ARGS 3
1433

    
1434
/* generate op code */
1435
void gen_code(const char *name, host_ulong offset, host_ulong size,
1436
              FILE *outfile, int gen_switch)
1437
{
1438
    int copy_size = 0;
1439
    uint8_t *p_start, *p_end;
1440
    host_ulong start_offset;
1441
    int nb_args, i, n;
1442
    uint8_t args_present[MAX_ARGS];
1443
    const char *sym_name, *p;
1444
    EXE_RELOC *rel;
1445

    
1446
    /* Compute exact size excluding prologue and epilogue instructions.
1447
     * Increment start_offset to skip epilogue instructions, then compute
1448
     * copy_size the indicate the size of the remaining instructions (in
1449
     * bytes).
1450
     */
1451
    p_start = text + offset;
1452
    p_end = p_start + size;
1453
    start_offset = offset;
1454
#if defined(HOST_I386) || defined(HOST_X86_64)
1455
#ifdef CONFIG_FORMAT_COFF
1456
    {
1457
        uint8_t *p;
1458
        p = p_end - 1;
1459
        if (p == p_start)
1460
            error("empty code for %s", name);
1461
        while (*p != 0xc3) {
1462
            p--;
1463
            if (p <= p_start)
1464
                error("ret or jmp expected at the end of %s", name);
1465
        }
1466
        copy_size = p - p_start;
1467
    }
1468
#else
1469
    {
1470
        int len;
1471
        len = p_end - p_start;
1472
        if (len == 0)
1473
            error("empty code for %s", name);
1474
        if (p_end[-1] == 0xc3) {
1475
            len--;
1476
        } else {
1477
            error("ret or jmp expected at the end of %s", name);
1478
        }
1479
        copy_size = len;
1480
    }
1481
#endif   
1482
#elif defined(HOST_PPC)
1483
    {
1484
        uint8_t *p;
1485
        p = (void *)(p_end - 4);
1486
        if (p == p_start)
1487
            error("empty code for %s", name);
1488
        if (get32((uint32_t *)p) != 0x4e800020)
1489
            error("blr expected at the end of %s", name);
1490
        copy_size = p - p_start;
1491
    }
1492
#elif defined(HOST_S390)
1493
    {
1494
        uint8_t *p;
1495
        p = (void *)(p_end - 2);
1496
        if (p == p_start)
1497
            error("empty code for %s", name);
1498
        if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
1499
            error("br %%r14 expected at the end of %s", name);
1500
        copy_size = p - p_start;
1501
    }
1502
#elif defined(HOST_ALPHA)
1503
    {
1504
        uint8_t *p;
1505
        p = p_end - 4;
1506
#if 0
1507
        /* XXX: check why it occurs */
1508
        if (p == p_start)
1509
            error("empty code for %s", name);
1510
#endif
1511
        if (get32((uint32_t *)p) != 0x6bfa8001)
1512
            error("ret expected at the end of %s", name);
1513
        copy_size = p - p_start;           
1514
    }
1515
#elif defined(HOST_IA64)
1516
    {
1517
        uint8_t *p;
1518
        p = (void *)(p_end - 4);
1519
        if (p == p_start)
1520
            error("empty code for %s", name);
1521
        /* br.ret.sptk.many b0;; */
1522
        /* 08 00 84 00 */
1523
        if (get32((uint32_t *)p) != 0x00840008)
1524
            error("br.ret.sptk.many b0;; expected at the end of %s", name);
1525
        copy_size = p_end - p_start;
1526
    }
1527
#elif defined(HOST_SPARC)
1528
    {
1529
#define INSN_SAVE       0x9de3a000
1530
#define INSN_RET        0x81c7e008
1531
#define INSN_RETL       0x81c3e008
1532
#define INSN_RESTORE    0x81e80000
1533
#define INSN_RETURN     0x81cfe008
1534
#define INSN_NOP        0x01000000
1535
#define INSN_ADD_SP     0x9c03a000 // add %sp, nn, %sp
1536
#define INSN_SUB_SP     0x9c23a000 // sub %sp, nn, %sp
1537

    
1538
        uint32_t start_insn, end_insn1, end_insn2;
1539
        uint8_t *p;
1540
        p = (void *)(p_end - 8);
1541
        if (p <= p_start)
1542
            error("empty code for %s", name);
1543
        start_insn = get32((uint32_t *)(p_start + 0x0));
1544
        end_insn1 = get32((uint32_t *)(p + 0x0));
1545
        end_insn2 = get32((uint32_t *)(p + 0x4));
1546
        if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1547
            (start_insn & ~0x1fff) == INSN_ADD_SP) {
1548
            p_start += 0x4;
1549
            start_offset += 0x4;
1550
            if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
1551
                /* SPARC v7: ret; restore; */ ;
1552
            else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
1553
                /* SPARC v9: return; nop; */ ;
1554
            else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
1555
                /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
1556
            else
1557

    
1558
                error("ret; restore; not found at end of %s", name);
1559
        } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1560
            ;
1561
        } else {
1562
            error("No save at the beginning of %s", name);
1563
        }
1564
#if 0
1565
        /* Skip a preceeding nop, if present.  */
1566
        if (p > p_start) {
1567
            skip_insn = get32((uint32_t *)(p - 0x4));
1568
            if (skip_insn == INSN_NOP)
1569
                p -= 4;
1570
        }
1571
#endif
1572
        copy_size = p - p_start;
1573
    }
1574
#elif defined(HOST_SPARC64)
1575
    {
1576
#define INSN_SAVE       0x9de3a000
1577
#define INSN_RET        0x81c7e008
1578
#define INSN_RETL       0x81c3e008
1579
#define INSN_RESTORE    0x81e80000
1580
#define INSN_RETURN     0x81cfe008
1581
#define INSN_NOP        0x01000000
1582
#define INSN_ADD_SP     0x9c03a000 // add %sp, nn, %sp
1583
#define INSN_SUB_SP     0x9c23a000 // sub %sp, nn, %sp
1584

    
1585
        uint32_t start_insn, end_insn1, end_insn2, skip_insn;
1586
        uint8_t *p;
1587
        p = (void *)(p_end - 8);
1588
#if 0
1589
        /* XXX: check why it occurs */
1590
        if (p <= p_start)
1591
            error("empty code for %s", name);
1592
#endif
1593
        start_insn = get32((uint32_t *)(p_start + 0x0));
1594
        end_insn1 = get32((uint32_t *)(p + 0x0));
1595
        end_insn2 = get32((uint32_t *)(p + 0x4));
1596
        if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1597
            (start_insn & ~0x1fff) == INSN_ADD_SP) {
1598
            p_start += 0x4;
1599
            start_offset += 0x4;
1600
            if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
1601
                /* SPARC v7: ret; restore; */ ;
1602
            else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
1603
                /* SPARC v9: return; nop; */ ;
1604
            else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
1605
                /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
1606
            else
1607

    
1608
                error("ret; restore; not found at end of %s", name);
1609
        } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1610
            ;
1611
        } else {
1612
            error("No save at the beginning of %s", name);
1613
        }
1614
       
1615
        /* Skip a preceeding nop, if present.  */
1616
        if (p > p_start) {
1617
            skip_insn = get32((uint32_t *)(p - 0x4));
1618
            if (skip_insn == 0x01000000)
1619
                p -= 4;
1620
        }
1621
       
1622
        copy_size = p - p_start;
1623
    }
1624
#elif defined(HOST_ARM)
1625
    {
1626
        uint32_t insn;
1627

    
1628
        if ((p_end - p_start) <= 16)
1629
            error("%s: function too small", name);
1630
        if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
1631
            (get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 ||
1632
            get32((uint32_t *)(p_start + 8)) != 0xe24cb004)
1633
            error("%s: invalid prolog", name);
1634
        p_start += 12;
1635
        start_offset += 12;
1636
        insn = get32((uint32_t *)p_start);
1637
        if ((insn & 0xffffff00) == 0xe24dd000) {
1638
            /* Stack adjustment.  Assume op uses the frame pointer.  */
1639
            p_start -= 4;
1640
            start_offset -= 4;
1641
        }
1642
        copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
1643
                                      relocs, nb_relocs);
1644
    }
1645
#elif defined(HOST_M68K)
1646
    {
1647
        uint8_t *p;
1648
        p = (void *)(p_end - 2);
1649
        if (p == p_start)
1650
            error("empty code for %s", name);
1651
        // remove NOP's, probably added for alignment
1652
        while ((get16((uint16_t *)p) == 0x4e71) &&
1653
               (p>p_start))
1654
            p -= 2;
1655
        if (get16((uint16_t *)p) != 0x4e75)
1656
            error("rts expected at the end of %s", name);
1657
        copy_size = p - p_start;
1658
    }
1659
#elif defined(HOST_MIPS) || defined(HOST_MIPS64)
1660
    {
1661
#define INSN_RETURN     0x03e00008
1662
#define INSN_NOP        0x00000000
1663

    
1664
        uint8_t *p = p_end;
1665

    
1666
        if (p < (p_start + 0x8)) {
1667
            error("empty code for %s", name);
1668
        } else {
1669
            uint32_t end_insn1, end_insn2;
1670

    
1671
            p -= 0x8;
1672
            end_insn1 = get32((uint32_t *)(p + 0x0));
1673
            end_insn2 = get32((uint32_t *)(p + 0x4));
1674
            if (end_insn1 != INSN_RETURN && end_insn2 != INSN_NOP)
1675
                error("jr ra not found at end of %s", name);
1676
        }
1677
        copy_size = p - p_start;
1678
    }
1679
#else
1680
#error unsupported CPU
1681
#endif
1682

    
1683
    /* compute the number of arguments by looking at the relocations */
1684
    for(i = 0;i < MAX_ARGS; i++)
1685
        args_present[i] = 0;
1686

    
1687
    for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1688
        host_ulong offset = get_rel_offset(rel);
1689
        if (offset >= start_offset &&
1690
            offset < start_offset + (p_end - p_start)) {
1691
            sym_name = get_rel_sym_name(rel);
1692
            if(!sym_name)
1693
                continue;
1694
            if (strstart(sym_name, "__op_param", &p) ||
1695
                strstart(sym_name, "__op_gen_label", &p)) {
1696
                n = strtoul(p, NULL, 10);
1697
                if (n > MAX_ARGS)
1698
                    error("too many arguments in %s", name);
1699
                args_present[n - 1] = 1;
1700
            }
1701
        }
1702
    }
1703
   
1704
    nb_args = 0;
1705
    while (nb_args < MAX_ARGS && args_present[nb_args])
1706
        nb_args++;
1707
    for(i = nb_args; i < MAX_ARGS; i++) {
1708
        if (args_present[i])
1709
            error("inconsistent argument numbering in %s", name);
1710
    }
1711

    
1712
    if (gen_switch == 2) {
1713
        fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
1714
    } else if (gen_switch == 1) {
1715

    
1716
        /* output C code */
1717
        fprintf(outfile, "case INDEX_%s: {\n", name);
1718
        if (nb_args > 0) {
1719
            fprintf(outfile, "    long ");
1720
            for(i = 0; i < nb_args; i++) {
1721
                if (i != 0)
1722
                    fprintf(outfile, ", ");
1723
                fprintf(outfile, "param%d", i + 1);
1724
            }
1725
            fprintf(outfile, ";\n");
1726
        }
1727
#if defined(HOST_IA64)
1728
        fprintf(outfile, "    extern char %s;\n", name);
1729
#else
1730
        fprintf(outfile, "    extern void %s();\n", name);
1731
#endif
1732

    
1733
        for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1734
            host_ulong offset = get_rel_offset(rel);
1735
            if (offset >= start_offset &&
1736
                offset < start_offset + (p_end - p_start)) {
1737
                sym_name = get_rel_sym_name(rel);
1738
                if(!sym_name)
1739
                    continue;
1740
                if (*sym_name &&
1741
                    !strstart(sym_name, "__op_param", NULL) &&
1742
                    !strstart(sym_name, "__op_jmp", NULL) &&
1743
                    !strstart(sym_name, "__op_gen_label", NULL)) {
1744
#if defined(HOST_SPARC)
1745
                    if (sym_name[0] == '.') {
1746
                        fprintf(outfile,
1747
                                "extern char __dot_%s __asm__(\"%s\");\n",
1748
                                sym_name+1, sym_name);
1749
                        continue;
1750
                    }
1751
#endif
1752
#if defined(__APPLE__)
1753
                    /* Set __attribute((unused)) on darwin because we
1754
                       want to avoid warning when we don't use the symbol.  */
1755
                    fprintf(outfile, "    extern char %s __attribute__((unused));\n", sym_name);
1756
#elif defined(HOST_IA64)
1757
                        if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
1758
                                /*
1759
                                 * PCREL21 br.call targets generally
1760
                                 * are out of range and need to go
1761
                                 * through an "import stub".
1762
                                 */
1763
                                fprintf(outfile, "    extern char %s;\n",
1764
                                        sym_name);
1765
#else
1766
                    fprintf(outfile, "extern char %s;\n", sym_name);
1767
#endif
1768
                }
1769
            }
1770
        }
1771

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

    
1775
        /* emit code offset information */
1776
        {
1777
            EXE_SYM *sym;
1778
            const char *sym_name, *p;
1779
            host_ulong val;
1780
            int n;
1781

    
1782
            for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
1783
                sym_name = get_sym_name(sym);
1784
                if (strstart(sym_name, "__op_label", &p)) {
1785
                    uint8_t *ptr;
1786
                    unsigned long offset;
1787
                   
1788
                    /* test if the variable refers to a label inside
1789
                       the code we are generating */
1790
#ifdef CONFIG_FORMAT_COFF
1791
                    if (sym->st_shndx == text_shndx) {
1792
                        ptr = sdata[coff_text_shndx];
1793
                    } else if (sym->st_shndx == data_shndx) {
1794
                        ptr = sdata[coff_data_shndx];
1795
                    } else {
1796
                        ptr = NULL;
1797
                    }
1798
#elif defined(CONFIG_FORMAT_MACH)
1799
                    if(!sym->n_sect)
1800
                        continue;
1801
                    ptr = sdata[sym->n_sect-1];
1802
#else
1803
                    ptr = sdata[sym->st_shndx];
1804
#endif
1805
                    if (!ptr)
1806
                        error("__op_labelN in invalid section");
1807
                    offset = sym->st_value;
1808
#ifdef CONFIG_FORMAT_MACH
1809
                    offset -= section_hdr[sym->n_sect-1].addr;
1810
#endif
1811
                    val = *(host_ulong *)(ptr + offset);
1812
#ifdef ELF_USES_RELOCA
1813
                    {
1814
                        int reloc_shndx, nb_relocs1, j;
1815

    
1816
                        /* try to find a matching relocation */
1817
                        reloc_shndx = find_reloc(sym->st_shndx);
1818
                        if (reloc_shndx) {
1819
                            nb_relocs1 = shdr[reloc_shndx].sh_size /
1820
                                shdr[reloc_shndx].sh_entsize;
1821
                            rel = (ELF_RELOC *)sdata[reloc_shndx];
1822
                            for(j = 0; j < nb_relocs1; j++) {
1823
                                if (rel->r_offset == offset) {
1824
                                    val = rel->r_addend;
1825
                                    break;
1826
                                }
1827
                                rel++;
1828
                            }
1829
                        }
1830
                    }
1831
#endif                   
1832
                    if (val >= start_offset && val <= start_offset + copy_size) {
1833
                        n = strtol(p, NULL, 10);
1834
                        fprintf(outfile, "    label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset));
1835
                    }
1836
                }
1837
            }
1838
        }
1839

    
1840
        /* load parameters in variables */
1841
        for(i = 0; i < nb_args; i++) {
1842
            fprintf(outfile, "    param%d = *opparam_ptr++;\n", i + 1);
1843
        }
1844

    
1845
        /* patch relocations */
1846
#if defined(HOST_I386)
1847
            {
1848
                char relname[256];
1849
                int type;
1850
                int addend;
1851
                int reloc_offset;
1852
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1853
                if (rel->r_offset >= start_offset &&
1854
                    rel->r_offset < start_offset + copy_size) {
1855
                    sym_name = get_rel_sym_name(rel);
1856
                    if (!sym_name)
1857
                        continue;
1858
                    reloc_offset = rel->r_offset - start_offset;
1859
                    if (strstart(sym_name, "__op_jmp", &p)) {
1860
                        int n;
1861
                        n = strtol(p, NULL, 10);
1862
                        /* __op_jmp relocations are done at
1863
                           runtime to do translated block
1864
                           chaining: the offset of the instruction
1865
                           needs to be stored */
1866
                        fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
1867
                                n, reloc_offset);
1868
                        continue;
1869
                    }
1870

    
1871
                    get_reloc_expr(relname, sizeof(relname), sym_name);
1872
                    addend = get32((uint32_t *)(text + rel->r_offset));
1873
#ifdef CONFIG_FORMAT_ELF
1874
                    type = ELF32_R_TYPE(rel->r_info);
1875
                    switch(type) {
1876
                    case R_386_32:
1877
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
1878
                                reloc_offset, relname, addend);
1879
                        break;
1880
                    case R_386_PC32:
1881
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
1882
                                reloc_offset, relname, reloc_offset, addend);
1883
                        break;
1884
                    default:
1885
                        error("unsupported i386 relocation (%d)", type);
1886
                    }
1887
#elif defined(CONFIG_FORMAT_COFF)
1888
                    {
1889
                        char *temp_name;
1890
                        int j;
1891
                        EXE_SYM *sym;
1892
                        temp_name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
1893
                        if (!strcmp(temp_name, ".data")) {
1894
                            for (j = 0, sym = symtab; j < nb_syms; j++, sym++) {
1895
                                if (strstart(sym->st_name, sym_name, NULL)) {
1896
                                    addend -= sym->st_value;
1897
                                }
1898
                            }
1899
                        }
1900
                    }
1901
                    type = rel->r_type;
1902
                    switch(type) {
1903
                    case DIR32:
1904
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
1905
                                reloc_offset, relname, addend);
1906
                        break;
1907
                    case DISP32:
1908
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
1909
                                reloc_offset, relname, reloc_offset, addend);
1910
                        break;
1911
                    default:
1912
                        error("unsupported i386 relocation (%d)", type);
1913
                    }
1914
#else
1915
#error unsupport object format
1916
#endif
1917
                }
1918
                }
1919
            }
1920
#elif defined(HOST_X86_64)
1921
            {
1922
                char relname[256];
1923
                int type;
1924
                int addend;
1925
                int reloc_offset;
1926
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1927
                if (rel->r_offset >= start_offset &&
1928
                    rel->r_offset < start_offset + copy_size) {
1929
                    sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1930
                    get_reloc_expr(relname, sizeof(relname), sym_name);
1931
                    type = ELF32_R_TYPE(rel->r_info);
1932
                    addend = rel->r_addend;
1933
                    reloc_offset = rel->r_offset - start_offset;
1934
                    switch(type) {
1935
                    case R_X86_64_32:
1936
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
1937
                                reloc_offset, relname, addend);
1938
                        break;
1939
                    case R_X86_64_32S:
1940
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
1941
                                reloc_offset, relname, addend);
1942
                        break;
1943
                    case R_X86_64_PC32:
1944
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
1945
                                reloc_offset, relname, reloc_offset, addend);
1946
                        break;
1947
                    default:
1948
                        error("unsupported X86_64 relocation (%d)", type);
1949
                    }
1950
                }
1951
                }
1952
            }
1953
#elif defined(HOST_PPC)
1954
            {
1955
#ifdef CONFIG_FORMAT_ELF
1956
                char relname[256];
1957
                int type;
1958
                int addend;
1959
                int reloc_offset;
1960
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1961
                    if (rel->r_offset >= start_offset &&
1962
                        rel->r_offset < start_offset + copy_size) {
1963
                        sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
1964
                        reloc_offset = rel->r_offset - start_offset;
1965
                        if (strstart(sym_name, "__op_jmp", &p)) {
1966
                            int n;
1967
                            n = strtol(p, NULL, 10);
1968
                            /* __op_jmp relocations are done at
1969
                               runtime to do translated block
1970
                               chaining: the offset of the instruction
1971
                               needs to be stored */
1972
                            fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
1973
                                    n, reloc_offset);
1974
                            continue;
1975
                        }
1976
                       
1977
                        get_reloc_expr(relname, sizeof(relname), sym_name);
1978
                        type = ELF32_R_TYPE(rel->r_info);
1979
                        addend = rel->r_addend;
1980
                        switch(type) {
1981
                        case R_PPC_ADDR32:
1982
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
1983
                                    reloc_offset, relname, addend);
1984
                            break;
1985
                        case R_PPC_ADDR16_LO:
1986
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
1987
                                    reloc_offset, relname, addend);
1988
                            break;
1989
                        case R_PPC_ADDR16_HI:
1990
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
1991
                                    reloc_offset, relname, addend);
1992
                            break;
1993
                        case R_PPC_ADDR16_HA:
1994
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
1995
                                    reloc_offset, relname, addend);
1996
                            break;
1997
                        case R_PPC_REL24:
1998
                            /* warning: must be at 32 MB distancy */
1999
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
2000
                                    reloc_offset, reloc_offset, relname, reloc_offset, addend);
2001
                            break;
2002
                        default:
2003
                            error("unsupported powerpc relocation (%d)", type);
2004
                        }
2005
                    }
2006
                }
2007
#elif defined(CONFIG_FORMAT_MACH)
2008
                struct scattered_relocation_info *scarel;
2009
                struct relocation_info * rel;
2010
                char final_sym_name[256];
2011
                const char *sym_name;
2012
                const char *p;
2013
                int slide, sslide;
2014
                int i;
2015

    
2016
                for(i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
2017
                    unsigned int offset, length, value = 0;
2018
                    unsigned int type, pcrel, isym = 0;
2019
                    unsigned int usesym = 0;
2020

    
2021
                    if(R_SCATTERED & rel->r_address) {
2022
                        scarel = (struct scattered_relocation_info*)rel;
2023
                        offset = (unsigned int)scarel->r_address;
2024
                        length = scarel->r_length;
2025
                        pcrel = scarel->r_pcrel;
2026
                        type = scarel->r_type;
2027
                        value = scarel->r_value;
2028
                    } else {
2029
                        value = isym = rel->r_symbolnum;
2030
                        usesym = (rel->r_extern);
2031
                        offset = rel->r_address;
2032
                        length = rel->r_length;
2033
                        pcrel = rel->r_pcrel;
2034
                        type = rel->r_type;
2035
                    }
2036

    
2037
                    slide = offset - start_offset;
2038

    
2039
                    if (!(offset >= start_offset && offset < start_offset + size))
2040
                        continue;  /* not in our range */
2041

    
2042
                        sym_name = get_reloc_name(rel, &sslide);
2043

    
2044
                        if(usesym && symtab[isym].n_type & N_STAB)
2045
                            continue; /* don't handle STAB (debug sym) */
2046

    
2047
                        if (sym_name && strstart(sym_name, "__op_jmp", &p)) {
2048
                            int n;
2049
                            n = strtol(p, NULL, 10);
2050
                            fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
2051
                                    n, slide);
2052
                            continue; /* Nothing more to do */
2053
                        }
2054

    
2055
                        if(!sym_name) {
2056
                            fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n",
2057
                                    name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type);
2058
                            continue; /* dunno how to handle without final_sym_name */
2059
                        }
2060

    
2061
                        get_reloc_expr(final_sym_name, sizeof(final_sym_name),
2062
                                       sym_name);
2063
                        switch(type) {
2064
                        case PPC_RELOC_BR24:
2065
                            if (!strstart(sym_name,"__op_gen_label",&p)) {
2066
                                fprintf(outfile, "{\n");
2067
                                fprintf(outfile, "    uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
2068
                                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",
2069
                                        slide, slide, name, sslide);
2070
                                fprintf(outfile, "}\n");
2071
                            } else {
2072
                                fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
2073
                                        slide, slide, final_sym_name, slide);
2074
                            }
2075
                            break;
2076
                        case PPC_RELOC_HI16:
2077
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n",
2078
                                    slide, final_sym_name, sslide);
2079
                            break;
2080
                        case PPC_RELOC_LO16:
2081
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n",
2082
                                    slide, final_sym_name, sslide);
2083
                            break;
2084
                        case PPC_RELOC_HA16:
2085
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n",
2086
                                    slide, final_sym_name, sslide);
2087
                            break;
2088
                        default:
2089
                            error("unsupported powerpc relocation (%d)", type);
2090
                    }
2091
                }
2092
#else
2093
#error unsupport object format
2094
#endif
2095
            }
2096
#elif defined(HOST_S390)
2097
            {
2098
                char relname[256];
2099
                int type;
2100
                int addend;
2101
                int reloc_offset;
2102
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2103
                    if (rel->r_offset >= start_offset &&
2104
                        rel->r_offset < start_offset + copy_size) {
2105
                        sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2106
                        get_reloc_expr(relname, sizeof(relname), sym_name);
2107
                        type = ELF32_R_TYPE(rel->r_info);
2108
                        addend = rel->r_addend;
2109
                        reloc_offset = rel->r_offset - start_offset;
2110
                        switch(type) {
2111
                        case R_390_32:
2112
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2113
                                    reloc_offset, relname, addend);
2114
                            break;
2115
                        case R_390_16:
2116
                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
2117
                                    reloc_offset, relname, addend);
2118
                            break;
2119
                        case R_390_8:
2120
                            fprintf(outfile, "    *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
2121
                                    reloc_offset, relname, addend);
2122
                            break;
2123
                        default:
2124
                            error("unsupported s390 relocation (%d)", type);
2125
                        }
2126
                    }
2127
                }
2128
            }
2129
#elif defined(HOST_ALPHA)
2130
            {
2131
                for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
2132
                    if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
2133
                        int type;
2134
                        long reloc_offset;
2135

    
2136
                        type = ELF64_R_TYPE(rel->r_info);
2137
                        sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
2138
                        reloc_offset = rel->r_offset - start_offset;
2139
                        switch (type) {
2140
                        case R_ALPHA_GPDISP:
2141
                            /* The gp is just 32 bit, and never changes, so it's easiest to emit it
2142
                               as an immediate instead of constructing it from the pv or ra.  */
2143
                            fprintf(outfile, "    immediate_ldah(gen_code_ptr + %ld, gp);\n",
2144
                                    reloc_offset);
2145
                            fprintf(outfile, "    immediate_lda(gen_code_ptr + %ld, gp);\n",
2146
                                    reloc_offset + (int)rel->r_addend);
2147
                            break;
2148
                        case R_ALPHA_LITUSE:
2149
                            /* jsr to literal hint. Could be used to optimize to bsr. Ignore for
2150
                               now, since some called functions (libc) need pv to be set up.  */
2151
                            break;
2152
                        case R_ALPHA_HINT:
2153
                            /* Branch target prediction hint. Ignore for now.  Should be already
2154
                               correct for in-function jumps.  */
2155
                            break;
2156
                        case R_ALPHA_LITERAL:
2157
                            /* Load a literal from the GOT relative to the gp.  Since there's only a
2158
                               single gp, nothing is to be done.  */
2159
                            break;
2160
                        case R_ALPHA_GPRELHIGH:
2161
                            /* Handle fake relocations against __op_param symbol.  Need to emit the
2162
                               high part of the immediate value instead.  Other symbols need no
2163
                               special treatment.  */
2164
                            if (strstart(sym_name, "__op_param", &p))
2165
                                fprintf(outfile, "    immediate_ldah(gen_code_ptr + %ld, param%s);\n",
2166
                                        reloc_offset, p);
2167
                            break;
2168
                        case R_ALPHA_GPRELLOW:
2169
                            if (strstart(sym_name, "__op_param", &p))
2170
                                fprintf(outfile, "    immediate_lda(gen_code_ptr + %ld, param%s);\n",
2171
                                        reloc_offset, p);
2172
                            break;
2173
                        case R_ALPHA_BRSGP:
2174
                            /* PC-relative jump. Tweak offset to skip the two instructions that try to
2175
                               set up the gp from the pv.  */
2176
                            fprintf(outfile, "    fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
2177
                                    reloc_offset, sym_name, reloc_offset);
2178
                            break;
2179
                        default:
2180
                            error("unsupported Alpha relocation (%d)", type);
2181
                        }
2182
                    }
2183
                }
2184
            }
2185
#elif defined(HOST_IA64)
2186
            {
2187
                unsigned long sym_idx;
2188
                long code_offset;
2189
                char relname[256];
2190
                int type;
2191
                long addend;
2192

    
2193
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2194
                    sym_idx = ELF64_R_SYM(rel->r_info);
2195
                    if (rel->r_offset < start_offset
2196
                        || rel->r_offset >= start_offset + copy_size)
2197
                        continue;
2198
                    sym_name = (strtab + symtab[sym_idx].st_name);
2199
                    code_offset = rel->r_offset - start_offset;
2200
                    if (strstart(sym_name, "__op_jmp", &p)) {
2201
                        int n;
2202
                        n = strtol(p, NULL, 10);
2203
                        /* __op_jmp relocations are done at
2204
                           runtime to do translated block
2205
                           chaining: the offset of the instruction
2206
                           needs to be stored */
2207
                        fprintf(outfile, "    jmp_offsets[%d] ="
2208
                                "%ld + (gen_code_ptr - gen_code_buf);\n",
2209
                                n, code_offset);
2210
                        continue;
2211
                    }
2212
                    get_reloc_expr(relname, sizeof(relname), sym_name);
2213
                    type = ELF64_R_TYPE(rel->r_info);
2214
                    addend = rel->r_addend;
2215
                    switch(type) {
2216
                      case R_IA64_IMM64:
2217
                          fprintf(outfile,
2218
                                  "    ia64_imm64(gen_code_ptr + %ld, "
2219
                                  "%s + %ld);\n",
2220
                                  code_offset, relname, addend);
2221
                          break;
2222
                      case R_IA64_LTOFF22X:
2223
                      case R_IA64_LTOFF22:
2224
                          fprintf(outfile, "    IA64_LTOFF(gen_code_ptr + %ld,"
2225
                                  " %s + %ld, %d);\n",
2226
                                  code_offset, relname, addend,
2227
                                  (type == R_IA64_LTOFF22X));
2228
                          break;
2229
                      case R_IA64_LDXMOV:
2230
                          fprintf(outfile,
2231
                                  "    ia64_ldxmov(gen_code_ptr + %ld,"
2232
                                  " %s + %ld);\n", code_offset, relname, addend);
2233
                          break;
2234

    
2235
                      case R_IA64_PCREL21B:
2236
                          if (strstart(sym_name, "__op_gen_label", NULL)) {
2237
                              fprintf(outfile,
2238
                                      "    ia64_imm21b(gen_code_ptr + %ld,"
2239
                                      " (long) (%s + %ld -\n\t\t"
2240
                                      "((long) gen_code_ptr + %ld)) >> 4);\n",
2241
                                      code_offset, relname, addend,
2242
                                      code_offset & ~0xfUL);
2243
                          } else {
2244
                              fprintf(outfile,
2245
                                      "    IA64_PLT(gen_code_ptr + %ld, "
2246
                                      "%d);\t/* %s + %ld */\n",
2247
                                      code_offset,
2248
                                      get_plt_index(sym_name, addend),
2249
                                      sym_name, addend);
2250
                          }
2251
                          break;
2252
                      default:
2253
                          error("unsupported ia64 relocation (0x%x)",
2254
                                type);
2255
                    }
2256
                }
2257
                fprintf(outfile, "    ia64_nop_b(gen_code_ptr + %d);\n",
2258
                        copy_size - 16 + 2);
2259
            }
2260
#elif defined(HOST_SPARC)
2261
            {
2262
                char relname[256];
2263
                int type;
2264
                int addend;
2265
                int reloc_offset;
2266
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2267
                    if (rel->r_offset >= start_offset &&
2268
                        rel->r_offset < start_offset + copy_size) {
2269
                        sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
2270
                        get_reloc_expr(relname, sizeof(relname), sym_name);
2271
                        type = ELF32_R_TYPE(rel->r_info);
2272
                        addend = rel->r_addend;
2273
                        reloc_offset = rel->r_offset - start_offset;
2274
                        switch(type) {
2275
                        case R_SPARC_32:
2276
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2277
                                    reloc_offset, relname, addend);
2278
                            break;
2279
                        case R_SPARC_HI22:
2280
                            fprintf(outfile,
2281
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2282
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2283
                                    " & ~0x3fffff) "
2284
                                    " | (((%s + %d) >> 10) & 0x3fffff);\n",
2285
                                    reloc_offset, reloc_offset, relname, addend);
2286
                            break;
2287
                        case R_SPARC_LO10:
2288
                            fprintf(outfile,
2289
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2290
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2291
                                    " & ~0x3ff) "
2292
                                    " | ((%s + %d) & 0x3ff);\n",
2293
                                    reloc_offset, reloc_offset, relname, addend);
2294
                            break;
2295
                        case R_SPARC_WDISP30:
2296
                            fprintf(outfile,
2297
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2298
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2299
                                    " & ~0x3fffffff) "
2300
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2301
                                    "    & 0x3fffffff);\n",
2302
                                    reloc_offset, reloc_offset, relname, addend,
2303
                                    reloc_offset);
2304
                            break;
2305
                        case R_SPARC_WDISP22:
2306
                            fprintf(outfile,
2307
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2308
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2309
                                    " & ~0x3fffff) "
2310
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2311
                                    "    & 0x3fffff);\n",
2312
                                    rel->r_offset - start_offset,
2313
                                    rel->r_offset - start_offset,
2314
                                    relname, addend,
2315
                                    rel->r_offset - start_offset);
2316
                            break;
2317
                        default:
2318
                            error("unsupported sparc relocation (%d)", type);
2319
                        }
2320
                    }
2321
                }
2322
            }
2323
#elif defined(HOST_SPARC64)
2324
            {
2325
                char relname[256];
2326
                int type;
2327
                int addend;
2328
                int reloc_offset;
2329
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2330
                    if (rel->r_offset >= start_offset &&
2331
                        rel->r_offset < start_offset + copy_size) {
2332
                        sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
2333
                        get_reloc_expr(relname, sizeof(relname), sym_name);
2334
                        type = ELF32_R_TYPE(rel->r_info);
2335
                        addend = rel->r_addend;
2336
                        reloc_offset = rel->r_offset - start_offset;
2337
                        switch(type) {
2338
                        case R_SPARC_32:
2339
                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2340
                                    reloc_offset, relname, addend);
2341
                            break;
2342
                        case R_SPARC_HI22:
2343
                            fprintf(outfile,
2344
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2345
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2346
                                    " & ~0x3fffff) "
2347
                                    " | (((%s + %d) >> 10) & 0x3fffff);\n",
2348
                                    reloc_offset, reloc_offset, relname, addend);
2349
                            break;
2350
                        case R_SPARC_LO10:
2351
                            fprintf(outfile,
2352
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2353
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2354
                                    " & ~0x3ff) "
2355
                                    " | ((%s + %d) & 0x3ff);\n",
2356
                                    reloc_offset, reloc_offset, relname, addend);
2357
                            break;
2358
                        case R_SPARC_OLO10:
2359
                            addend += ELF64_R_TYPE_DATA (rel->r_info);
2360
                            fprintf(outfile,
2361
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2362
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2363
                                    " & ~0x3ff) "
2364
                                    " | ((%s + %d) & 0x3ff);\n",
2365
                                    reloc_offset, reloc_offset, relname, addend);
2366
                            break;
2367
                        case R_SPARC_WDISP30:
2368
                            fprintf(outfile,
2369
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2370
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2371
                                    " & ~0x3fffffff) "
2372
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2373
                                    "    & 0x3fffffff);\n",
2374
                                    reloc_offset, reloc_offset, relname, addend,
2375
                                    reloc_offset);
2376
                            break;
2377
                        case R_SPARC_WDISP22:
2378
                            fprintf(outfile,
2379
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2380
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2381
                                    " & ~0x3fffff) "
2382
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2383
                                    "    & 0x3fffff);\n",
2384
                                    reloc_offset, reloc_offset, relname, addend,
2385
                                    reloc_offset);
2386
                            break;
2387
                        case R_SPARC_HH22:
2388
                            fprintf(outfile,
2389
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2390
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2391
                                    " & ~0x00000000) "
2392
                                    " | (((%s + %d) >> 42) & 0x00000000);\n",
2393
                                    reloc_offset, reloc_offset, relname, addend);
2394
                             break;
2395

    
2396
                        case R_SPARC_LM22:
2397
                            fprintf(outfile,
2398
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2399
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2400
                                    " & ~0x00000000) "
2401
                                    " | (((%s + %d) >> 10) & 0x00000000);\n",
2402
                                    reloc_offset, reloc_offset, relname, addend);
2403
                            break;
2404

    
2405
                        case R_SPARC_HM10:
2406
                            fprintf(outfile,
2407
                                    "    *(uint32_t *)(gen_code_ptr + %d) = "
2408
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
2409
                                    " & ~0x00000000) "
2410
                                    " | ((((%s + %d) >> 32 & 0x3ff)) & 0x00000000);\n",
2411
                                    reloc_offset, reloc_offset, relname, addend);
2412
                            break;
2413

    
2414
                        default:
2415
                            error("unsupported sparc64 relocation (%d) for symbol %s", type, relname);
2416
                        }
2417
                    }
2418
                }
2419
            }
2420
#elif defined(HOST_ARM)
2421
            {
2422
                char relname[256];
2423
                int type;
2424
                int addend;
2425
                int reloc_offset;
2426
                uint32_t insn;
2427

    
2428
                insn = get32((uint32_t *)(p_start + 4));
2429
                /* If prologue ends in sub sp, sp, #const then assume
2430
                   op has a stack frame and needs the frame pointer.  */
2431
                if ((insn & 0xffffff00) == 0xe24dd000) {
2432
                    int i;
2433
                    uint32_t opcode;
2434
                    opcode = 0xe28db000; /* add fp, sp, #0.  */
2435
#if 0
2436
/* ??? Need to undo the extra stack adjustment at the end of the op.
2437
   For now just leave the stack misaligned and hope it doesn't break anything
2438
   too important.  */
2439
                    if ((insn & 4) != 0) {
2440
                        /* Preserve doubleword stack alignment.  */
2441
                        fprintf(outfile,
2442
                                "    *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n",
2443
                                insn + 4);
2444
                        opcode -= 4;
2445
                    }
2446
#endif
2447
                    insn = get32((uint32_t *)(p_start - 4));
2448
                    /* Calculate the size of the saved registers,
2449
                       excluding pc.  */
2450
                    for (i = 0; i < 15; i++) {
2451
                        if (insn & (1 << i))
2452
                            opcode += 4;
2453
                    }
2454
                    fprintf(outfile,
2455
                            "    *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
2456
                }
2457
                arm_emit_ldr_info(relname, start_offset, outfile, p_start, p_end,
2458
                                  relocs, nb_relocs);
2459

    
2460
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2461
                if (rel->r_offset >= start_offset &&
2462
                    rel->r_offset < start_offset + copy_size) {
2463
                    sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2464
                    /* the compiler leave some unnecessary references to the code */
2465
                    if (sym_name[0] == '\0')
2466
                        continue;
2467
                    get_reloc_expr(relname, sizeof(relname), sym_name);
2468
                    type = ELF32_R_TYPE(rel->r_info);
2469
                    addend = get32((uint32_t *)(text + rel->r_offset));
2470
                    reloc_offset = rel->r_offset - start_offset;
2471
                    switch(type) {
2472
                    case R_ARM_ABS32:
2473
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2474
                                reloc_offset, relname, addend);
2475
                        break;
2476
                    case R_ARM_PC24:
2477
                    case R_ARM_JUMP24:
2478
                    case R_ARM_CALL:
2479
                        fprintf(outfile, "    arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
2480
                                reloc_offset, addend, relname);
2481
                        break;
2482
                    default:
2483
                        error("unsupported arm relocation (%d)", type);
2484
                    }
2485
                }
2486
                }
2487
            }
2488
#elif defined(HOST_M68K)
2489
            {
2490
                char relname[256];
2491
                int type;
2492
                int addend;
2493
                int reloc_offset;
2494
                Elf32_Sym *sym;
2495
                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2496
                if (rel->r_offset >= start_offset &&
2497
                    rel->r_offset < start_offset + copy_size) {
2498
                    sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
2499
                    sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2500
                    get_reloc_expr(relname, sizeof(relname), sym_name);
2501
                    type = ELF32_R_TYPE(rel->r_info);
2502
                    addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
2503
                    reloc_offset = rel->r_offset - start_offset;
2504
                    switch(type) {
2505
                    case R_68K_32:
2506
                        fprintf(outfile, "    /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
2507
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
2508
                                reloc_offset, relname, addend );
2509
                        break;
2510
                    case R_68K_PC32:
2511
                        fprintf(outfile, "    /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
2512
                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
2513
                                reloc_offset, relname, reloc_offset, /*sym->st_value+*/ addend);
2514
                        break;
2515
                    default:
2516
                        error("unsupported m68k relocation (%d)", type);
2517
                    }
2518
                }
2519
                }
2520
            }
2521
#elif defined(HOST_MIPS) || defined(HOST_MIPS64)
2522
            {
2523
                for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
2524
                    if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
2525
                        char relname[256];
2526
                        int type;
2527
                        int addend;
2528
                        int reloc_offset;
2529

    
2530
                        sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
2531
                        /* the compiler leave some unnecessary references to the code */
2532
                        if (sym_name[0] == '\0')
2533
                            continue;
2534
                        get_reloc_expr(relname, sizeof(relname), sym_name);
2535
                        type = ELF32_R_TYPE(rel->r_info);
2536
                        addend = get32((uint32_t *)(text + rel->r_offset));
2537
                        reloc_offset = rel->r_offset - start_offset;
2538
                        switch (type) {
2539
                        case R_MIPS_26:
2540
                            fprintf(outfile, "    /* R_MIPS_26 RELOC, offset 0x%x, name %s */\n",
2541
                                    rel->r_offset, sym_name);
2542
                            fprintf(outfile,
2543
                                    "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
2544
                                    "(0x%x & ~0x3fffff) "
2545
                                    "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) "
2546
                                    "   & 0x3fffff);\n",
2547
                                    reloc_offset, addend, addend, relname, reloc_offset);
2548
                            break;
2549
                        case R_MIPS_HI16:
2550
                            fprintf(outfile, "    /* R_MIPS_HI16 RELOC, offset 0x%x, name %s */\n",
2551
                                    rel->r_offset, sym_name);
2552
                            fprintf(outfile,
2553
                                    "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
2554
                                    "((*(uint32_t *)(gen_code_ptr + 0x%x)) "
2555
                                    " & ~0xffff) "
2556
                                    " | (((%s - 0x8000) >> 16) & 0xffff);\n",
2557
                                    reloc_offset, reloc_offset, relname);
2558
                            break;
2559
                        case R_MIPS_LO16:
2560
                            fprintf(outfile, "    /* R_MIPS_LO16 RELOC, offset 0x%x, name %s */\n",
2561
                                    rel->r_offset, sym_name);
2562
                            fprintf(outfile,
2563
                                    "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
2564
                                    "((*(uint32_t *)(gen_code_ptr + 0x%x)) "
2565
                                    " & ~0xffff) "
2566
                                    " | (%s & 0xffff);\n",
2567
                                    reloc_offset, reloc_offset, relname);
2568
                            break;
2569
                        case R_MIPS_PC16:
2570
                            fprintf(outfile, "    /* R_MIPS_PC16 RELOC, offset 0x%x, name %s */\n",
2571
                                    rel->r_offset, sym_name);
2572
                            fprintf(outfile,
2573
                                    "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
2574
                                    "(0x%x & ~0xffff) "
2575
                                    "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) "
2576
                                    "   & 0xffff);\n",
2577
                                    reloc_offset, addend, addend, relname, reloc_offset);
2578
                            break;
2579
                        case R_MIPS_GOT16:
2580
                        case R_MIPS_CALL16:
2581
                            fprintf(outfile, "    /* R_MIPS_GOT16 RELOC, offset 0x%x, name %s */\n",
2582
                                    rel->r_offset, sym_name);
2583
                            fprintf(outfile,
2584
                                    "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
2585
                                    "((*(uint32_t *)(gen_code_ptr + 0x%x)) "
2586
                                    " & ~0xffff) "
2587
                                    " | (((%s - 0x8000) >> 16) & 0xffff);\n",
2588
                                    reloc_offset, reloc_offset, relname);
2589
                            break;
2590
                        default:
2591
                            error("unsupported MIPS relocation (%d)", type);
2592
                        }
2593
                    }
2594
                }
2595
            }
2596
#else
2597
#error unsupported CPU
2598
#endif
2599
        fprintf(outfile, "    gen_code_ptr += %d;\n", copy_size);
2600
        fprintf(outfile, "}\n");
2601
        fprintf(outfile, "break;\n\n");
2602
    } else {
2603
        fprintf(outfile, "static inline void gen_%s(", name);
2604
        if (nb_args == 0) {
2605
            fprintf(outfile, "void");
2606
        } else {
2607
            for(i = 0; i < nb_args; i++) {
2608
                if (i != 0)
2609
                    fprintf(outfile, ", ");
2610
                fprintf(outfile, "long param%d", i + 1);
2611
            }
2612
        }
2613
        fprintf(outfile, ")\n");
2614
        fprintf(outfile, "{\n");
2615
        for(i = 0; i < nb_args; i++) {
2616
            fprintf(outfile, "    *gen_opparam_ptr++ = param%d;\n", i + 1);
2617
        }
2618
        fprintf(outfile, "    *gen_opc_ptr++ = INDEX_%s;\n", name);
2619
        fprintf(outfile, "}\n\n");
2620
    }
2621
}
2622

    
2623
int gen_file(FILE *outfile, int out_type)
2624
{
2625
    int i;
2626
    EXE_SYM *sym;
2627

    
2628
    if (out_type == OUT_INDEX_OP) {
2629
        fprintf(outfile, "DEF(end, 0, 0)\n");
2630
        fprintf(outfile, "DEF(nop, 0, 0)\n");
2631
        fprintf(outfile, "DEF(nop1, 1, 0)\n");
2632
        fprintf(outfile, "DEF(nop2, 2, 0)\n");
2633
        fprintf(outfile, "DEF(nop3, 3, 0)\n");
2634
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2635
            const char *name;
2636
            name = get_sym_name(sym);
2637
            if (strstart(name, OP_PREFIX, NULL)) {
2638
                gen_code(name, sym->st_value, sym->st_size, outfile, 2);
2639
            }
2640
        }
2641
    } else if (out_type == OUT_GEN_OP) {
2642
        /* generate gen_xxx functions */
2643
        fprintf(outfile, "#include \"dyngen-op.h\"\n");
2644
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2645
            const char *name;
2646
            name = get_sym_name(sym);
2647
            if (strstart(name, OP_PREFIX, NULL)) {
2648
#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
2649
                if (sym->st_shndx != text_shndx)
2650
                    error("invalid section for opcode (0x%x)", sym->st_shndx);
2651
#endif
2652
                gen_code(name, sym->st_value, sym->st_size, outfile, 0);
2653
            }
2654
        }
2655
       
2656
    } else {
2657
        /* generate big code generation switch */
2658

    
2659
#ifdef HOST_ARM
2660
        /* We need to know the size of all the ops so we can figure out when
2661
           to emit constant pools.  This must be consistent with opc.h.  */
2662
fprintf(outfile,
2663
"static const uint32_t arm_opc_size[] = {\n"
2664
"  0,\n" /* end */
2665
"  0,\n" /* nop */
2666
"  0,\n" /* nop1 */
2667
"  0,\n" /* nop2 */
2668
"  0,\n"); /* nop3 */
2669
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2670
            const char *name;
2671
            name = get_sym_name(sym);
2672
            if (strstart(name, OP_PREFIX, NULL)) {
2673
                fprintf(outfile, "  %d,\n", sym->st_size);
2674
            }
2675
        }
2676
fprintf(outfile,
2677
"};\n");
2678
#endif
2679

    
2680
fprintf(outfile,
2681
"int dyngen_code(uint8_t *gen_code_buf,\n"
2682
"                uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
2683
"                const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n"
2684
"{\n"
2685
"    uint8_t *gen_code_ptr;\n"
2686
"    const uint16_t *opc_ptr;\n"
2687
"    const uint32_t *opparam_ptr;\n");
2688

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

2697
   We currently generate:
2698
  
2699
   [ For this example we assume merging would move op1_pool out of range.
2700
     In practice we should be able to combine many ops before the offset
2701
     limits are reached. ]
2702
   op1_code;
2703
   op2_code;
2704
   goto op3;
2705
   op2_pool;
2706
   op1_pool;
2707
op3:
2708
   op3_code;
2709
   ret;
2710
   op3_pool;
2711

2712
   Ideally we'd put op1_pool before op2_pool, but that requires two passes.
2713
 */
2714
fprintf(outfile,
2715
"    uint8_t *last_gen_code_ptr = gen_code_buf;\n"
2716
"    LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
2717
"    uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
2718
/* Initialise the parmissible pool offset to an arbitary large value.  */
2719
"    uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
2720
#endif
2721
#ifdef HOST_IA64
2722
    {
2723
        long addend, not_first = 0;
2724
        unsigned long sym_idx;
2725
        int index, max_index;
2726
        const char *sym_name;
2727
        EXE_RELOC *rel;
2728

    
2729
        max_index = -1;
2730
        for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2731
            sym_idx = ELF64_R_SYM(rel->r_info);
2732
            sym_name = (strtab + symtab[sym_idx].st_name);
2733
            if (strstart(sym_name, "__op_gen_label", NULL))
2734
                continue;
2735
            if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
2736
                continue;
2737

    
2738
            addend = rel->r_addend;
2739
            index = get_plt_index(sym_name, addend);
2740
            if (index <= max_index)
2741
                continue;
2742
            max_index = index;
2743
            fprintf(outfile, "    extern void %s(void);\n", sym_name);
2744
        }
2745

    
2746
        fprintf(outfile,
2747
                "    struct ia64_fixup *plt_fixes = NULL, "
2748
                "*ltoff_fixes = NULL;\n"
2749
                "    static long plt_target[] = {\n\t");
2750

    
2751
        max_index = -1;
2752
        for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2753
            sym_idx = ELF64_R_SYM(rel->r_info);
2754
            sym_name = (strtab + symtab[sym_idx].st_name);
2755
            if (strstart(sym_name, "__op_gen_label", NULL))
2756
                continue;
2757
            if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
2758
                continue;
2759

    
2760
            addend = rel->r_addend;
2761
            index = get_plt_index(sym_name, addend);
2762
            if (index <= max_index)
2763
                continue;
2764
            max_index = index;
2765

    
2766
            if (not_first)
2767
                fprintf(outfile, ",\n\t");
2768
            not_first = 1;
2769
            if (addend)
2770
                fprintf(outfile, "(long) &%s + %ld", sym_name, addend);
2771
            else
2772
                fprintf(outfile, "(long) &%s", sym_name);
2773
        }
2774
        fprintf(outfile, "\n    };\n"
2775
            "    unsigned int plt_offset[%u] = { 0 };\n", max_index + 1);
2776
    }
2777
#endif
2778

    
2779
fprintf(outfile,
2780
"\n"
2781
"    gen_code_ptr = gen_code_buf;\n"
2782
"    opc_ptr = opc_buf;\n"
2783
"    opparam_ptr = opparam_buf;\n");
2784

    
2785
        /* Generate prologue, if needed. */
2786

    
2787
fprintf(outfile,
2788
"    for(;;) {\n");
2789

    
2790
#ifdef HOST_ARM
2791
/* Generate constant pool if needed */
2792
fprintf(outfile,
2793
"            if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
2794
"                gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
2795
"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n"
2796
"                last_gen_code_ptr = gen_code_ptr;\n"
2797
"                arm_ldr_ptr = arm_ldr_table;\n"
2798
"                arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
2799
"                arm_pool_ptr = gen_code_ptr + 0x1000000;\n"
2800
"            }\n");
2801
#endif
2802

    
2803
fprintf(outfile,
2804
"        switch(*opc_ptr++) {\n");
2805

    
2806
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2807
            const char *name;
2808
            name = get_sym_name(sym);
2809
            if (strstart(name, OP_PREFIX, NULL)) {
2810
#if 0
2811
                printf("%4d: %s pos=0x%08x len=%d\n",
2812
                       i, name, sym->st_value, sym->st_size);
2813
#endif
2814
#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
2815
                if (sym->st_shndx != text_shndx)
2816
                    error("invalid section for opcode (0x%x)", sym->st_shndx);
2817
#endif
2818
                gen_code(name, sym->st_value, sym->st_size, outfile, 1);
2819
            }
2820
        }
2821

    
2822
fprintf(outfile,
2823
"        case INDEX_op_nop:\n"
2824
"            break;\n"
2825
"        case INDEX_op_nop1:\n"
2826
"            opparam_ptr++;\n"
2827
"            break;\n"
2828
"        case INDEX_op_nop2:\n"
2829
"            opparam_ptr += 2;\n"
2830
"            break;\n"
2831
"        case INDEX_op_nop3:\n"
2832
"            opparam_ptr += 3;\n"
2833
"            break;\n"
2834
"        default:\n"
2835
"            goto the_end;\n"
2836
"        }\n");
2837

    
2838

    
2839
fprintf(outfile,
2840
"    }\n"
2841
" the_end:\n"
2842
);
2843
#ifdef HOST_IA64
2844
    fprintf(outfile,
2845
            "    {\n"
2846
            "      extern char code_gen_buffer[];\n"
2847
            "      ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
2848
            "(uint64_t) code_gen_buffer + 2*(1<<20), plt_fixes,\n\t\t\t"
2849
            "sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t"
2850
            "plt_target, plt_offset);\n    }\n");
2851
#endif
2852

    
2853
/* generate some code patching */
2854
#ifdef HOST_ARM
2855
fprintf(outfile,
2856
"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
2857
"    gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
2858
"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");
2859
#endif
2860
    /* flush instruction cache */
2861
    fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
2862

    
2863
    fprintf(outfile, "return gen_code_ptr -  gen_code_buf;\n");
2864
    fprintf(outfile, "}\n\n");
2865

    
2866
    }
2867

    
2868
    return 0;
2869
}
2870

    
2871
void usage(void)
2872
{
2873
    printf("dyngen (c) 2003 Fabrice Bellard\n"
2874
           "usage: dyngen [-o outfile] [-c] objfile\n"
2875
           "Generate a dynamic code generator from an object file\n"
2876
           "-c     output enum of operations\n"
2877
           "-g     output gen_op_xx() functions\n"
2878
           );
2879
    exit(1);
2880
}
2881

    
2882
int main(int argc, char **argv)
2883
{
2884
    int c, out_type;
2885
    const char *filename, *outfilename;
2886
    FILE *outfile;
2887

    
2888
    outfilename = "out.c";
2889
    out_type = OUT_CODE;
2890
    for(;;) {
2891
        c = getopt(argc, argv, "ho:cg");
2892
        if (c == -1)
2893
            break;
2894
        switch(c) {
2895
        case 'h':
2896
            usage();
2897
            break;
2898
        case 'o':
2899
            outfilename = optarg;
2900
            break;
2901
        case 'c':
2902
            out_type = OUT_INDEX_OP;
2903
            break;
2904
        case 'g':
2905
            out_type = OUT_GEN_OP;
2906
            break;
2907
        }
2908
    }
2909
    if (optind >= argc)
2910
        usage();
2911
    filename = argv[optind];
2912
    outfile = fopen(outfilename, "w");
2913
    if (!outfile)
2914
        error("could not open '%s'", outfilename);
2915

    
2916
    load_object(filename);
2917
    gen_file(outfile, out_type);
2918
    fclose(outfile);
2919
    return 0;
2920
}