]> git.proxmox.com Git - qemu.git/blame - dyngen.c
Update Sparc parts in documentation
[qemu.git] / dyngen.c
CommitLineData
7d13299d
FB
1/*
2 * Generic Dynamic compiler generator
5fafdf24 3 *
7d13299d
FB
4 * Copyright (c) 2003 Fabrice Bellard
5 *
67b915a5
FB
6 * The COFF object format support was extracted from Kazu's QEMU port
7 * to Win32.
8 *
82eec0a1
FB
9 * Mach-O Support by Matt Reda and Pierre d'Herbemont
10 *
7d13299d
FB
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 */
367e86e8
FB
25#include <stdlib.h>
26#include <stdio.h>
04369ff2 27#include <string.h>
367e86e8
FB
28#include <stdarg.h>
29#include <inttypes.h>
367e86e8
FB
30#include <unistd.h>
31#include <fcntl.h>
32
abcd5da7 33#include "config-host.h"
ce11fedc 34
11d9f695
FB
35/* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross
36 compilation */
37#if defined(CONFIG_WIN32)
67b915a5 38#define CONFIG_FORMAT_COFF
82eec0a1
FB
39#elif defined(CONFIG_DARWIN)
40#define CONFIG_FORMAT_MACH
67b915a5
FB
41#else
42#define CONFIG_FORMAT_ELF
43#endif
44
45#ifdef CONFIG_FORMAT_ELF
46
ce11fedc
FB
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
c4687878 57#elif defined(HOST_X86_64)
bc51c5c9
FB
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
ce11fedc
FB
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
367e86e8 77
ce11fedc
FB
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
efdea7bf
FB
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
d014c98c
FB
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
ff1f20a3
FB
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
38e584a0
FB
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
c4b89d18
TS
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
9617efe8
TS
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
ce11fedc
FB
135#else
136#error unsupported CPU - please update the code
137#endif
138
efdea7bf
FB
139#include "elf.h"
140
ce11fedc
FB
141#if ELF_CLASS == ELFCLASS32
142typedef int32_t host_long;
143typedef uint32_t host_ulong;
efdea7bf 144#define swabls(x) swab32s(x)
a86c8f29 145#define swablss(x) swab32ss(x)
ce11fedc
FB
146#else
147typedef int64_t host_long;
148typedef uint64_t host_ulong;
efdea7bf 149#define swabls(x) swab64s(x)
a86c8f29 150#define swablss(x) swab64ss(x)
fb3e5849
FB
151#endif
152
fe319756
FB
153#ifdef ELF_USES_RELOCA
154#define SHT_RELOC SHT_RELA
155#else
156#define SHT_RELOC SHT_REL
157#endif
158
67b915a5
FB
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
67b915a5
FB
166typedef int32_t host_long;
167typedef uint32_t host_ulong;
168
7a2d6d96
PB
169#include "a.out.h"
170
67b915a5
FB
171#define FILENAMELEN 256
172
173typedef 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
182typedef 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
82eec0a1
FB
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)
201typedef int32_t host_long;
202typedef uint32_t host_ulong;
203
204struct nlist_extended
205{
206 union {
5fafdf24
TS
207 char *n_name;
208 long n_strx;
82eec0a1 209 } n_un;
5fafdf24
TS
210 unsigned char n_type;
211 unsigned char n_sect;
82eec0a1
FB
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
abcd5da7 222#include "bswap.h"
ce11fedc 223
d219f7e7
FB
224enum {
225 OUT_GEN_OP,
226 OUT_CODE,
227 OUT_INDEX_OP,
228};
229
367e86e8 230/* all dynamically generated functions begin with this code */
dc99065b 231#define OP_PREFIX "op_"
367e86e8 232
67b915a5
FB
233int do_swap;
234
235void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
367e86e8 236{
67b915a5
FB
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}
367e86e8 245
67b915a5
FB
246void *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;
367e86e8 259}
67b915a5
FB
260
261int 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
277void 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
367e86e8
FB
294void swab16s(uint16_t *p)
295{
296 *p = bswap16(*p);
297}
298
299void swab32s(uint32_t *p)
300{
301 *p = bswap32(*p);
302}
303
a86c8f29
TS
304void swab32ss(int32_t *p)
305{
306 *p = bswap32(*p);
307}
308
ce11fedc 309void swab64s(uint64_t *p)
367e86e8
FB
310{
311 *p = bswap64(*p);
312}
313
a86c8f29
TS
314void swab64ss(int64_t *p)
315{
316 *p = bswap64(*p);
317}
318
67b915a5
FB
319uint16_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
328uint32_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
337void put16(uint16_t *p, uint16_t val)
338{
339 if (do_swap)
340 val = bswap16(val);
341 *p = val;
342}
343
344void put32(uint32_t *p, uint32_t val)
345{
346 if (do_swap)
347 val = bswap32(val);
348 *p = val;
349}
350
351/* executable information */
352EXE_SYM *symtab;
353int nb_syms;
354int text_shndx;
355uint8_t *text;
356EXE_RELOC *relocs;
357int nb_relocs;
358
359#ifdef CONFIG_FORMAT_ELF
360
361/* ELF file info */
362struct elf_shdr *shdr;
363uint8_t **sdata;
364struct elfhdr ehdr;
365char *strtab;
366
367int 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;
5fafdf24 375 return (h->e_ident[EI_DATA] == ELFDATA2MSB) !=
67b915a5
FB
376 (swaptest.b[0] == 0);
377}
3b46e624 378
ce11fedc 379void elf_swap_ehdr(struct elfhdr *h)
367e86e8
FB
380{
381 swab16s(&h->e_type); /* Object file type */
382 swab16s(&h-> e_machine); /* Architecture */
383 swab32s(&h-> e_version); /* Object file version */
ce11fedc
FB
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 */
367e86e8
FB
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
ce11fedc 396void elf_swap_shdr(struct elf_shdr *h)
367e86e8
FB
397{
398 swab32s(&h-> sh_name); /* Section name (string tbl index) */
399 swab32s(&h-> sh_type); /* Section type */
ce11fedc
FB
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 */
367e86e8
FB
404 swab32s(&h-> sh_link); /* Link to another section */
405 swab32s(&h-> sh_info); /* Additional section information */
ce11fedc
FB
406 swabls(&h-> sh_addralign); /* Section alignment */
407 swabls(&h-> sh_entsize); /* Entry size if section holds table */
367e86e8
FB
408}
409
ce11fedc 410void elf_swap_phdr(struct elf_phdr *h)
367e86e8
FB
411{
412 swab32s(&h->p_type); /* Segment type */
ce11fedc
FB
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 */
367e86e8 418 swab32s(&h->p_flags); /* Segment flags */
ce11fedc 419 swabls(&h->p_align); /* Segment alignment */
367e86e8
FB
420}
421
fe319756
FB
422void elf_swap_rel(ELF_RELOC *rel)
423{
424 swabls(&rel->r_offset);
425 swabls(&rel->r_info);
426#ifdef ELF_USES_RELOCA
a86c8f29 427 swablss(&rel->r_addend);
fe319756
FB
428#endif
429}
430
5fafdf24 431struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr,
67b915a5
FB
432 const char *name)
433{
434 int i;
435 const char *shname;
436 struct elf_shdr *sec;
367e86e8 437
67b915a5
FB
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
449int find_reloc(int sh_index)
367e86e8 450{
67b915a5
FB
451 struct elf_shdr *sec;
452 int i;
453
454 for(i = 0; i < ehdr.e_shnum; i++) {
455 sec = &shdr[i];
5fafdf24 456 if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index)
67b915a5
FB
457 return i;
458 }
459 return 0;
367e86e8
FB
460}
461
82eec0a1
FB
462static host_ulong get_rel_offset(EXE_RELOC *rel)
463{
464 return rel->r_offset;
465}
466
67b915a5 467static char *get_rel_sym_name(EXE_RELOC *rel)
367e86e8 468{
67b915a5
FB
469 return strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
470}
471
472static char *get_sym_name(EXE_SYM *sym)
473{
474 return strtab + sym->st_name;
475}
476
477/* load an elf object file */
478int 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;
3b46e624 486
67b915a5 487 fd = open(filename, O_RDONLY);
5fafdf24 488 if (fd < 0)
67b915a5 489 error("can't open file '%s'", filename);
3b46e624 490
67b915a5
FB
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);
367e86e8 505 if (do_swap)
67b915a5
FB
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);
3b46e624 527
67b915a5
FB
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];
a86c8f29 535 shstr = (char *)sdata[ehdr.e_shstrndx];
67b915a5
FB
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];
a86c8f29 571 strtab = (char *)sdata[symtab_sec->sh_link];
3b46e624 572
67b915a5
FB
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 */
591struct external_scnhdr *shdr;
592uint8_t **sdata;
593struct external_filehdr fhdr;
594struct external_syment *coff_symtab;
595char *strtab;
596int coff_text_shndx, coff_data_shndx;
597
598int 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
608void sym_ent_name(struct external_syment *ext_sym, EXE_SYM *sym)
609{
610 char *q;
611 int c, i, len;
3b46e624 612
67b915a5
FB
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 }
367e86e8
FB
632}
633
67b915a5 634char *name_for_dotdata(struct coff_rel *rel)
367e86e8 635{
67b915a5
FB
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) {
3b46e624 646
67b915a5
FB
647 return sym->st_name;
648
649 }
650 }
651 return NULL;
367e86e8
FB
652}
653
67b915a5 654static char *get_sym_name(EXE_SYM *sym)
367e86e8 655{
67b915a5 656 return sym->st_name;
367e86e8
FB
657}
658
67b915a5 659static char *get_rel_sym_name(EXE_RELOC *rel)
367e86e8 660{
67b915a5
FB
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);
b48a8bb6
FB
665 if (name[0] == '.')
666 return NULL;
67b915a5 667 return name;
367e86e8
FB
668}
669
82eec0a1
FB
670static host_ulong get_rel_offset(EXE_RELOC *rel)
671{
672 return rel->r_offset;
673}
674
67b915a5 675struct external_scnhdr *find_coff_section(struct external_scnhdr *shdr, int shnum, const char *name)
367e86e8
FB
676{
677 int i;
678 const char *shname;
67b915a5 679 struct external_scnhdr *sec;
367e86e8
FB
680
681 for(i = 0; i < shnum; i++) {
682 sec = &shdr[i];
67b915a5 683 if (!sec->s_name)
367e86e8 684 continue;
67b915a5 685 shname = sec->s_name;
367e86e8
FB
686 if (!strcmp(shname, name))
687 return sec;
688 }
689 return NULL;
690}
691
67b915a5
FB
692/* load a coff object file */
693int load_object(const char *filename)
fe319756 694{
67b915a5
FB
695 int fd;
696 struct external_scnhdr *sec, *text_sec, *data_sec;
fe319756 697 int i;
67b915a5
FB
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;
5fafdf24
TS
704
705 fd = open(filename, O_RDONLY
67b915a5
FB
706#ifdef _WIN32
707 | O_BINARY
708#endif
709 );
5fafdf24 710 if (fd < 0)
67b915a5 711 error("can't open file '%s'", filename);
3b46e624 712
67b915a5
FB
713 /* Read COFF header. */
714 if (read(fd, &fhdr, sizeof (fhdr)) != sizeof (fhdr))
715 error("unable to read file header");
fe319756 716
67b915a5
FB
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));
5fafdf24 725
67b915a5
FB
726 /* read all section data */
727 sdata = malloc(sizeof(void *) * fhdr.f_nscns);
728 memset(sdata, 0, sizeof(void *) * fhdr.f_nscns);
3b46e624 729
67b915a5
FB
730 const char *p;
731 for(i = 0;i < fhdr.f_nscns; i++) {
fe319756 732 sec = &shdr[i];
67b915a5
FB
733 if (!strstart(sec->s_name, ".bss", &p))
734 sdata[i] = load_data(fd, sec->s_scnptr, sec->s_size);
fe319756 735 }
fe319756 736
367e86e8 737
67b915a5
FB
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;
3b46e624 750
67b915a5
FB
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");
367e86e8 756 }
367e86e8 757
67b915a5
FB
758
759 n_strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), STRTAB_SIZE);
5fafdf24 760 strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab);
3b46e624 761
67b915a5
FB
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;
367e86e8 769 }
67b915a5
FB
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 }
3b46e624 808
67b915a5
FB
809 sym->st_type = ext_sym->e_type;
810 sym->st_shndx = ext_sym->e_scnum;
811 }
812
3b46e624 813
67b915a5
FB
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);
5fafdf24 821 for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs;
67b915a5
FB
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;
367e86e8
FB
829}
830
67b915a5
FB
831#endif /* CONFIG_FORMAT_COFF */
832
82eec0a1
FB
833#ifdef CONFIG_FORMAT_MACH
834
835/* File Header */
836struct mach_header mach_hdr;
837
838/* commands */
839struct segment_command *segment = 0;
840struct dysymtab_command *dysymtabcmd = 0;
841struct symtab_command *symtabcmd = 0;
842
843/* section */
844struct section *section_hdr;
845struct section *text_sec_hdr;
846uint8_t **sdata;
847
848/* relocs */
849struct relocation_info *relocs;
5fafdf24 850
82eec0a1
FB
851/* symbols */
852EXE_SYM *symtab;
853struct nlist *symtab_std;
854char *strtab;
855
856/* indirect symbols */
857uint32_t *tocdylib;
858
859/* Utility functions */
860
861static inline char *find_str_by_index(int index)
862{
863 return strtab+index;
864}
865
866/* Used by dyngen common code */
867static char *get_sym_name(EXE_SYM *sym)
868{
869 char *name = find_str_by_index(sym->n_un.n_strx);
5fafdf24 870
82eec0a1
FB
871 if ( sym->n_type & N_STAB ) /* Debug symbols are ignored */
872 return "debug";
3b46e624 873
82eec0a1
FB
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 */
5fafdf24 883static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname,
82eec0a1
FB
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 */
5fafdf24 899struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname,
82eec0a1
FB
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
909static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned int *value)
910{
911 struct scattered_relocation_info * scarel;
5fafdf24 912
82eec0a1
FB
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 */
926static const char * find_sym_with_value_and_sec_number( int value, int sectnum, int * offset )
927{
928 int i, ret = -1;
5fafdf24 929
82eec0a1
FB
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
5fafdf24
TS
948/*
949 * Find symbol name given a (virtual) address, and a section which is of type
82eec0a1
FB
950 * S_NON_LAZY_SYMBOL_POINTERS or S_LAZY_SYMBOL_POINTERS or S_SYMBOL_STUBS
951 */
952static 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;
3b46e624 956
82eec0a1
FB
957 /* Sanity check */
958 if(!( address >= sec_hdr->addr && address < (sec_hdr->addr + sec_hdr->size) ) )
959 return (char*)0;
3b46e624 960
82eec0a1
FB
961 if( sec_hdr->flags & S_SYMBOL_STUBS ){
962 size = sec_hdr->reserved2;
963 if(size == 0)
964 error("size = 0");
3b46e624 965
82eec0a1
FB
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;
3b46e624 972
82eec0a1
FB
973 /* Compute our index in toc */
974 tocindex = (address - sec_hdr->addr)/size;
975 symindex = tocdylib[sec_hdr->reserved1 + tocindex];
5fafdf24 976
82eec0a1
FB
977 name = get_sym_name(&symtab[symindex]);
978
979 return name;
980}
981
982static 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
994static 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;
5fafdf24 1001
82eec0a1
FB
1002 /* init the slide value */
1003 *sslide = 0;
5fafdf24 1004
82eec0a1
FB
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 */
5fafdf24 1011 if ( symtab[rel->r_symbolnum].n_type & N_STAB )
82eec0a1
FB
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;
3b46e624 1018
82eec0a1
FB
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 {
91aa5d49 1028 case PPC_RELOC_LO16: fetch_next_pair_value(rel+1, &other_half); sectoffset |= (other_half << 16);
82eec0a1 1029 break;
91aa5d49 1030 case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) | (uint16_t)(other_half & 0xffff);
82eec0a1 1031 break;
91aa5d49 1032 case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) + (int16_t)(other_half & 0xffff);
82eec0a1
FB
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;
3b46e624 1044
82eec0a1
FB
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);
5fafdf24 1051
82eec0a1
FB
1052 return name;
1053}
1054
1055/* Used by dyngen common code */
1056static 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 */
1063static 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 */
1073int 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;
3b46e624 1083
82eec0a1 1084 fd = open(filename, O_RDONLY);
5fafdf24 1085 if (fd < 0)
82eec0a1 1086 error("can't open file '%s'", filename);
3b46e624 1087
82eec0a1
FB
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 }
3b46e624 1096
82eec0a1
FB
1097 if (mach_hdr.cputype != CPU_TYPE_POWERPC)
1098 error("Unsupported CPU");
3b46e624 1099
82eec0a1
FB
1100 if (mach_hdr.filetype != MH_OBJECT)
1101 error("Unsupported Mach Object");
3b46e624 1102
82eec0a1
FB
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);
3b46e624 1146
82eec0a1
FB
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 }
5fafdf24 1151
82eec0a1
FB
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];
5fafdf24 1158
82eec0a1
FB
1159 /* Make sure dysym was loaded */
1160 if(!(int)dysymtabcmd)
1161 error("could not find __DYSYMTAB segment");
3b46e624 1162
82eec0a1
FB
1163 /* read the table of content of the indirect sym */
1164 tocdylib = load_data( fd, dysymtabcmd->indirectsymoff, dysymtabcmd->nindirectsyms * sizeof(uint32_t) );
3b46e624 1165
82eec0a1
FB
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);
5fafdf24 1173
82eec0a1 1174 symtab = malloc(sizeof(EXE_SYM) * nb_syms);
5fafdf24 1175
82eec0a1
FB
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++) {
82eec0a1
FB
1178 struct nlist *sym_follow, *sym_next = 0;
1179 unsigned int j;
82eec0a1 1180 memset(sym, 0, sizeof(*sym));
3b46e624 1181
91aa5d49 1182 if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
82eec0a1 1183 continue;
3b46e624 1184
82eec0a1 1185 memcpy(sym, syment, sizeof(*syment));
3b46e624 1186
82eec0a1
FB
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 }
5fafdf24 1204
82eec0a1
FB
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
bef79c34
FB
1215void 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] == '.')
4bb3973f 1226 snprintf(name, name_size,
bef79c34
FB
1227 "(long)(&__dot_%s)",
1228 sym_name + 1);
1229 else
1230#endif
1231 snprintf(name, name_size, "(long)(&%s)", sym_name);
1232 }
1233}
1234
b8076a74
FB
1235#ifdef HOST_IA64
1236
1237#define PLT_ENTRY_SIZE 16 /* 1 bundle containing "brl" */
1238
1239struct plt_entry {
1240 struct plt_entry *next;
1241 const char *name;
1242 unsigned long addend;
1243} *plt_list;
1244
1245static int
1246get_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
ff1f20a3
FB
1277#ifdef HOST_ARM
1278
1279int 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;
46152182 1285 int offset, min_offset, pc_offset, data_size, spare, max_pool;
ff1f20a3
FB
1286 uint8_t data_allocated[1024];
1287 unsigned int data_index;
46152182 1288 int type;
3b46e624 1289
ff1f20a3 1290 memset(data_allocated, 0, sizeof(data_allocated));
3b46e624 1291
ff1f20a3
FB
1292 p = p_start;
1293 min_offset = p_end - p_start;
46152182 1294 spare = 0x7fffffff;
ff1f20a3
FB
1295 while (p < p_start + min_offset) {
1296 insn = get32((uint32_t *)p);
46152182
PB
1297 /* TODO: Armv5e ldrd. */
1298 /* TODO: VFP load. */
ff1f20a3
FB
1299 if ((insn & 0x0d5f0000) == 0x051f0000) {
1300 /* ldr reg, [pc, #im] */
1301 offset = insn & 0xfff;
1302 if (!(insn & 0x00800000))
46152182
PB
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;
ff1f20a3 1333 if ((offset & 3) !=0)
5fafdf24 1334 error("%s:%04x: pc offset must be 32 bit aligned",
46152182
PB
1335 name, start_offset + p - p_start);
1336 if (offset < 0)
1337 error("%s:%04x: Embedded literal value",
ff1f20a3
FB
1338 name, start_offset + p - p_start);
1339 pc_offset = p - p_start + offset + 8;
5fafdf24 1340 if (pc_offset <= (p - p_start) ||
ff1f20a3 1341 pc_offset >= (p_end - p_start))
5fafdf24 1342 error("%s:%04x: pc offset must point inside the function code",
ff1f20a3
FB
1343 name, start_offset + p - p_start);
1344 if (pc_offset < min_offset)
1345 min_offset = pc_offset;
1346 if (outfile) {
46152182 1347 /* The intruction position */
5fafdf24 1348 fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
ff1f20a3 1349 p - p_start);
46152182
PB
1350 /* The position of the constant pool data. */
1351 data_index = ((p_end - p_start) - pc_offset) >> 2;
5fafdf24 1352 fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n",
ff1f20a3 1353 data_index);
46152182 1354 fprintf(outfile, " arm_ldr_ptr->type = %d;\n", type);
ff1f20a3 1355 fprintf(outfile, " arm_ldr_ptr++;\n");
ff1f20a3
FB
1356 }
1357 }
1358 p += 4;
1359 }
46152182
PB
1360
1361 /* Copy and relocate the constant pool data. */
ff1f20a3
FB
1362 data_size = (p_end - p_start) - min_offset;
1363 if (data_size > 0 && outfile) {
46152182
PB
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 }
ff1f20a3
FB
1403 }
1404
ff1f20a3
FB
1405 if (p == p_start)
1406 goto arm_ret_error;
1407 p -= 4;
1408 insn = get32((uint32_t *)p);
46152182
PB
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) {
ff1f20a3
FB
1423 arm_ret_error:
1424 if (!outfile)
1425 printf("%s: invalid epilog\n", name);
1426 }
46152182 1427 return p - p_start;
ff1f20a3
FB
1428}
1429#endif
1430
1431
367e86e8
FB
1432#define MAX_ARGS 3
1433
1434/* generate op code */
5fafdf24 1435void gen_code(const char *name, host_ulong offset, host_ulong size,
67b915a5 1436 FILE *outfile, int gen_switch)
367e86e8
FB
1437{
1438 int copy_size = 0;
1439 uint8_t *p_start, *p_end;
ae228531 1440 host_ulong start_offset;
ce11fedc 1441 int nb_args, i, n;
367e86e8
FB
1442 uint8_t args_present[MAX_ARGS];
1443 const char *sym_name, *p;
67b915a5 1444 EXE_RELOC *rel;
367e86e8 1445
ae228531
FB
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 */
367e86e8
FB
1451 p_start = text + offset;
1452 p_end = p_start + size;
ae228531 1453 start_offset = offset;
c4687878 1454#if defined(HOST_I386) || defined(HOST_X86_64)
67b915a5
FB
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)
d4e8164f 1464 error("ret or jmp expected at the end of %s", name);
367e86e8 1465 }
67b915a5
FB
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);
367e86e8 1478 }
67b915a5
FB
1479 copy_size = len;
1480 }
3b46e624 1481#endif
67b915a5
FB
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;
630be16f 1506#if 0
67b915a5
FB
1507 /* XXX: check why it occurs */
1508 if (p == p_start)
1509 error("empty code for %s", name);
630be16f 1510#endif
67b915a5
FB
1511 if (get32((uint32_t *)p) != 0x6bfa8001)
1512 error("ret expected at the end of %s", name);
3b46e624 1513 copy_size = p - p_start;
67b915a5
FB
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);
b8076a74 1525 copy_size = p_end - p_start;
67b915a5
FB
1526 }
1527#elif defined(HOST_SPARC)
1528 {
fdbb4691
FB
1529#define INSN_SAVE 0x9de3a000
1530#define INSN_RET 0x81c7e008
74ccb34e 1531#define INSN_RETL 0x81c3e008
fdbb4691
FB
1532#define INSN_RESTORE 0x81e80000
1533#define INSN_RETURN 0x81cfe008
1534#define INSN_NOP 0x01000000
74ccb34e
FB
1535#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
1536#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
fdbb4691 1537
67b915a5
FB
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));
74ccb34e
FB
1546 if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1547 (start_insn & ~0x1fff) == INSN_ADD_SP) {
67b915a5
FB
1548 p_start += 0x4;
1549 start_offset += 0x4;
fdbb4691
FB
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; */ ;
74ccb34e
FB
1554 else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
1555 /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
fdbb4691
FB
1556 else
1557
67b915a5 1558 error("ret; restore; not found at end of %s", name);
74ccb34e
FB
1559 } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1560 ;
67b915a5
FB
1561 } else {
1562 error("No save at the beginning of %s", name);
1563 }
ff1f20a3 1564#if 0
67b915a5
FB
1565 /* Skip a preceeding nop, if present. */
1566 if (p > p_start) {
1567 skip_insn = get32((uint32_t *)(p - 0x4));
fdbb4691 1568 if (skip_insn == INSN_NOP)
67b915a5
FB
1569 p -= 4;
1570 }
ff1f20a3 1571#endif
67b915a5
FB
1572 copy_size = p - p_start;
1573 }
1574#elif defined(HOST_SPARC64)
1575 {
74ccb34e
FB
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
67b915a5
FB
1585 uint32_t start_insn, end_insn1, end_insn2, skip_insn;
1586 uint8_t *p;
1587 p = (void *)(p_end - 8);
74ccb34e
FB
1588#if 0
1589 /* XXX: check why it occurs */
67b915a5
FB
1590 if (p <= p_start)
1591 error("empty code for %s", name);
74ccb34e 1592#endif
67b915a5
FB
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));
74ccb34e
FB
1596 if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1597 (start_insn & ~0x1fff) == INSN_ADD_SP) {
67b915a5
FB
1598 p_start += 0x4;
1599 start_offset += 0x4;
74ccb34e
FB
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
67b915a5 1608 error("ret; restore; not found at end of %s", name);
74ccb34e
FB
1609 } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1610 ;
67b915a5
FB
1611 } else {
1612 error("No save at the beginning of %s", name);
1613 }
3b46e624 1614
67b915a5
FB
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 }
3b46e624 1621
67b915a5
FB
1622 copy_size = p - p_start;
1623 }
1624#elif defined(HOST_ARM)
1625 {
46152182
PB
1626 uint32_t insn;
1627
ff1f20a3
FB
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;
46152182
PB
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 }
5fafdf24 1642 copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
ff1f20a3 1643 relocs, nb_relocs);
367e86e8 1644 }
67b915a5
FB
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) &&
5fafdf24 1653 (p>p_start))
67b915a5
FB
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 }
9617efe8 1659#elif defined(HOST_MIPS) || defined(HOST_MIPS64)
c4b89d18
TS
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 }
67b915a5
FB
1679#else
1680#error unsupported CPU
1681#endif
367e86e8
FB
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
ce11fedc 1687 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
82eec0a1
FB
1688 host_ulong offset = get_rel_offset(rel);
1689 if (offset >= start_offset &&
1690 offset < start_offset + (p_end - p_start)) {
67b915a5 1691 sym_name = get_rel_sym_name(rel);
82eec0a1
FB
1692 if(!sym_name)
1693 continue;
c4687878
FB
1694 if (strstart(sym_name, "__op_param", &p) ||
1695 strstart(sym_name, "__op_gen_label", &p)) {
ce11fedc 1696 n = strtoul(p, NULL, 10);
d4e8164f 1697 if (n > MAX_ARGS)
ce11fedc
FB
1698 error("too many arguments in %s", name);
1699 args_present[n - 1] = 1;
367e86e8
FB
1700 }
1701 }
1702 }
3b46e624 1703
367e86e8
FB
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
0ea00c9a 1712 if (gen_switch == 2) {
a513fe19 1713 fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
0ea00c9a 1714 } else if (gen_switch == 1) {
dc99065b
FB
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");
367e86e8 1726 }
b8076a74
FB
1727#if defined(HOST_IA64)
1728 fprintf(outfile, " extern char %s;\n", name);
1729#else
dc99065b 1730 fprintf(outfile, " extern void %s();\n", name);
b8076a74 1731#endif
dc99065b 1732
ce11fedc 1733 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
82eec0a1
FB
1734 host_ulong offset = get_rel_offset(rel);
1735 if (offset >= start_offset &&
1736 offset < start_offset + (p_end - p_start)) {
67b915a5 1737 sym_name = get_rel_sym_name(rel);
82eec0a1
FB
1738 if(!sym_name)
1739 continue;
5fafdf24 1740 if (*sym_name &&
d4e8164f 1741 !strstart(sym_name, "__op_param", NULL) &&
c4687878
FB
1742 !strstart(sym_name, "__op_jmp", NULL) &&
1743 !strstart(sym_name, "__op_gen_label", NULL)) {
d014c98c
FB
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
b8076a74 1752#if defined(__APPLE__)
85028e4d
TS
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);
b8076a74
FB
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);
82eec0a1 1765#else
ce11fedc 1766 fprintf(outfile, "extern char %s;\n", sym_name);
82eec0a1 1767#endif
dc99065b
FB
1768 }
1769 }
1770 }
1771
82eec0a1
FB
1772 fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n",
1773 name, (int)(start_offset - offset), copy_size);
d4e8164f
FB
1774
1775 /* emit code offset information */
1776 {
67b915a5 1777 EXE_SYM *sym;
d4e8164f 1778 const char *sym_name, *p;
7a2d6d96 1779 host_ulong val;
d4e8164f
FB
1780 int n;
1781
1782 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
67b915a5 1783 sym_name = get_sym_name(sym);
d4e8164f 1784 if (strstart(sym_name, "__op_label", &p)) {
c1e42a13 1785 uint8_t *ptr;
fe319756 1786 unsigned long offset;
3b46e624 1787
d4e8164f
FB
1788 /* test if the variable refers to a label inside
1789 the code we are generating */
67b915a5
FB
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 }
82eec0a1
FB
1798#elif defined(CONFIG_FORMAT_MACH)
1799 if(!sym->n_sect)
1800 continue;
1801 ptr = sdata[sym->n_sect-1];
67b915a5 1802#else
fe319756 1803 ptr = sdata[sym->st_shndx];
67b915a5 1804#endif
fe319756
FB
1805 if (!ptr)
1806 error("__op_labelN in invalid section");
1807 offset = sym->st_value;
82eec0a1
FB
1808#ifdef CONFIG_FORMAT_MACH
1809 offset -= section_hdr[sym->n_sect-1].addr;
1810#endif
7a2d6d96 1811 val = *(host_ulong *)(ptr + offset);
fe319756
FB
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) {
5fafdf24 1819 nb_relocs1 = shdr[reloc_shndx].sh_size /
fe319756
FB
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) {
039de852 1824 val = rel->r_addend;
fe319756
FB
1825 break;
1826 }
1827 rel++;
1828 }
1829 }
1830 }
3b46e624 1831#endif
c4687878 1832 if (val >= start_offset && val <= start_offset + copy_size) {
d4e8164f 1833 n = strtol(p, NULL, 10);
3442e896 1834 fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset));
d4e8164f
FB
1835 }
1836 }
1837 }
1838 }
1839
85028e4d 1840 /* load parameters in variables */
dc99065b
FB
1841 for(i = 0; i < nb_args; i++) {
1842 fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1);
1843 }
1844
1845 /* patch relocations */
ce11fedc 1846#if defined(HOST_I386)
dc99065b 1847 {
4a1a1707 1848 char relname[256];
dc99065b 1849 int type;
ce11fedc 1850 int addend;
3442e896 1851 int reloc_offset;
dc99065b 1852 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
ae228531
FB
1853 if (rel->r_offset >= start_offset &&
1854 rel->r_offset < start_offset + copy_size) {
67b915a5 1855 sym_name = get_rel_sym_name(rel);
b48a8bb6
FB
1856 if (!sym_name)
1857 continue;
3442e896 1858 reloc_offset = rel->r_offset - start_offset;
ecd854fd
FB
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",
3442e896 1867 n, reloc_offset);
ecd854fd
FB
1868 continue;
1869 }
3442e896 1870
4a1a1707 1871 get_reloc_expr(relname, sizeof(relname), sym_name);
367e86e8 1872 addend = get32((uint32_t *)(text + rel->r_offset));
67b915a5
FB
1873#ifdef CONFIG_FORMAT_ELF
1874 type = ELF32_R_TYPE(rel->r_info);
367e86e8
FB
1875 switch(type) {
1876 case R_386_32:
5fafdf24 1877 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
4a1a1707 1878 reloc_offset, relname, addend);
367e86e8
FB
1879 break;
1880 case R_386_PC32:
5fafdf24 1881 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
4a1a1707 1882 reloc_offset, relname, reloc_offset, addend);
367e86e8
FB
1883 break;
1884 default:
1885 error("unsupported i386 relocation (%d)", type);
1886 }
67b915a5 1887#elif defined(CONFIG_FORMAT_COFF)
40c3bac3
FB
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 }
67b915a5
FB
1901 type = rel->r_type;
1902 switch(type) {
1903 case DIR32:
5fafdf24 1904 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
4a1a1707 1905 reloc_offset, relname, addend);
67b915a5
FB
1906 break;
1907 case DISP32:
5fafdf24 1908 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
4a1a1707 1909 reloc_offset, relname, reloc_offset, addend);
67b915a5
FB
1910 break;
1911 default:
1912 error("unsupported i386 relocation (%d)", type);
1913 }
1914#else
1915#error unsupport object format
1916#endif
367e86e8 1917 }
dc99065b
FB
1918 }
1919 }
c4687878 1920#elif defined(HOST_X86_64)
bc51c5c9 1921 {
4a1a1707 1922 char relname[256];
bc51c5c9
FB
1923 int type;
1924 int addend;
3442e896 1925 int reloc_offset;
bc51c5c9
FB
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;
4a1a1707 1930 get_reloc_expr(relname, sizeof(relname), sym_name);
bc51c5c9
FB
1931 type = ELF32_R_TYPE(rel->r_info);
1932 addend = rel->r_addend;
3442e896 1933 reloc_offset = rel->r_offset - start_offset;
bc51c5c9
FB
1934 switch(type) {
1935 case R_X86_64_32:
5fafdf24 1936 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
4a1a1707 1937 reloc_offset, relname, addend);
bc51c5c9
FB
1938 break;
1939 case R_X86_64_32S:
5fafdf24 1940 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
4a1a1707 1941 reloc_offset, relname, addend);
bc51c5c9
FB
1942 break;
1943 case R_X86_64_PC32:
5fafdf24 1944 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
4a1a1707 1945 reloc_offset, relname, reloc_offset, addend);
bc51c5c9
FB
1946 break;
1947 default:
c4687878 1948 error("unsupported X86_64 relocation (%d)", type);
bc51c5c9
FB
1949 }
1950 }
1951 }
1952 }
ce11fedc 1953#elif defined(HOST_PPC)
04369ff2 1954 {
82eec0a1 1955#ifdef CONFIG_FORMAT_ELF
4a1a1707 1956 char relname[256];
04369ff2 1957 int type;
ce11fedc 1958 int addend;
3442e896 1959 int reloc_offset;
04369ff2 1960 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
ae228531
FB
1961 if (rel->r_offset >= start_offset &&
1962 rel->r_offset < start_offset + copy_size) {
efdea7bf 1963 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
3442e896 1964 reloc_offset = rel->r_offset - start_offset;
d4e8164f
FB
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",
3442e896 1973 n, reloc_offset);
d4e8164f
FB
1974 continue;
1975 }
3b46e624 1976
4a1a1707 1977 get_reloc_expr(relname, sizeof(relname), sym_name);
04369ff2
FB
1978 type = ELF32_R_TYPE(rel->r_info);
1979 addend = rel->r_addend;
1980 switch(type) {
1981 case R_PPC_ADDR32:
5fafdf24 1982 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
4a1a1707 1983 reloc_offset, relname, addend);
04369ff2
FB
1984 break;
1985 case R_PPC_ADDR16_LO:
5fafdf24 1986 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
4a1a1707 1987 reloc_offset, relname, addend);
04369ff2
FB
1988 break;
1989 case R_PPC_ADDR16_HI:
5fafdf24 1990 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
4a1a1707 1991 reloc_offset, relname, addend);
04369ff2
FB
1992 break;
1993 case R_PPC_ADDR16_HA:
5fafdf24 1994 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
4a1a1707 1995 reloc_offset, relname, addend);
04369ff2
FB
1996 break;
1997 case R_PPC_REL24:
1998 /* warning: must be at 32 MB distancy */
5fafdf24 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",
4a1a1707 2000 reloc_offset, reloc_offset, relname, reloc_offset, addend);
04369ff2
FB
2001 break;
2002 default:
2003 error("unsupported powerpc relocation (%d)", type);
2004 }
2005 }
2006 }
82eec0a1 2007#elif defined(CONFIG_FORMAT_MACH)
a029baa4
TS
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
5fafdf24 2039 if (!(offset >= start_offset && offset < start_offset + size))
a029baa4
TS
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
5fafdf24 2061 get_reloc_expr(final_sym_name, sizeof(final_sym_name),
a029baa4
TS
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 }
82eec0a1 2075 break;
a029baa4 2076 case PPC_RELOC_HI16:
5fafdf24 2077 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n",
a029baa4
TS
2078 slide, final_sym_name, sslide);
2079 break;
2080 case PPC_RELOC_LO16:
5fafdf24 2081 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n",
a029baa4
TS
2082 slide, final_sym_name, sslide);
2083 break;
2084 case PPC_RELOC_HA16:
5fafdf24 2085 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n",
a029baa4
TS
2086 slide, final_sym_name, sslide);
2087 break;
2088 default:
2089 error("unsupported powerpc relocation (%d)", type);
2090 }
2091 }
82eec0a1
FB
2092#else
2093#error unsupport object format
2094#endif
04369ff2 2095 }
ce11fedc 2096#elif defined(HOST_S390)
fb3e5849 2097 {
4a1a1707 2098 char relname[256];
fb3e5849 2099 int type;
ce11fedc 2100 int addend;
3442e896 2101 int reloc_offset;
fb3e5849 2102 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
ae228531
FB
2103 if (rel->r_offset >= start_offset &&
2104 rel->r_offset < start_offset + copy_size) {
efdea7bf 2105 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
4a1a1707 2106 get_reloc_expr(relname, sizeof(relname), sym_name);
fb3e5849
FB
2107 type = ELF32_R_TYPE(rel->r_info);
2108 addend = rel->r_addend;
3442e896 2109 reloc_offset = rel->r_offset - start_offset;
fb3e5849
FB
2110 switch(type) {
2111 case R_390_32:
5fafdf24 2112 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
4a1a1707 2113 reloc_offset, relname, addend);
fb3e5849
FB
2114 break;
2115 case R_390_16:
5fafdf24 2116 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
4a1a1707 2117 reloc_offset, relname, addend);
fb3e5849
FB
2118 break;
2119 case R_390_8:
5fafdf24 2120 fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
4a1a1707 2121 reloc_offset, relname, addend);
fb3e5849
FB
2122 break;
2123 default:
2124 error("unsupported s390 relocation (%d)", type);
2125 }
2126 }
2127 }
2128 }
efdea7bf
FB
2129#elif defined(HOST_ALPHA)
2130 {
2131 for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
ae228531 2132 if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
efdea7bf 2133 int type;
3442e896 2134 long reloc_offset;
74c95119 2135
efdea7bf 2136 type = ELF64_R_TYPE(rel->r_info);
74c95119 2137 sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
3442e896 2138 reloc_offset = rel->r_offset - start_offset;
efdea7bf
FB
2139 switch (type) {
2140 case R_ALPHA_GPDISP:
74c95119
FB
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",
3442e896 2144 reloc_offset);
74c95119 2145 fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n",
3442e896 2146 reloc_offset + (int)rel->r_addend);
efdea7bf
FB
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:
74c95119
FB
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",
3442e896 2166 reloc_offset, p);
74c95119
FB
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",
3442e896 2171 reloc_offset, p);
74c95119
FB
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. */
2f87c607 2176 fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
3442e896 2177 reloc_offset, sym_name, reloc_offset);
efdea7bf
FB
2178 break;
2179 default:
2180 error("unsupported Alpha relocation (%d)", type);
2181 }
2182 }
2183 }
2184 }
2185#elif defined(HOST_IA64)
2186 {
b8076a74
FB
2187 unsigned long sym_idx;
2188 long code_offset;
4a1a1707 2189 char relname[256];
efdea7bf 2190 int type;
b8076a74
FB
2191 long addend;
2192
efdea7bf 2193 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
b8076a74
FB
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);
3442e896 2199 code_offset = rel->r_offset - start_offset;
b8076a74
FB
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",
3442e896 2209 n, code_offset);
b8076a74
FB
2210 continue;
2211 }
4a1a1707 2212 get_reloc_expr(relname, sizeof(relname), sym_name);
b8076a74
FB
2213 type = ELF64_R_TYPE(rel->r_info);
2214 addend = rel->r_addend;
b8076a74
FB
2215 switch(type) {
2216 case R_IA64_IMM64:
2217 fprintf(outfile,
2218 " ia64_imm64(gen_code_ptr + %ld, "
2219 "%s + %ld);\n",
4a1a1707 2220 code_offset, relname, addend);
b8076a74
FB
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",
4a1a1707 2226 code_offset, relname, addend,
b8076a74
FB
2227 (type == R_IA64_LTOFF22X));
2228 break;
2229 case R_IA64_LDXMOV:
2230 fprintf(outfile,
2231 " ia64_ldxmov(gen_code_ptr + %ld,"
4a1a1707 2232 " %s + %ld);\n", code_offset, relname, addend);
b8076a74
FB
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",
4a1a1707 2241 code_offset, relname, addend,
b8076a74
FB
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 }
efdea7bf 2256 }
b8076a74
FB
2257 fprintf(outfile, " ia64_nop_b(gen_code_ptr + %d);\n",
2258 copy_size - 16 + 2);
efdea7bf 2259 }
d014c98c
FB
2260#elif defined(HOST_SPARC)
2261 {
4a1a1707 2262 char relname[256];
d014c98c
FB
2263 int type;
2264 int addend;
3442e896 2265 int reloc_offset;
d014c98c 2266 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
ae228531
FB
2267 if (rel->r_offset >= start_offset &&
2268 rel->r_offset < start_offset + copy_size) {
d014c98c 2269 sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
4a1a1707 2270 get_reloc_expr(relname, sizeof(relname), sym_name);
d014c98c
FB
2271 type = ELF32_R_TYPE(rel->r_info);
2272 addend = rel->r_addend;
3442e896 2273 reloc_offset = rel->r_offset - start_offset;
d014c98c
FB
2274 switch(type) {
2275 case R_SPARC_32:
5fafdf24 2276 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
4a1a1707 2277 reloc_offset, relname, addend);
d014c98c
FB
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) "
ae228531 2284 " | (((%s + %d) >> 10) & 0x3fffff);\n",
4a1a1707 2285 reloc_offset, reloc_offset, relname, addend);
d014c98c
FB
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",
4a1a1707 2293 reloc_offset, reloc_offset, relname, addend);
d014c98c
FB
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) "
ae228531 2300 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
d014c98c 2301 " & 0x3fffffff);\n",
4a1a1707 2302 reloc_offset, reloc_offset, relname, addend,
3442e896 2303 reloc_offset);
d014c98c 2304 break;
fdbb4691
FB
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,
4a1a1707 2314 relname, addend,
fdbb4691
FB
2315 rel->r_offset - start_offset);
2316 break;
d014c98c
FB
2317 default:
2318 error("unsupported sparc relocation (%d)", type);
2319 }
2320 }
2321 }
2322 }
2323#elif defined(HOST_SPARC64)
2324 {
4a1a1707 2325 char relname[256];
d014c98c
FB
2326 int type;
2327 int addend;
3442e896 2328 int reloc_offset;
d014c98c 2329 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
ae228531
FB
2330 if (rel->r_offset >= start_offset &&
2331 rel->r_offset < start_offset + copy_size) {
d014c98c 2332 sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
4a1a1707 2333 get_reloc_expr(relname, sizeof(relname), sym_name);
74ccb34e 2334 type = ELF32_R_TYPE(rel->r_info);
d014c98c 2335 addend = rel->r_addend;
3442e896 2336 reloc_offset = rel->r_offset - start_offset;
d014c98c
FB
2337 switch(type) {
2338 case R_SPARC_32:
2339 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
4a1a1707 2340 reloc_offset, relname, addend);
d014c98c
FB
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) "
ae228531 2347 " | (((%s + %d) >> 10) & 0x3fffff);\n",
4a1a1707 2348 reloc_offset, reloc_offset, relname, addend);
d014c98c
FB
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",
4a1a1707 2356 reloc_offset, reloc_offset, relname, addend);
d014c98c 2357 break;
74ccb34e
FB
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",
4a1a1707 2365 reloc_offset, reloc_offset, relname, addend);
74ccb34e 2366 break;
d014c98c
FB
2367 case R_SPARC_WDISP30:
2368 fprintf(outfile,
2369 " *(uint32_t *)(gen_code_ptr + %d) = "
2370 "((*(uint32_t *)(gen_code_ptr + %d)) "
2371 " & ~0x3fffffff) "
ae228531 2372 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
d014c98c 2373 " & 0x3fffffff);\n",
4a1a1707 2374 reloc_offset, reloc_offset, relname, addend,
3442e896 2375 reloc_offset);
d014c98c 2376 break;
74ccb34e
FB
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",
4a1a1707 2384 reloc_offset, reloc_offset, relname, addend,
74ccb34e
FB
2385 reloc_offset);
2386 break;
b80029ca
TS
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",
4a1a1707 2393 reloc_offset, reloc_offset, relname, addend);
b80029ca
TS
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",
4a1a1707 2402 reloc_offset, reloc_offset, relname, addend);
b80029ca
TS
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",
4a1a1707 2411 reloc_offset, reloc_offset, relname, addend);
b80029ca
TS
2412 break;
2413
d014c98c 2414 default:
4a1a1707 2415 error("unsupported sparc64 relocation (%d) for symbol %s", type, relname);
d014c98c
FB
2416 }
2417 }
2418 }
2419 }
ff1f20a3
FB
2420#elif defined(HOST_ARM)
2421 {
4a1a1707 2422 char relname[256];
ff1f20a3
FB
2423 int type;
2424 int addend;
3442e896 2425 int reloc_offset;
46152182
PB
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 }
4a1a1707 2457 arm_emit_ldr_info(relname, start_offset, outfile, p_start, p_end,
ff1f20a3
FB
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;
4a1a1707 2467 get_reloc_expr(relname, sizeof(relname), sym_name);
ff1f20a3
FB
2468 type = ELF32_R_TYPE(rel->r_info);
2469 addend = get32((uint32_t *)(text + rel->r_offset));
3442e896 2470 reloc_offset = rel->r_offset - start_offset;
ff1f20a3
FB
2471 switch(type) {
2472 case R_ARM_ABS32:
5fafdf24 2473 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
4a1a1707 2474 reloc_offset, relname, addend);
ff1f20a3
FB
2475 break;
2476 case R_ARM_PC24:
46152182
PB
2477 case R_ARM_JUMP24:
2478 case R_ARM_CALL:
5fafdf24 2479 fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
4a1a1707 2480 reloc_offset, addend, relname);
ff1f20a3
FB
2481 break;
2482 default:
2483 error("unsupported arm relocation (%d)", type);
2484 }
2485 }
2486 }
38e584a0
FB
2487 }
2488#elif defined(HOST_M68K)
2489 {
4a1a1707 2490 char relname[256];
38e584a0
FB
2491 int type;
2492 int addend;
3442e896 2493 int reloc_offset;
38e584a0
FB
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;
4a1a1707 2500 get_reloc_expr(relname, sizeof(relname), sym_name);
38e584a0
FB
2501 type = ELF32_R_TYPE(rel->r_info);
2502 addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
3442e896 2503 reloc_offset = rel->r_offset - start_offset;
38e584a0
FB
2504 switch(type) {
2505 case R_68K_32:
2506 fprintf(outfile, " /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
5fafdf24 2507 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
4a1a1707 2508 reloc_offset, relname, addend );
38e584a0
FB
2509 break;
2510 case R_68K_PC32:
2511 fprintf(outfile, " /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
5fafdf24 2512 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
4a1a1707 2513 reloc_offset, relname, reloc_offset, /*sym->st_value+*/ addend);
38e584a0
FB
2514 break;
2515 default:
2516 error("unsupported m68k relocation (%d)", type);
2517 }
2518 }
2519 }
ff1f20a3 2520 }
9617efe8 2521#elif defined(HOST_MIPS) || defined(HOST_MIPS64)
c4b89d18
TS
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) {
4a1a1707 2525 char relname[256];
c4b89d18
TS
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;
4a1a1707 2534 get_reloc_expr(relname, sizeof(relname), sym_name);
c4b89d18
TS
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) {
9617efe8
TS
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",
4a1a1707 2547 reloc_offset, addend, addend, relname, reloc_offset);
9617efe8 2548 break;
c4b89d18
TS
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",
4a1a1707 2557 reloc_offset, reloc_offset, relname);
c4b89d18
TS
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",
4a1a1707 2567 reloc_offset, reloc_offset, relname);
c4b89d18
TS
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",
4a1a1707 2577 reloc_offset, addend, addend, relname, reloc_offset);
c4b89d18
TS
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",
4a1a1707 2588 reloc_offset, reloc_offset, relname);
c4b89d18
TS
2589 break;
2590 default:
2591 error("unsupported MIPS relocation (%d)", type);
2592 }
2593 }
2594 }
2595 }
ce11fedc
FB
2596#else
2597#error unsupported CPU
2598#endif
dc99065b
FB
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);
367e86e8
FB
2611 }
2612 }
dc99065b
FB
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");
367e86e8 2620 }
367e86e8
FB
2621}
2622
67b915a5 2623int gen_file(FILE *outfile, int out_type)
367e86e8 2624{
67b915a5
FB
2625 int i;
2626 EXE_SYM *sym;
367e86e8 2627
d219f7e7 2628 if (out_type == OUT_INDEX_OP) {
a513fe19 2629 fprintf(outfile, "DEF(end, 0, 0)\n");
e477b8b8
FB
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");
dc99065b 2634 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
82eec0a1 2635 const char *name;
67b915a5 2636 name = get_sym_name(sym);
82eec0a1 2637 if (strstart(name, OP_PREFIX, NULL)) {
67b915a5 2638 gen_code(name, sym->st_value, sym->st_size, outfile, 2);
dc99065b
FB
2639 }
2640 }
d219f7e7
FB
2641 } else if (out_type == OUT_GEN_OP) {
2642 /* generate gen_xxx functions */
c4687878 2643 fprintf(outfile, "#include \"dyngen-op.h\"\n");
d219f7e7
FB
2644 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2645 const char *name;
67b915a5 2646 name = get_sym_name(sym);
d219f7e7 2647 if (strstart(name, OP_PREFIX, NULL)) {
82eec0a1 2648#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
67b915a5 2649 if (sym->st_shndx != text_shndx)
d219f7e7 2650 error("invalid section for opcode (0x%x)", sym->st_shndx);
82eec0a1 2651#endif
67b915a5 2652 gen_code(name, sym->st_value, sym->st_size, outfile, 0);
d219f7e7
FB
2653 }
2654 }
3b46e624 2655
dc99065b
FB
2656 } else {
2657 /* generate big code generation switch */
46152182
PB
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. */
2662fprintf(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 }
2676fprintf(outfile,
2677"};\n");
2678#endif
2679
dc99065b
FB
2680fprintf(outfile,
2681"int dyngen_code(uint8_t *gen_code_buf,\n"
d4e8164f 2682" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
c4687878 2683" const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n"
dc99065b
FB
2684"{\n"
2685" uint8_t *gen_code_ptr;\n"
2686" const uint16_t *opc_ptr;\n"
ff1f20a3
FB
2687" const uint32_t *opparam_ptr;\n");
2688
2689#ifdef HOST_ARM
46152182
PB
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:
3b46e624 2698
46152182
PB
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;
2707op3:
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 */
ff1f20a3
FB
2714fprintf(outfile,
2715" uint8_t *last_gen_code_ptr = gen_code_buf;\n"
2716" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
46152182
PB
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");
ff1f20a3 2720#endif
b8076a74
FB
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
ff1f20a3
FB
2778
2779fprintf(outfile,
2780"\n"
dc99065b
FB
2781" gen_code_ptr = gen_code_buf;\n"
2782" opc_ptr = opc_buf;\n"
ae228531
FB
2783" opparam_ptr = opparam_buf;\n");
2784
5fafdf24 2785 /* Generate prologue, if needed. */
ae228531
FB
2786
2787fprintf(outfile,
46152182
PB
2788" for(;;) {\n");
2789
2790#ifdef HOST_ARM
2791/* Generate constant pool if needed */
2792fprintf(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
2803fprintf(outfile,
2804" switch(*opc_ptr++) {\n");
367e86e8 2805
dc99065b
FB
2806 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2807 const char *name;
67b915a5 2808 name = get_sym_name(sym);
dc99065b 2809 if (strstart(name, OP_PREFIX, NULL)) {
367e86e8 2810#if 0
5fafdf24 2811 printf("%4d: %s pos=0x%08x len=%d\n",
dc99065b 2812 i, name, sym->st_value, sym->st_size);
367e86e8 2813#endif
82eec0a1 2814#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
67b915a5 2815 if (sym->st_shndx != text_shndx)
dc99065b 2816 error("invalid section for opcode (0x%x)", sym->st_shndx);
82eec0a1 2817#endif
67b915a5 2818 gen_code(name, sym->st_value, sym->st_size, outfile, 1);
dc99065b
FB
2819 }
2820 }
2821
2822fprintf(outfile,
8ef9a8ec
FB
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"
dc99065b
FB
2834" default:\n"
2835" goto the_end;\n"
ff1f20a3
FB
2836" }\n");
2837
ff1f20a3
FB
2838
2839fprintf(outfile,
dc99065b
FB
2840" }\n"
2841" the_end:\n"
2842);
b8076a74
FB
2843#ifdef HOST_IA64
2844 fprintf(outfile,
fd4a43e4
FB
2845 " {\n"
2846 " extern char code_gen_buffer[];\n"
2847 " ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
b8076a74
FB
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"
fd4a43e4 2850 "plt_target, plt_offset);\n }\n");
b8076a74 2851#endif
dc99065b 2852
5fafdf24 2853/* generate some code patching */
9621339d 2854#ifdef HOST_ARM
46152182
PB
2855fprintf(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");
9621339d 2859#endif
d219f7e7
FB
2860 /* flush instruction cache */
2861 fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
2862
dc99065b
FB
2863 fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
2864 fprintf(outfile, "}\n\n");
2865
367e86e8
FB
2866 }
2867
367e86e8
FB
2868 return 0;
2869}
2870
2871void usage(void)
2872{
2873 printf("dyngen (c) 2003 Fabrice Bellard\n"
dc99065b
FB
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"
d219f7e7 2877 "-g output gen_op_xx() functions\n"
dc99065b 2878 );
367e86e8
FB
2879 exit(1);
2880}
2881
2882int main(int argc, char **argv)
2883{
d219f7e7 2884 int c, out_type;
367e86e8
FB
2885 const char *filename, *outfilename;
2886 FILE *outfile;
2887
2888 outfilename = "out.c";
d219f7e7 2889 out_type = OUT_CODE;
367e86e8 2890 for(;;) {
d219f7e7 2891 c = getopt(argc, argv, "ho:cg");
367e86e8
FB
2892 if (c == -1)
2893 break;
2894 switch(c) {
2895 case 'h':
2896 usage();
2897 break;
2898 case 'o':
2899 outfilename = optarg;
2900 break;
dc99065b 2901 case 'c':
d219f7e7
FB
2902 out_type = OUT_INDEX_OP;
2903 break;
2904 case 'g':
2905 out_type = OUT_GEN_OP;
dc99065b 2906 break;
367e86e8
FB
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);
67b915a5
FB
2915
2916 load_object(filename);
2917 gen_file(outfile, out_type);
367e86e8
FB
2918 fclose(outfile);
2919 return 0;
2920}