VirtualBox

source: vbox/trunk/src/recompiler/dyngen.c@ 9663

Last change on this file since 9663 was 8722, checked in by vboxsync, 17 years ago

recompiler: fix for some special gcc versions

  • Property svn:eol-style set to native
File size: 100.6 KB
Line 
1/*
2 * Generic Dynamic compiler generator
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * The COFF object format support was extracted from Kazu's QEMU port
7 * to Win32.
8 *
9 * Mach-O Support by Matt Reda and Pierre d'Herbemont
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <stdarg.h>
29#include <inttypes.h>
30#include <unistd.h>
31#include <fcntl.h>
32
33#include "config-host.h"
34
35/* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross
36 compilation */
37#if defined(CONFIG_WIN32)
38#define CONFIG_FORMAT_COFF
39#elif defined(CONFIG_DARWIN)
40#define CONFIG_FORMAT_MACH
41#elif defined(CONFIG_OS2)
42#define CONFIG_FORMAT_AOUT
43#else
44#define CONFIG_FORMAT_ELF
45#endif
46
47#ifdef CONFIG_FORMAT_ELF
48
49/* elf format definitions. We use these macros to test the CPU to
50 allow cross compilation (this tool must be ran on the build
51 platform) */
52#if defined(HOST_I386)
53
54#define ELF_CLASS ELFCLASS32
55#define ELF_ARCH EM_386
56#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
57#undef ELF_USES_RELOCA
58
59#elif defined(HOST_X86_64)
60
61#define ELF_CLASS ELFCLASS64
62#define ELF_ARCH EM_X86_64
63#define elf_check_arch(x) ((x) == EM_X86_64)
64#define ELF_USES_RELOCA
65
66#elif defined(HOST_PPC)
67
68#define ELF_CLASS ELFCLASS32
69#define ELF_ARCH EM_PPC
70#define elf_check_arch(x) ((x) == EM_PPC)
71#define ELF_USES_RELOCA
72
73#elif defined(HOST_S390)
74
75#define ELF_CLASS ELFCLASS32
76#define ELF_ARCH EM_S390
77#define elf_check_arch(x) ((x) == EM_S390)
78#define ELF_USES_RELOCA
79
80#elif defined(HOST_ALPHA)
81
82#define ELF_CLASS ELFCLASS64
83#define ELF_ARCH EM_ALPHA
84#define elf_check_arch(x) ((x) == EM_ALPHA)
85#define ELF_USES_RELOCA
86
87#elif defined(HOST_IA64)
88
89#define ELF_CLASS ELFCLASS64
90#define ELF_ARCH EM_IA_64
91#define elf_check_arch(x) ((x) == EM_IA_64)
92#define ELF_USES_RELOCA
93
94#elif defined(HOST_SPARC)
95
96#define ELF_CLASS ELFCLASS32
97#define ELF_ARCH EM_SPARC
98#define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS)
99#define ELF_USES_RELOCA
100
101#elif defined(HOST_SPARC64)
102
103#define ELF_CLASS ELFCLASS64
104#define ELF_ARCH EM_SPARCV9
105#define elf_check_arch(x) ((x) == EM_SPARCV9)
106#define ELF_USES_RELOCA
107
108#elif defined(HOST_ARM)
109
110#define ELF_CLASS ELFCLASS32
111#define ELF_ARCH EM_ARM
112#define elf_check_arch(x) ((x) == EM_ARM)
113#define ELF_USES_RELOC
114
115#elif defined(HOST_M68K)
116
117#define ELF_CLASS ELFCLASS32
118#define ELF_ARCH EM_68K
119#define elf_check_arch(x) ((x) == EM_68K)
120#define ELF_USES_RELOCA
121
122#else
123#error unsupported CPU - please update the code
124#endif
125
126#include "elf.h"
127
128#if ELF_CLASS == ELFCLASS32
129typedef int32_t host_long;
130typedef uint32_t host_ulong;
131#define swabls(x) swab32s(x)
132#define swablss(x) swab32ss(x)
133#else
134typedef int64_t host_long;
135typedef uint64_t host_ulong;
136#define swabls(x) swab64s(x)
137#define swablss(x) swab64ss(x)
138#endif
139
140#ifdef ELF_USES_RELOCA
141#define SHT_RELOC SHT_RELA
142#else
143#define SHT_RELOC SHT_REL
144#endif
145
146#define EXE_RELOC ELF_RELOC
147#define EXE_SYM ElfW(Sym)
148
149#endif /* CONFIG_FORMAT_ELF */
150
151#ifdef CONFIG_FORMAT_COFF
152
153#include "a.out.h"
154
155typedef int32_t host_long;
156typedef uint32_t host_ulong;
157
158#define FILENAMELEN 256
159
160typedef struct coff_sym {
161 struct external_syment *st_syment;
162 char st_name[FILENAMELEN];
163 uint32_t st_value;
164 int st_size;
165 uint8_t st_type;
166 uint8_t st_shndx;
167} coff_Sym;
168
169typedef struct coff_rel {
170 struct external_reloc *r_reloc;
171 int r_offset;
172 uint8_t r_type;
173} coff_Rel;
174
175#define EXE_RELOC struct coff_rel
176#define EXE_SYM struct coff_sym
177
178#endif /* CONFIG_FORMAT_COFF */
179
180#ifdef CONFIG_FORMAT_MACH
181
182#include <mach-o/loader.h>
183#include <mach-o/nlist.h>
184#include <mach-o/reloc.h>
185#if !defined(HOST_I386)
186#include <mach-o/ppc/reloc.h>
187#endif
188
189# define check_mach_header(x) (x.magic == MH_MAGIC)
190typedef int32_t host_long;
191typedef uint32_t host_ulong;
192
193struct nlist_extended
194{
195 union {
196 char *n_name;
197 long n_strx;
198 } n_un;
199 unsigned char n_type;
200 unsigned char n_sect;
201 short st_desc;
202 unsigned long st_value;
203 unsigned long st_size;
204};
205
206#define EXE_RELOC struct relocation_info
207#define EXE_SYM struct nlist_extended
208#if defined(HOST_I386)
209# define r_offset r_address
210#endif
211
212#endif /* CONFIG_FORMAT_MACH */
213
214#ifdef CONFIG_FORMAT_AOUT
215
216#include "a_out.h"
217
218typedef int32_t host_long;
219typedef uint32_t host_ulong;
220
221struct nlist_extended
222{
223 union {
224 char *n_name;
225 struct nlist *n_next;
226 long n_strx;
227 } n_un;
228 unsigned char n_type;
229 char n_other;
230 short n_desc;
231 unsigned long st_value; /* n_value -> st_value */
232 unsigned long st_size; /* added */
233};
234
235#define EXE_RELOC struct relocation_info
236#define EXE_SYM struct nlist_extended
237#define r_offset r_address
238
239#endif /* CONFIG_FORMAT_AOUT */
240
241#include "bswap.h"
242
243enum {
244 OUT_GEN_OP,
245 OUT_CODE,
246 OUT_INDEX_OP
247};
248
249/* all dynamically generated functions begin with this code */
250#define OP_PREFIX "op_"
251
252int do_swap;
253
254void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
255{
256 va_list ap;
257 va_start(ap, fmt);
258 fprintf(stderr, "dyngen: ");
259 vfprintf(stderr, fmt, ap);
260 fprintf(stderr, "\n");
261 va_end(ap);
262 exit(1);
263}
264
265void *load_data(int fd, long offset, unsigned int size)
266{
267 char *data;
268
269 data = malloc(size);
270 if (!data)
271 return NULL;
272 lseek(fd, offset, SEEK_SET);
273 if (read(fd, data, size) != size) {
274 free(data);
275 return NULL;
276 }
277 return data;
278}
279
280int strstart(const char *str, const char *val, const char **ptr)
281{
282 const char *p, *q;
283 p = str;
284 q = val;
285 while (*q != '\0') {
286 if (*p != *q)
287 return 0;
288 p++;
289 q++;
290 }
291 if (ptr)
292 *ptr = p;
293 return 1;
294}
295
296void pstrcpy(char *buf, int buf_size, const char *str)
297{
298 int c;
299 char *q = buf;
300
301 if (buf_size <= 0)
302 return;
303
304 for(;;) {
305 c = *str++;
306 if (c == 0 || q >= buf + buf_size - 1)
307 break;
308 *q++ = c;
309 }
310 *q = '\0';
311}
312
313void swab16s(uint16_t *p)
314{
315 *p = bswap16(*p);
316}
317
318void swab32s(uint32_t *p)
319{
320 *p = bswap32(*p);
321}
322
323void swab32ss(int32_t *p)
324{
325 *p = bswap32(*p);
326}
327
328void swab64s(uint64_t *p)
329{
330 *p = bswap64(*p);
331}
332
333void swab64ss(int64_t *p)
334{
335 *p = bswap64(*p);
336}
337
338uint16_t get16(uint16_t *p)
339{
340 uint16_t val;
341 val = *p;
342 if (do_swap)
343 val = bswap16(val);
344 return val;
345}
346
347uint32_t get32(uint32_t *p)
348{
349 uint32_t val;
350 val = *p;
351 if (do_swap)
352 val = bswap32(val);
353 return val;
354}
355
356void put16(uint16_t *p, uint16_t val)
357{
358 if (do_swap)
359 val = bswap16(val);
360 *p = val;
361}
362
363void put32(uint32_t *p, uint32_t val)
364{
365 if (do_swap)
366 val = bswap32(val);
367 *p = val;
368}
369
370/* executable information */
371EXE_SYM *symtab;
372int nb_syms;
373int text_shndx;
374uint8_t *text;
375EXE_RELOC *relocs;
376int nb_relocs;
377
378#ifdef CONFIG_FORMAT_ELF
379
380/* ELF file info */
381struct elf_shdr *shdr;
382uint8_t **sdata;
383struct elfhdr ehdr;
384char *strtab;
385
386int elf_must_swap(struct elfhdr *h)
387{
388 union {
389 uint32_t i;
390 uint8_t b[4];
391 } swaptest;
392
393 swaptest.i = 1;
394 return (h->e_ident[EI_DATA] == ELFDATA2MSB) !=
395 (swaptest.b[0] == 0);
396}
397
398void elf_swap_ehdr(struct elfhdr *h)
399{
400 swab16s(&h->e_type); /* Object file type */
401 swab16s(&h-> e_machine); /* Architecture */
402 swab32s(&h-> e_version); /* Object file version */
403 swabls(&h-> e_entry); /* Entry point virtual address */
404 swabls(&h-> e_phoff); /* Program header table file offset */
405 swabls(&h-> e_shoff); /* Section header table file offset */
406 swab32s(&h-> e_flags); /* Processor-specific flags */
407 swab16s(&h-> e_ehsize); /* ELF header size in bytes */
408 swab16s(&h-> e_phentsize); /* Program header table entry size */
409 swab16s(&h-> e_phnum); /* Program header table entry count */
410 swab16s(&h-> e_shentsize); /* Section header table entry size */
411 swab16s(&h-> e_shnum); /* Section header table entry count */
412 swab16s(&h-> e_shstrndx); /* Section header string table index */
413}
414
415void elf_swap_shdr(struct elf_shdr *h)
416{
417 swab32s(&h-> sh_name); /* Section name (string tbl index) */
418 swab32s(&h-> sh_type); /* Section type */
419 swabls(&h-> sh_flags); /* Section flags */
420 swabls(&h-> sh_addr); /* Section virtual addr at execution */
421 swabls(&h-> sh_offset); /* Section file offset */
422 swabls(&h-> sh_size); /* Section size in bytes */
423 swab32s(&h-> sh_link); /* Link to another section */
424 swab32s(&h-> sh_info); /* Additional section information */
425 swabls(&h-> sh_addralign); /* Section alignment */
426 swabls(&h-> sh_entsize); /* Entry size if section holds table */
427}
428
429void elf_swap_phdr(struct elf_phdr *h)
430{
431 swab32s(&h->p_type); /* Segment type */
432 swabls(&h->p_offset); /* Segment file offset */
433 swabls(&h->p_vaddr); /* Segment virtual address */
434 swabls(&h->p_paddr); /* Segment physical address */
435 swabls(&h->p_filesz); /* Segment size in file */
436 swabls(&h->p_memsz); /* Segment size in memory */
437 swab32s(&h->p_flags); /* Segment flags */
438 swabls(&h->p_align); /* Segment alignment */
439}
440
441void elf_swap_rel(ELF_RELOC *rel)
442{
443 swabls(&rel->r_offset);
444 swabls(&rel->r_info);
445#ifdef ELF_USES_RELOCA
446 swablss(&rel->r_addend);
447#endif
448}
449
450struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr,
451 const char *name)
452{
453 int i;
454 const char *shname;
455 struct elf_shdr *sec;
456
457 for(i = 0; i < shnum; i++) {
458 sec = &shdr[i];
459 if (!sec->sh_name)
460 continue;
461 shname = shstr + sec->sh_name;
462 if (!strcmp(shname, name))
463 return sec;
464 }
465 return NULL;
466}
467
468int find_reloc(int sh_index)
469{
470 struct elf_shdr *sec;
471 int i;
472
473 for(i = 0; i < ehdr.e_shnum; i++) {
474 sec = &shdr[i];
475 if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index)
476 return i;
477 }
478 return 0;
479}
480
481static host_ulong get_rel_offset(EXE_RELOC *rel)
482{
483 return rel->r_offset;
484}
485
486static char *get_rel_sym_name(EXE_RELOC *rel)
487{
488 return strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
489}
490
491static char *get_sym_name(EXE_SYM *sym)
492{
493 return strtab + sym->st_name;
494}
495
496/* load an elf object file */
497int load_object(const char *filename)
498{
499 int fd;
500 struct elf_shdr *sec, *symtab_sec, *strtab_sec, *text_sec;
501 int i, j;
502 ElfW(Sym) *sym;
503 char *shstr;
504 ELF_RELOC *rel;
505
506 fd = open(filename, O_RDONLY
507#ifdef O_BINARY
508 | O_BINARY
509#endif
510 );
511 if (fd < 0)
512 error("can't open file '%s'", filename);
513
514 /* Read ELF header. */
515 if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
516 error("unable to read file header");
517
518 /* Check ELF identification. */
519 if (ehdr.e_ident[EI_MAG0] != ELFMAG0
520 || ehdr.e_ident[EI_MAG1] != ELFMAG1
521 || ehdr.e_ident[EI_MAG2] != ELFMAG2
522 || ehdr.e_ident[EI_MAG3] != ELFMAG3
523 || ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
524 error("bad ELF header");
525 }
526
527 do_swap = elf_must_swap(&ehdr);
528 if (do_swap)
529 elf_swap_ehdr(&ehdr);
530 if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
531 error("Unsupported ELF class (%#x)", ehdr.e_ident[EI_CLASS]);
532 if (ehdr.e_type != ET_REL)
533 error("ELF object file expected");
534 if (ehdr.e_version != EV_CURRENT)
535 error("Invalid ELF version");
536 if (!elf_check_arch(ehdr.e_machine))
537 error("Unsupported CPU (e_machine=%d)", ehdr.e_machine);
538
539 /* read section headers */
540 shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(struct elf_shdr));
541 if (do_swap) {
542 for(i = 0; i < ehdr.e_shnum; i++) {
543 elf_swap_shdr(&shdr[i]);
544 }
545 }
546
547 /* read all section data */
548 sdata = malloc(sizeof(void *) * ehdr.e_shnum);
549 memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
550
551 for(i = 0;i < ehdr.e_shnum; i++) {
552 sec = &shdr[i];
553 if (sec->sh_type != SHT_NOBITS)
554 sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size);
555 }
556
557 sec = &shdr[ehdr.e_shstrndx];
558 shstr = (char *)sdata[ehdr.e_shstrndx];
559
560 /* swap relocations */
561 for(i = 0; i < ehdr.e_shnum; i++) {
562 sec = &shdr[i];
563 if (sec->sh_type == SHT_RELOC) {
564 nb_relocs = sec->sh_size / sec->sh_entsize;
565 if (do_swap) {
566 for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++)
567 elf_swap_rel(rel);
568 }
569 }
570 }
571 /* text section */
572
573 text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
574 if (!text_sec)
575 error("could not find .text section");
576 text_shndx = text_sec - shdr;
577 text = sdata[text_shndx];
578
579 /* find text relocations, if any */
580 relocs = NULL;
581 nb_relocs = 0;
582 i = find_reloc(text_shndx);
583 if (i != 0) {
584 relocs = (ELF_RELOC *)sdata[i];
585 nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize;
586 }
587
588 symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
589 if (!symtab_sec)
590 error("could not find .symtab section");
591 strtab_sec = &shdr[symtab_sec->sh_link];
592
593 symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
594 strtab = (char *)sdata[symtab_sec->sh_link];
595
596 nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
597 if (do_swap) {
598 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
599 swab32s(&sym->st_name);
600 swabls(&sym->st_value);
601 swabls(&sym->st_size);
602 swab16s(&sym->st_shndx);
603 }
604 }
605 close(fd);
606 return 0;
607}
608
609#endif /* CONFIG_FORMAT_ELF */
610
611#ifdef CONFIG_FORMAT_COFF
612
613/* COFF file info */
614struct external_scnhdr *shdr;
615uint8_t **sdata;
616struct external_filehdr fhdr;
617struct external_syment *coff_symtab;
618char *strtab;
619int coff_text_shndx, coff_data_shndx;
620
621int data_shndx;
622
623#define STRTAB_SIZE 4
624
625#define DIR32 0x06
626#define DISP32 0x14
627
628#define T_FUNCTION 0x20
629#define C_EXTERNAL 2
630
631void sym_ent_name(struct external_syment *ext_sym, EXE_SYM *sym)
632{
633 char *q;
634 int c, i, len;
635
636 if (ext_sym->e.e.e_zeroes != 0) {
637 q = sym->st_name;
638 for(i = 0; i < 8; i++) {
639 c = ext_sym->e.e_name[i];
640 if (c == '\0')
641 break;
642 *q++ = c;
643 }
644 *q = '\0';
645 } else {
646 pstrcpy(sym->st_name, sizeof(sym->st_name), strtab + ext_sym->e.e.e_offset);
647 }
648
649 /* now convert the name to a C name (suppress the leading '_') */
650 if (sym->st_name[0] == '_') {
651 len = strlen(sym->st_name);
652 memmove(sym->st_name, sym->st_name + 1, len - 1);
653 sym->st_name[len - 1] = '\0';
654 }
655}
656
657char *name_for_dotdata(struct coff_rel *rel)
658{
659 int i;
660 struct coff_sym *sym;
661 uint32_t text_data;
662
663 text_data = *(uint32_t *)(text + rel->r_offset);
664
665 for (i = 0, sym = symtab; i < nb_syms; i++, sym++) {
666 if (sym->st_syment->e_scnum == data_shndx &&
667 text_data >= sym->st_value &&
668 text_data < sym->st_value + sym->st_size) {
669
670 return sym->st_name;
671
672 }
673 }
674 return NULL;
675}
676
677static char *get_sym_name(EXE_SYM *sym)
678{
679 return sym->st_name;
680}
681
682static char *get_rel_sym_name(EXE_RELOC *rel)
683{
684 char *name;
685 name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
686 if (!strcmp(name, ".data"))
687 name = name_for_dotdata(rel);
688 if (name[0] == '.')
689 return NULL;
690 return name;
691}
692
693static host_ulong get_rel_offset(EXE_RELOC *rel)
694{
695 return rel->r_offset;
696}
697
698struct external_scnhdr *find_coff_section(struct external_scnhdr *shdr, int shnum, const char *name)
699{
700 int i;
701 const char *shname;
702 struct external_scnhdr *sec;
703
704 for(i = 0; i < shnum; i++) {
705 sec = &shdr[i];
706 if (!sec->s_name)
707 continue;
708 shname = sec->s_name;
709 if (!strcmp(shname, name))
710 return sec;
711 }
712 return NULL;
713}
714
715/* load a coff object file */
716int load_object(const char *filename)
717{
718 int fd;
719 struct external_scnhdr *sec, *text_sec, *data_sec;
720 int i;
721 struct external_syment *ext_sym;
722 struct external_reloc *coff_relocs;
723 struct external_reloc *ext_rel;
724 uint32_t *n_strtab;
725 EXE_SYM *sym;
726 EXE_RELOC *rel;
727
728 fd = open(filename, O_RDONLY
729#ifdef O_BINARY
730 | O_BINARY
731#endif
732 );
733 if (fd < 0)
734 error("can't open file '%s'", filename);
735
736 /* Read COFF header. */
737 if (read(fd, &fhdr, sizeof (fhdr)) != sizeof (fhdr))
738 error("unable to read file header");
739
740 /* Check COFF identification. */
741 if (fhdr.f_magic != I386MAGIC) {
742 error("bad COFF header");
743 }
744 do_swap = 0;
745
746 /* read section headers */
747 shdr = load_data(fd, sizeof(struct external_filehdr) + fhdr.f_opthdr, fhdr.f_nscns * sizeof(struct external_scnhdr));
748
749 /* read all section data */
750 sdata = malloc(sizeof(void *) * fhdr.f_nscns);
751 memset(sdata, 0, sizeof(void *) * fhdr.f_nscns);
752
753 const char *p;
754 for(i = 0;i < fhdr.f_nscns; i++) {
755 sec = &shdr[i];
756 if (!strstart(sec->s_name, ".bss", &p))
757 sdata[i] = load_data(fd, sec->s_scnptr, sec->s_size);
758 }
759
760
761 /* text section */
762 text_sec = find_coff_section(shdr, fhdr.f_nscns, ".text");
763 if (!text_sec)
764 error("could not find .text section");
765 coff_text_shndx = text_sec - shdr;
766 text = sdata[coff_text_shndx];
767
768 /* data section */
769 data_sec = find_coff_section(shdr, fhdr.f_nscns, ".data");
770 if (!data_sec)
771 error("could not find .data section");
772 coff_data_shndx = data_sec - shdr;
773
774 coff_symtab = load_data(fd, fhdr.f_symptr, fhdr.f_nsyms*SYMESZ);
775 for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
776 for(i=0;i<8;i++)
777 printf(" %02x", ((uint8_t *)ext_sym->e.e_name)[i]);
778 printf("\n");
779 }
780
781
782 n_strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), STRTAB_SIZE);
783 strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab);
784
785 nb_syms = fhdr.f_nsyms;
786
787 for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
788 if (strstart(ext_sym->e.e_name, ".text", NULL))
789 text_shndx = ext_sym->e_scnum;
790 if (strstart(ext_sym->e.e_name, ".data", NULL))
791 data_shndx = ext_sym->e_scnum;
792 }
793
794 /* set coff symbol */
795 symtab = malloc(sizeof(struct coff_sym) * nb_syms);
796
797 int aux_size, j;
798 for (i = 0, ext_sym = coff_symtab, sym = symtab; i < nb_syms; i++, ext_sym++, sym++) {
799 memset(sym, 0, sizeof(*sym));
800 sym->st_syment = ext_sym;
801 sym_ent_name(ext_sym, sym);
802 sym->st_value = ext_sym->e_value;
803
804 aux_size = *(int8_t *)ext_sym->e_numaux;
805 if (ext_sym->e_scnum == text_shndx && ext_sym->e_type == T_FUNCTION) {
806 for (j = aux_size + 1; j < nb_syms - i; j++) {
807 if ((ext_sym + j)->e_scnum == text_shndx &&
808 (ext_sym + j)->e_type == T_FUNCTION ){
809 sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
810 break;
811 } else if (j == nb_syms - i - 1) {
812 sec = &shdr[coff_text_shndx];
813 sym->st_size = sec->s_size - ext_sym->e_value;
814 break;
815 }
816 }
817 } else if (ext_sym->e_scnum == data_shndx && *(uint8_t *)ext_sym->e_sclass == C_EXTERNAL) {
818 for (j = aux_size + 1; j < nb_syms - i; j++) {
819 if ((ext_sym + j)->e_scnum == data_shndx) {
820 sym->st_size = (ext_sym + j)->e_value - ext_sym->e_value;
821 break;
822 } else if (j == nb_syms - i - 1) {
823 sec = &shdr[coff_data_shndx];
824 sym->st_size = sec->s_size - ext_sym->e_value;
825 break;
826 }
827 }
828 } else {
829 sym->st_size = 0;
830 }
831
832 sym->st_type = ext_sym->e_type;
833 sym->st_shndx = ext_sym->e_scnum;
834 }
835
836
837 /* find text relocations, if any */
838 sec = &shdr[coff_text_shndx];
839 coff_relocs = load_data(fd, sec->s_relptr, sec->s_nreloc*RELSZ);
840 nb_relocs = sec->s_nreloc;
841
842 /* set coff relocation */
843 relocs = malloc(sizeof(struct coff_rel) * nb_relocs);
844 for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs;
845 i++, ext_rel++, rel++) {
846 memset(rel, 0, sizeof(*rel));
847 rel->r_reloc = ext_rel;
848 rel->r_offset = *(uint32_t *)ext_rel->r_vaddr;
849 rel->r_type = *(uint16_t *)ext_rel->r_type;
850 }
851 return 0;
852}
853
854#endif /* CONFIG_FORMAT_COFF */
855
856#ifdef CONFIG_FORMAT_MACH
857
858/* File Header */
859struct mach_header mach_hdr;
860
861/* commands */
862struct segment_command *segment = 0;
863struct dysymtab_command *dysymtabcmd = 0;
864struct symtab_command *symtabcmd = 0;
865
866/* section */
867struct section *section_hdr;
868struct section *text_sec_hdr;
869uint8_t **sdata;
870
871/* relocs */
872struct relocation_info *relocs;
873
874/* symbols */
875EXE_SYM *symtab;
876struct nlist *symtab_std;
877char *strtab;
878
879/* indirect symbols */
880uint32_t *tocdylib;
881
882/* Utility functions */
883
884static inline char *find_str_by_index(int index)
885{
886 return strtab+index;
887}
888
889/* Used by dyngen common code */
890static char *get_sym_name(EXE_SYM *sym)
891{
892 char *name = find_str_by_index(sym->n_un.n_strx);
893
894 if ( sym->n_type & N_STAB ) /* Debug symbols are ignored */
895 return "debug";
896
897 if(!name)
898 return name;
899 if(name[0]=='_')
900 return name + 1;
901 else
902 return name;
903}
904
905/* find a section index given its segname, sectname */
906static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname,
907 const char *sectname)
908{
909 int i;
910 struct section *sec = section_hdr;
911
912 for(i = 0; i < shnum; i++, sec++) {
913 if (!sec->segname || !sec->sectname)
914 continue;
915 if (!strcmp(sec->sectname, sectname) && !strcmp(sec->segname, segname))
916 return i;
917 }
918 return -1;
919}
920
921/* find a section header given its segname, sectname */
922struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname,
923 const char *sectname)
924{
925 int index = find_mach_sec_index(section_hdr, shnum, segname, sectname);
926 if(index == -1)
927 return NULL;
928 return section_hdr+index;
929}
930
931
932#if defined(HOST_PPC)
933static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned int *value)
934{
935 struct scattered_relocation_info * scarel;
936
937 if(R_SCATTERED & rel->r_address) {
938 scarel = (struct scattered_relocation_info*)rel;
939 if(scarel->r_type != PPC_RELOC_PAIR)
940 error("fetch_next_pair_value: looking for a pair which was not found (1)");
941 *value = scarel->r_value;
942 } else {
943 if(rel->r_type != PPC_RELOC_PAIR)
944 error("fetch_next_pair_value: looking for a pair which was not found (2)");
945 *value = rel->r_address;
946 }
947}
948#endif
949
950/* find a sym name given its value, in a section number */
951static const char * find_sym_with_value_and_sec_number( int value, int sectnum, int * offset )
952{
953 int i, ret = -1;
954
955 for( i = 0 ; i < nb_syms; i++ )
956 {
957 if( !(symtab[i].n_type & N_STAB) && (symtab[i].n_type & N_SECT) &&
958 (symtab[i].n_sect == sectnum) && (symtab[i].st_value <= value) )
959 {
960 if( (ret<0) || (symtab[i].st_value >= symtab[ret].st_value) )
961 ret = i;
962 }
963 }
964 if( ret < 0 ) {
965 *offset = 0;
966 return 0;
967 } else {
968 *offset = value - symtab[ret].st_value;
969 return get_sym_name(&symtab[ret]);
970 }
971}
972
973/*
974 * Find symbol name given a (virtual) address, and a section which is of type
975 * S_NON_LAZY_SYMBOL_POINTERS or S_LAZY_SYMBOL_POINTERS or S_SYMBOL_STUBS
976 */
977static const char * find_reloc_name_in_sec_ptr(int address, struct section * sec_hdr)
978{
979 unsigned int tocindex, symindex, size;
980 const char *name = 0;
981
982 /* Sanity check */
983 if(!( address >= sec_hdr->addr && address < (sec_hdr->addr + sec_hdr->size) ) )
984 return (char*)0;
985
986 if( sec_hdr->flags & S_SYMBOL_STUBS ){
987 size = sec_hdr->reserved2;
988 if(size == 0)
989 error("size = 0");
990
991 }
992 else if( sec_hdr->flags & S_LAZY_SYMBOL_POINTERS ||
993 sec_hdr->flags & S_NON_LAZY_SYMBOL_POINTERS)
994 size = sizeof(unsigned long);
995 else
996 return 0;
997
998 /* Compute our index in toc */
999 tocindex = (address - sec_hdr->addr)/size;
1000 symindex = tocdylib[sec_hdr->reserved1 + tocindex];
1001
1002 name = get_sym_name(&symtab[symindex]);
1003
1004 return name;
1005}
1006
1007static const char * find_reloc_name_given_its_address(int address)
1008{
1009 unsigned int i;
1010 for(i = 0; i < segment->nsects ; i++)
1011 {
1012 const char * name = find_reloc_name_in_sec_ptr(address, &section_hdr[i]);
1013 if((long)name != -1)
1014 return name;
1015 }
1016 return 0;
1017}
1018
1019static const char * get_reloc_name(EXE_RELOC * rel, int * sslide)
1020{
1021 char * name = 0;
1022 struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
1023 int sectnum = rel->r_symbolnum;
1024 int sectoffset;
1025 int other_half=0;
1026
1027 /* init the slide value */
1028 *sslide = 0;
1029
1030 if(R_SCATTERED & rel->r_address)
1031 return (char *)find_reloc_name_given_its_address(sca_rel->r_value);
1032
1033 if(rel->r_extern)
1034 {
1035 /* ignore debug sym */
1036 if ( symtab[rel->r_symbolnum].n_type & N_STAB )
1037 return 0;
1038 return get_sym_name(&symtab[rel->r_symbolnum]);
1039 }
1040
1041#if defined(HOST_I386)
1042 /* ignore internal pc relative fixups where both ends are in the text section. */
1043 if (rel->r_pcrel && !rel->r_extern && rel->r_symbolnum == 1 /* ASSUMES text */)
1044 return NULL;
1045#endif
1046
1047 /* Intruction contains an offset to the symbols pointed to, in the rel->r_symbolnum section */
1048 sectoffset = *(uint32_t *)(text + rel->r_address) & 0xffff;
1049
1050 if(sectnum==0xffffff)
1051 return 0;
1052
1053 /* Sanity Check */
1054 if(sectnum > segment->nsects)
1055 error("sectnum > segment->nsects");
1056
1057#if defined(HOST_PPC)
1058 switch(rel->r_type)
1059 {
1060 case PPC_RELOC_LO16: fetch_next_pair_value(rel+1, &other_half); sectoffset |= (other_half << 16);
1061 break;
1062 case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) | (uint16_t)(other_half & 0xffff);
1063 break;
1064 case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) + (int16_t)(other_half & 0xffff);
1065 break;
1066 case PPC_RELOC_BR24:
1067 sectoffset = ( *(uint32_t *)(text + rel->r_address) & 0x03fffffc );
1068 if (sectoffset & 0x02000000) sectoffset |= 0xfc000000;
1069 break;
1070 default:
1071 error("switch(rel->type) not found");
1072 }
1073#elif defined(HOST_I386)
1074 /* The intruction contains the addend. */
1075 sectoffset = *(uint32_t *)(text + rel->r_address);
1076#else
1077#error unsupported mach-o host
1078#endif
1079
1080 if(rel->r_pcrel)
1081 sectoffset += rel->r_address;
1082
1083#if defined(HOST_PPC)
1084 if (rel->r_type == PPC_RELOC_BR24)
1085 name = (char *)find_reloc_name_in_sec_ptr((int)sectoffset, &section_hdr[sectnum-1]);
1086#endif
1087
1088 /* search it in the full symbol list, if not found */
1089 if(!name)
1090 name = (char *)find_sym_with_value_and_sec_number(sectoffset, sectnum, sslide);
1091
1092 return name;
1093}
1094
1095#if defined(HOST_I386)
1096static const char *get_rel_sym_name_and_addend(EXE_RELOC *rel, int *addend)
1097{
1098 const char *name = NULL;
1099
1100 if (R_SCATTERED & rel->r_address) {
1101 unsigned int i;
1102 struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
1103 if (sca_rel->r_length != 2 || rel->r_pcrel) {
1104 error("Fully implement R_SCATTERED! r_address=%#x r_type=%#x r_length=%d r_pcrel=%d r_value=%#x\n",
1105 (int)sca_rel->r_address, sca_rel->r_type, sca_rel->r_length, sca_rel->r_pcrel, sca_rel->r_value);
1106 }
1107
1108 /* this seems to be the way to calc the addend. */
1109 *addend = *(int32_t *)(text + sca_rel->r_address) - sca_rel->r_value;
1110
1111 /* todo: do we need to ignore internal relocations? */
1112#if 0
1113 if (sca_rel->r_pcrel ...)
1114 return NULL;
1115#endif
1116
1117 /* find_reloc_name_given_its_address doesn't do the right thing here, so
1118 we locate the section and use find_sym_with_value_and_sec_number */
1119 for (i = 0; i < segment->nsects ; i++) {
1120 if ((uintptr_t)sca_rel->r_value - section_hdr[i].addr < section_hdr[i].size) {
1121 int off = 0;
1122 name = find_sym_with_value_and_sec_number(sca_rel->r_value, i + 1, &off);
1123 if (name) {
1124 *addend += off;
1125 break;
1126 }
1127 }
1128 }
1129 if (!name)
1130 error("Fully implement R_SCATTERED! r_address=%#x r_type=%#x r_length=%d r_pcrel=%d r_value=%#x\n",
1131 (int)sca_rel->r_address, sca_rel->r_type, sca_rel->r_length, sca_rel->r_pcrel, sca_rel->r_value);
1132 }
1133 else
1134 {
1135 /* ignore debug syms (paranoia). */
1136 if (symtab[rel->r_symbolnum].n_type & N_STAB)
1137 return NULL;
1138
1139 /* ignore internal pc relative fixups where both ends are in the text section. */
1140 if (rel->r_pcrel && !rel->r_extern && rel->r_symbolnum == 1 /* ASSUMES text */)
1141 return NULL;
1142
1143 /* get the addend, it is in the instruction stream. */
1144 *addend = *(int32_t *)(text + rel->r_address);
1145 if (rel->r_pcrel)
1146 *addend += rel->r_address;
1147
1148 /* external fixups are easy. */
1149 if (rel->r_extern)
1150 {
1151 if (rel->r_symbolnum >= nb_syms)
1152 error("rel->r_symbolnum (%d) >= nb_syms (%d)", rel->r_symbolnum, nb_syms);
1153 name = get_sym_name(&symtab[rel->r_symbolnum]);
1154 }
1155 else
1156 {
1157 /* sanity checks. */
1158 if (rel->r_symbolnum == 0xffffff)
1159 return NULL;
1160 if (rel->r_symbolnum > segment->nsects)
1161 error("sectnum (%d) > segment->nsects (%d)", rel->r_symbolnum, segment->nsects);
1162 if (rel->r_pcrel)
1163 error("internal pcrel fixups not implemented");
1164
1165 /* search for the symbol. */
1166 name = find_sym_with_value_and_sec_number(*addend, rel->r_symbolnum, addend);
1167 }
1168 }
1169 return name;
1170}
1171#endif /* HOST_I386 */
1172
1173/* Used by dyngen common code */
1174static const char * get_rel_sym_name(EXE_RELOC * rel)
1175{
1176 int sslide;
1177#if defined(HOST_I386)
1178 return get_rel_sym_name_and_addend(rel, &sslide);
1179#else
1180 return get_reloc_name( rel, &sslide);
1181#endif
1182}
1183
1184/* Used by dyngen common code */
1185static host_ulong get_rel_offset(EXE_RELOC *rel)
1186{
1187 struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
1188 if(R_SCATTERED & rel->r_address)
1189 return sca_rel->r_address;
1190 else
1191 return rel->r_address;
1192}
1193
1194/* load a mach-o object file */
1195int load_object(const char *filename)
1196{
1197 int fd;
1198 unsigned int offset_to_segment = 0;
1199 unsigned int offset_to_dysymtab = 0;
1200 unsigned int offset_to_symtab = 0;
1201 struct load_command lc;
1202 unsigned int i, j;
1203 EXE_SYM *sym;
1204 struct nlist *syment;
1205
1206 fd = open(filename, O_RDONLY
1207#ifdef O_BINARY
1208 | O_BINARY
1209#endif
1210 );
1211 if (fd < 0)
1212 error("can't open file '%s'", filename);
1213
1214 /* Read Mach header. */
1215 if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
1216 error("unable to read file header");
1217
1218 /* Check Mach identification. */
1219 if (!check_mach_header(mach_hdr)) {
1220 error("bad Mach header");
1221 }
1222
1223#if defined(HOST_PPC)
1224 if (mach_hdr.cputype != CPU_TYPE_POWERPC)
1225#elif defined(HOST_I386)
1226 if (mach_hdr.cputype != CPU_TYPE_X86)
1227#else
1228#error unsupported host
1229#endif
1230 error("Unsupported CPU");
1231
1232 if (mach_hdr.filetype != MH_OBJECT)
1233 error("Unsupported Mach Object");
1234
1235 /* read segment headers */
1236 for(i=0, j=sizeof(mach_hdr); i<mach_hdr.ncmds ; i++)
1237 {
1238 if(read(fd, &lc, sizeof(struct load_command)) != sizeof(struct load_command))
1239 error("unable to read load_command");
1240 if(lc.cmd == LC_SEGMENT)
1241 {
1242 offset_to_segment = j;
1243 lseek(fd, offset_to_segment, SEEK_SET);
1244 segment = malloc(sizeof(struct segment_command));
1245 if(read(fd, segment, sizeof(struct segment_command)) != sizeof(struct segment_command))
1246 error("unable to read LC_SEGMENT");
1247 }
1248 if(lc.cmd == LC_DYSYMTAB)
1249 {
1250 offset_to_dysymtab = j;
1251 lseek(fd, offset_to_dysymtab, SEEK_SET);
1252 dysymtabcmd = malloc(sizeof(struct dysymtab_command));
1253 if(read(fd, dysymtabcmd, sizeof(struct dysymtab_command)) != sizeof(struct dysymtab_command))
1254 error("unable to read LC_DYSYMTAB");
1255 }
1256 if(lc.cmd == LC_SYMTAB)
1257 {
1258 offset_to_symtab = j;
1259 lseek(fd, offset_to_symtab, SEEK_SET);
1260 symtabcmd = malloc(sizeof(struct symtab_command));
1261 if(read(fd, symtabcmd, sizeof(struct symtab_command)) != sizeof(struct symtab_command))
1262 error("unable to read LC_SYMTAB");
1263 }
1264 j+=lc.cmdsize;
1265
1266 lseek(fd, j, SEEK_SET);
1267 }
1268
1269 if(!segment)
1270 error("unable to find LC_SEGMENT");
1271
1272 /* read section headers */
1273 section_hdr = load_data(fd, offset_to_segment + sizeof(struct segment_command), segment->nsects * sizeof(struct section));
1274
1275 /* read all section data */
1276 sdata = (uint8_t **)malloc(sizeof(void *) * segment->nsects);
1277 memset(sdata, 0, sizeof(void *) * segment->nsects);
1278
1279 /* Load the data in section data */
1280 for(i = 0; i < segment->nsects; i++) {
1281 sdata[i] = load_data(fd, section_hdr[i].offset, section_hdr[i].size);
1282 }
1283
1284 /* text section */
1285 text_sec_hdr = find_mach_sec_hdr(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
1286 i = find_mach_sec_index(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
1287 if (i == -1 || !text_sec_hdr)
1288 error("could not find __TEXT,__text section");
1289 text = sdata[i];
1290
1291 /* Make sure dysym was loaded */
1292 if(!(int)dysymtabcmd)
1293 error("could not find __DYSYMTAB segment");
1294
1295 /* read the table of content of the indirect sym */
1296 tocdylib = load_data( fd, dysymtabcmd->indirectsymoff, dysymtabcmd->nindirectsyms * sizeof(uint32_t) );
1297
1298 /* Make sure symtab was loaded */
1299 if(!(int)symtabcmd)
1300 error("could not find __SYMTAB segment");
1301 nb_syms = symtabcmd->nsyms;
1302
1303 symtab_std = load_data(fd, symtabcmd->symoff, symtabcmd->nsyms * sizeof(struct nlist));
1304 strtab = load_data(fd, symtabcmd->stroff, symtabcmd->strsize);
1305
1306 symtab = malloc(sizeof(EXE_SYM) * nb_syms);
1307
1308 /* Now transform the symtab, to an extended version, with the sym size, and the C name */
1309 for(i = 0, sym = symtab, syment = symtab_std; i < nb_syms; i++, sym++, syment++) {
1310 struct nlist *sym_cur, *sym_next = 0;
1311 unsigned int j;
1312 memset(sym, 0, sizeof(*sym));
1313
1314 if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
1315 continue;
1316
1317 memcpy(sym, syment, sizeof(*syment));
1318
1319#if defined(VBOX)
1320 /* don't bother calcing size of internal symbol local symbols. */
1321 if (strstart(find_str_by_index(sym->n_un.n_strx), ".L", NULL)) {
1322 sym->st_size = 0;
1323 continue;
1324 }
1325#endif
1326
1327 /* Find the following symbol in order to get the current symbol size */
1328 for (j = 0, sym_cur = symtab_std; j < nb_syms; j++, sym_cur++) {
1329 if ( sym_cur->n_sect != /*syment->n_sect*/ 1
1330 || (sym_cur->n_type & N_STAB)
1331 || sym_cur->n_value <= syment->n_value)
1332 continue;
1333 if ( sym_next
1334 && sym_next->n_value <= sym_cur->n_value)
1335 continue;
1336#if defined(HOST_I386)
1337 /* Ignore local labels (.Lxxx). */
1338 if (strstart(find_str_by_index(sym_cur->n_un.n_strx), ".L", NULL))
1339 continue;
1340#endif
1341 /* a good one */
1342 sym_next = sym_cur;
1343 }
1344 if(sym_next)
1345 sym->st_size = sym_next->n_value - sym->st_value;
1346 else
1347 sym->st_size = text_sec_hdr->size - sym->st_value;
1348 }
1349
1350 /* Find Reloc */
1351 relocs = load_data(fd, text_sec_hdr->reloff, text_sec_hdr->nreloc * sizeof(struct relocation_info));
1352 nb_relocs = text_sec_hdr->nreloc;
1353
1354 close(fd);
1355 return 0;
1356}
1357
1358#endif /* CONFIG_FORMAT_MACH */
1359
1360#ifdef CONFIG_FORMAT_AOUT
1361
1362struct exec *aout_hdr;
1363struct nlist *symtab_std;
1364char *strtab;
1365
1366
1367/* Utility functions */
1368
1369static inline char *find_str_by_index(int index)
1370{
1371 return strtab+index;
1372}
1373
1374/* Used by dyngen common code */
1375static char *get_sym_name(EXE_SYM *sym)
1376{
1377 char *name = find_str_by_index(sym->n_un.n_strx);
1378
1379 if (sym->n_type & N_STAB) /* Debug symbols are ignored */
1380 return "debug";
1381 if (name && name[0] == '_')
1382 return name + 1;
1383 return name;
1384}
1385
1386static int type_to_sec_number(unsigned type)
1387{
1388 switch (type)
1389 {
1390 case 0: case 0 |N_EXT: case N_WEAKU: return N_UNDF;
1391 case N_ABS: case N_ABS |N_EXT: case N_WEAKA: return N_ABS;
1392 case N_TEXT: case N_TEXT|N_EXT: case N_WEAKT: return N_TEXT;
1393 case N_DATA: case N_DATA|N_EXT: case N_WEAKD: return N_DATA;
1394 case N_BSS: case N_BSS |N_EXT: case N_WEAKB: return N_BSS;
1395 case N_SETA: case N_SETA|N_EXT: return N_SETA;
1396 case N_SETT: case N_SETT|N_EXT: return N_SETT;
1397 case N_SETD: case N_SETD|N_EXT: return N_SETD;
1398
1399 default:
1400 return type;
1401 }
1402}
1403
1404/* find a sym name given its value, in a section number */
1405static const char *find_sym_with_value_and_sec_number(long value, int sec, int *offset)
1406{
1407 int i, ret = -1;
1408
1409 for (i = 0; i < nb_syms; i++) {
1410 if ( !(symtab[i].n_type & N_STAB)
1411 && type_to_sec_number(symtab[i].n_type) == sec
1412 && symtab[i].st_value <= value
1413 && ( ret < 0
1414 || symtab[i].st_value >= symtab[ret].st_value)) {
1415 ret = i;
1416 }
1417 }
1418 if (ret < 0) {
1419 *offset = 0;
1420 return 0;
1421 }
1422 *offset = value - symtab[ret].st_value;
1423 return get_sym_name(&symtab[ret]);
1424}
1425
1426static const char *get_rel_sym_name_and_addend(EXE_RELOC *rel, int *sslide)
1427{
1428 int sec;
1429 int off;
1430
1431 *sslide = 0;
1432
1433 if (rel->r_extern)
1434 {
1435 /* ignore debug sym */
1436 if (symtab[rel->r_symbolnum].n_type & N_STAB)
1437 return 0;
1438
1439 /* The intruction contains the addend. */
1440 off = *(uint32_t *)(text + rel->r_address);
1441 if (rel->r_pcrel)
1442 off += rel->r_address;
1443 *sslide = off;
1444 return get_sym_name(&symtab[rel->r_symbolnum]);
1445 }
1446 if (rel->r_symbolnum == 0xffffff)
1447 return 0;
1448
1449 sec = rel->r_symbolnum & ~N_EXT;
1450 /* sanity */
1451 switch (sec)
1452 {
1453 case N_TEXT: case N_DATA: case N_BSS: case N_ABS: break;
1454 default: error("invalid section %d", sec);
1455 }
1456
1457 /* The intruction contains the addend. */
1458 off = *(uint32_t *)(text + rel->r_address);
1459 if (rel->r_pcrel)
1460 off += rel->r_address;
1461
1462 /* search it in the full symbol list, if not found */
1463 return find_sym_with_value_and_sec_number(off, sec, sslide);
1464}
1465
1466/* Used by dyngen common code */
1467static const char * get_rel_sym_name(EXE_RELOC *rel)
1468{
1469 int ignored;
1470 return get_rel_sym_name_and_addend(rel, &ignored);
1471}
1472
1473/* Used by dyngen common code */
1474static host_ulong get_rel_offset(EXE_RELOC *rel)
1475{
1476 return rel->r_address;
1477}
1478
1479/* load an a.out object file */
1480int load_object(const char *filename)
1481{
1482 FILE *pf;
1483 long file_size;
1484 unsigned i;
1485 EXE_SYM *dst_sym;
1486 struct nlist *src_sym;
1487
1488 /*
1489 * Open the file and validate the header.
1490 */
1491 pf = fopen(filename, "rb");
1492 if (!pf)
1493 error("can't open file '%s'", filename);
1494
1495 /* we're optimistic, read the entire file first. */
1496 if (fseek(pf, 0, SEEK_END) != 0)
1497 error("Input file '%s' is not seekable", filename);
1498 file_size = ftell(pf);
1499 fseek(pf, 0L, SEEK_SET);
1500
1501 aout_hdr = malloc(file_size + 1);
1502 if (!aout_hdr)
1503 error("malloc(%ld) failed", file_size + 1);
1504 if (fread(aout_hdr, 1, file_size, pf) != file_size)
1505 error("error reading '%s'", filename);
1506 fclose(pf);
1507
1508 /* validate the header. */
1509 if (N_MAGIC(*aout_hdr) != OMAGIC)
1510 error("unknown magic: %lo", N_MAGIC(*aout_hdr));
1511 if (N_MACHTYPE(*aout_hdr) != M_386 && N_MACHTYPE(*aout_hdr) != 0)
1512 error("unsupported machtype: %d", N_MACHTYPE(*aout_hdr));
1513
1514 /* setup globals. */
1515 strtab = (char *)((uint8_t *)aout_hdr + N_STROFF(*aout_hdr));
1516 symtab_std = (struct nlist *)((uint8_t *)aout_hdr + N_SYMOFF(*aout_hdr));
1517
1518 relocs = (struct relocation_info *)((uint8_t *)aout_hdr + N_TRELOFF(*aout_hdr));
1519 nb_syms = aout_hdr->a_syms / sizeof(struct nlist);
1520 text_shndx = 1;
1521 text = (uint8_t *)aout_hdr + N_TXTOFF(*aout_hdr);
1522 nb_relocs = aout_hdr->a_trsize / sizeof(relocs[0]);
1523
1524 /*
1525 * Now transform the symtab, to an extended version, with the sym size, and the C name
1526 */
1527 src_sym = symtab_std;
1528 dst_sym = symtab = malloc(sizeof(EXE_SYM) * nb_syms);
1529 if (!dst_sym)
1530 error("malloc(%zd) failed", sizeof(EXE_SYM) * nb_syms);
1531 for (i = 0; i < nb_syms; i++, src_sym++, dst_sym++) {
1532 struct nlist *sym_next = NULL;
1533 struct nlist *sym_cur;
1534 unsigned sec;
1535 unsigned j;
1536
1537 /* copy the symbol and find the name. */
1538 dst_sym->n_un.n_strx = src_sym->n_un.n_strx;
1539 dst_sym->n_type = src_sym->n_type;
1540 dst_sym->n_other = src_sym->n_other;
1541 dst_sym->n_desc = src_sym->n_desc;
1542 dst_sym->st_value = src_sym->n_value;
1543 dst_sym->st_size = 0;
1544 if (src_sym->n_type & N_STAB)
1545 continue; /* skip debug symbols. */
1546
1547 /* Find the following symbol in order to get the current symbol size */
1548 sec = type_to_sec_number(dst_sym->n_type);
1549 for (j = 0, sym_cur = symtab_std; j < nb_syms; j++, sym_cur++) {
1550 if ( type_to_sec_number(sym_cur->n_type) != sec
1551 || (sym_cur->n_type & N_STAB)
1552 || sym_cur->n_value <= dst_sym->st_value)
1553 continue;
1554 if ( sym_next
1555 && sym_next->n_value <= sym_cur->n_value)
1556 continue;
1557 /* good one */
1558 sym_next = sym_cur;
1559 }
1560 if (sym_next)
1561 dst_sym->st_size = sym_next->n_value - dst_sym->st_value;
1562 else
1563 dst_sym->st_size = aout_hdr->a_text - dst_sym->st_value;
1564 }
1565
1566 return 0;
1567}
1568
1569#endif /* CONFIG_FORMAT_AOUT */
1570
1571
1572void get_reloc_expr(char *name, int name_size, const char *sym_name)
1573{
1574 const char *p;
1575
1576 if (strstart(sym_name, "__op_param", &p)) {
1577 snprintf(name, name_size, "param%s", p);
1578 } else if (strstart(sym_name, "__op_gen_label", &p)) {
1579 snprintf(name, name_size, "gen_labels[param%s]", p);
1580 } else {
1581#ifdef HOST_SPARC
1582 if (sym_name[0] == '.')
1583 snprintf(name, name_size,
1584 "(long)(&__dot_%s)",
1585 sym_name + 1);
1586 else
1587#endif
1588 snprintf(name, name_size, "(long)(&%s)", sym_name);
1589 }
1590}
1591
1592#ifdef HOST_IA64
1593
1594#define PLT_ENTRY_SIZE 16 /* 1 bundle containing "brl" */
1595
1596struct plt_entry {
1597 struct plt_entry *next;
1598 const char *name;
1599 unsigned long addend;
1600} *plt_list;
1601
1602static int
1603get_plt_index (const char *name, unsigned long addend)
1604{
1605 struct plt_entry *plt, *prev= NULL;
1606 int index = 0;
1607
1608 /* see if we already have an entry for this target: */
1609 for (plt = plt_list; plt; ++index, prev = plt, plt = plt->next)
1610 if (strcmp(plt->name, name) == 0 && plt->addend == addend)
1611 return index;
1612
1613 /* nope; create a new PLT entry: */
1614
1615 plt = malloc(sizeof(*plt));
1616 if (!plt) {
1617 perror("malloc");
1618 exit(1);
1619 }
1620 memset(plt, 0, sizeof(*plt));
1621 plt->name = strdup(name);
1622 plt->addend = addend;
1623
1624 /* append to plt-list: */
1625 if (prev)
1626 prev->next = plt;
1627 else
1628 plt_list = plt;
1629 return index;
1630}
1631
1632#endif
1633
1634#ifdef HOST_ARM
1635
1636int arm_emit_ldr_info(const char *name, unsigned long start_offset,
1637 FILE *outfile, uint8_t *p_start, uint8_t *p_end,
1638 ELF_RELOC *relocs, int nb_relocs)
1639{
1640 uint8_t *p;
1641 uint32_t insn;
1642 int offset, min_offset, pc_offset, data_size, spare, max_pool;
1643 uint8_t data_allocated[1024];
1644 unsigned int data_index;
1645 int type;
1646
1647 memset(data_allocated, 0, sizeof(data_allocated));
1648
1649 p = p_start;
1650 min_offset = p_end - p_start;
1651 spare = 0x7fffffff;
1652 while (p < p_start + min_offset) {
1653 insn = get32((uint32_t *)p);
1654 /* TODO: Armv5e ldrd. */
1655 /* TODO: VFP load. */
1656 if ((insn & 0x0d5f0000) == 0x051f0000) {
1657 /* ldr reg, [pc, #im] */
1658 offset = insn & 0xfff;
1659 if (!(insn & 0x00800000))
1660 offset = -offset;
1661 max_pool = 4096;
1662 type = 0;
1663 } else if ((insn & 0x0e5f0f00) == 0x0c1f0100) {
1664 /* FPA ldf. */
1665 offset = (insn & 0xff) << 2;
1666 if (!(insn & 0x00800000))
1667 offset = -offset;
1668 max_pool = 1024;
1669 type = 1;
1670 } else if ((insn & 0x0fff0000) == 0x028f0000) {
1671 /* Some gcc load a doubleword immediate with
1672 add regN, pc, #imm
1673 ldmia regN, {regN, regM}
1674 Hope and pray the compiler never generates somethin like
1675 add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */
1676 int r;
1677
1678 r = (insn & 0xf00) >> 7;
1679 offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r));
1680 max_pool = 1024;
1681 type = 2;
1682 } else {
1683 max_pool = 0;
1684 type = -1;
1685 }
1686 if (type >= 0) {
1687 /* PC-relative load needs fixing up. */
1688 if (spare > max_pool - offset)
1689 spare = max_pool - offset;
1690 if ((offset & 3) !=0)
1691 error("%s:%04x: pc offset must be 32 bit aligned",
1692 name, start_offset + p - p_start);
1693 if (offset < 0)
1694 error("%s:%04x: Embedded literal value",
1695 name, start_offset + p - p_start);
1696 pc_offset = p - p_start + offset + 8;
1697 if (pc_offset <= (p - p_start) ||
1698 pc_offset >= (p_end - p_start))
1699 error("%s:%04x: pc offset must point inside the function code",
1700 name, start_offset + p - p_start);
1701 if (pc_offset < min_offset)
1702 min_offset = pc_offset;
1703 if (outfile) {
1704 /* The intruction position */
1705 fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
1706 p - p_start);
1707 /* The position of the constant pool data. */
1708 data_index = ((p_end - p_start) - pc_offset) >> 2;
1709 fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n",
1710 data_index);
1711 fprintf(outfile, " arm_ldr_ptr->type = %d;\n", type);
1712 fprintf(outfile, " arm_ldr_ptr++;\n");
1713 }
1714 }
1715 p += 4;
1716 }
1717
1718 /* Copy and relocate the constant pool data. */
1719 data_size = (p_end - p_start) - min_offset;
1720 if (data_size > 0 && outfile) {
1721 spare += min_offset;
1722 fprintf(outfile, " arm_data_ptr -= %d;\n", data_size >> 2);
1723 fprintf(outfile, " arm_pool_ptr -= %d;\n", data_size);
1724 fprintf(outfile, " if (arm_pool_ptr > gen_code_ptr + %d)\n"
1725 " arm_pool_ptr = gen_code_ptr + %d;\n",
1726 spare, spare);
1727
1728 data_index = 0;
1729 for (pc_offset = min_offset;
1730 pc_offset < p_end - p_start;
1731 pc_offset += 4) {
1732
1733 ELF_RELOC *rel;
1734 int i, addend, type;
1735 const char *sym_name;
1736 char relname[1024];
1737
1738 /* data value */
1739 addend = get32((uint32_t *)(p_start + pc_offset));
1740 relname[0] = '\0';
1741 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1742 if (rel->r_offset == (pc_offset + start_offset)) {
1743 sym_name = get_rel_sym_name(rel);
1744 /* the compiler leave some unnecessary references to the code */
1745 get_reloc_expr(relname, sizeof(relname), sym_name);
1746 type = ELF32_R_TYPE(rel->r_info);
1747 if (type != R_ARM_ABS32)
1748 error("%s: unsupported data relocation", name);
1749 break;
1750 }
1751 }
1752 fprintf(outfile, " arm_data_ptr[%d] = 0x%x",
1753 data_index, addend);
1754 if (relname[0] != '\0')
1755 fprintf(outfile, " + %s", relname);
1756 fprintf(outfile, ";\n");
1757
1758 data_index++;
1759 }
1760 }
1761
1762 if (p == p_start)
1763 goto arm_ret_error;
1764 p -= 4;
1765 insn = get32((uint32_t *)p);
1766 /* The last instruction must be an ldm instruction. There are several
1767 forms generated by gcc:
1768 ldmib sp, {..., pc} (implies a sp adjustment of +4)
1769 ldmia sp, {..., pc}
1770 ldmea fp, {..., pc} */
1771 if ((insn & 0xffff8000) == 0xe99d8000) {
1772 if (outfile) {
1773 fprintf(outfile,
1774 " *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n",
1775 p - p_start);
1776 }
1777 p += 4;
1778 } else if ((insn & 0xffff8000) != 0xe89d8000
1779 && (insn & 0xffff8000) != 0xe91b8000) {
1780 arm_ret_error:
1781 if (!outfile)
1782 printf("%s: invalid epilog\n", name);
1783 }
1784 return p - p_start;
1785}
1786#endif
1787
1788
1789#define MAX_ARGS 3
1790
1791/* generate op code */
1792void gen_code(const char *name, host_ulong offset, host_ulong size,
1793 FILE *outfile, int gen_switch)
1794{
1795 int copy_size = 0;
1796 uint8_t *p_start, *p_end;
1797 host_ulong start_offset;
1798 int nb_args, i, n;
1799 uint8_t args_present[MAX_ARGS];
1800 const char *sym_name, *p;
1801 EXE_RELOC *rel;
1802
1803 /* Compute exact size excluding prologue and epilogue instructions.
1804 * Increment start_offset to skip epilogue instructions, then compute
1805 * copy_size the indicate the size of the remaining instructions (in
1806 * bytes).
1807 */
1808 p_start = text + offset;
1809 p_end = p_start + size;
1810 start_offset = offset;
1811#if defined(HOST_I386) || defined(HOST_X86_64)
1812#if defined(CONFIG_FORMAT_COFF) || defined(CONFIG_FORMAT_AOUT) || defined(CONFIG_FORMAT_MACH)
1813 {
1814 uint8_t *p;
1815 p = p_end - 1;
1816 if (p == p_start)
1817 error("empty code for %s", name);
1818 while (*p != 0xc3) {
1819 p--;
1820 if (p <= p_start)
1821 error("ret or jmp expected at the end of %s", name);
1822 }
1823 copy_size = p - p_start;
1824 }
1825#else
1826 {
1827 int len;
1828 len = p_end - p_start;
1829 if (len == 0)
1830 error("empty code for %s", name);
1831 if (p_end[-1] == 0xc3) {
1832 len--;
1833 } else {
1834 error("ret or jmp expected at the end of %s", name);
1835 }
1836 copy_size = len;
1837 }
1838#endif
1839#elif defined(HOST_PPC)
1840 {
1841 uint8_t *p;
1842 p = (void *)(p_end - 4);
1843 if (p == p_start)
1844 error("empty code for %s", name);
1845 if (get32((uint32_t *)p) != 0x4e800020)
1846 error("blr expected at the end of %s", name);
1847 copy_size = p - p_start;
1848 }
1849#elif defined(HOST_S390)
1850 {
1851 uint8_t *p;
1852 p = (void *)(p_end - 2);
1853 if (p == p_start)
1854 error("empty code for %s", name);
1855 if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
1856 error("br %%r14 expected at the end of %s", name);
1857 copy_size = p - p_start;
1858 }
1859#elif defined(HOST_ALPHA)
1860 {
1861 uint8_t *p;
1862 p = p_end - 4;
1863#if 0
1864 /* XXX: check why it occurs */
1865 if (p == p_start)
1866 error("empty code for %s", name);
1867#endif
1868 if (get32((uint32_t *)p) != 0x6bfa8001)
1869 error("ret expected at the end of %s", name);
1870 copy_size = p - p_start;
1871 }
1872#elif defined(HOST_IA64)
1873 {
1874 uint8_t *p;
1875 p = (void *)(p_end - 4);
1876 if (p == p_start)
1877 error("empty code for %s", name);
1878 /* br.ret.sptk.many b0;; */
1879 /* 08 00 84 00 */
1880 if (get32((uint32_t *)p) != 0x00840008)
1881 error("br.ret.sptk.many b0;; expected at the end of %s", name);
1882 copy_size = p_end - p_start;
1883 }
1884#elif defined(HOST_SPARC)
1885 {
1886#define INSN_SAVE 0x9de3a000
1887#define INSN_RET 0x81c7e008
1888#define INSN_RETL 0x81c3e008
1889#define INSN_RESTORE 0x81e80000
1890#define INSN_RETURN 0x81cfe008
1891#define INSN_NOP 0x01000000
1892#define INSN_ADD_SP 0x9c03a000 /* add %sp, nn, %sp */
1893#define INSN_SUB_SP 0x9c23a000 /* sub %sp, nn, %sp */
1894
1895 uint32_t start_insn, end_insn1, end_insn2;
1896 uint8_t *p;
1897 p = (void *)(p_end - 8);
1898 if (p <= p_start)
1899 error("empty code for %s", name);
1900 start_insn = get32((uint32_t *)(p_start + 0x0));
1901 end_insn1 = get32((uint32_t *)(p + 0x0));
1902 end_insn2 = get32((uint32_t *)(p + 0x4));
1903 if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1904 (start_insn & ~0x1fff) == INSN_ADD_SP) {
1905 p_start += 0x4;
1906 start_offset += 0x4;
1907 if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
1908 /* SPARC v7: ret; restore; */ ;
1909 else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
1910 /* SPARC v9: return; nop; */ ;
1911 else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
1912 /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
1913 else
1914
1915 error("ret; restore; not found at end of %s", name);
1916 } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1917 ;
1918 } else {
1919 error("No save at the beginning of %s", name);
1920 }
1921#if 0
1922 /* Skip a preceeding nop, if present. */
1923 if (p > p_start) {
1924 skip_insn = get32((uint32_t *)(p - 0x4));
1925 if (skip_insn == INSN_NOP)
1926 p -= 4;
1927 }
1928#endif
1929 copy_size = p - p_start;
1930 }
1931#elif defined(HOST_SPARC64)
1932 {
1933#define INSN_SAVE 0x9de3a000
1934#define INSN_RET 0x81c7e008
1935#define INSN_RETL 0x81c3e008
1936#define INSN_RESTORE 0x81e80000
1937#define INSN_RETURN 0x81cfe008
1938#define INSN_NOP 0x01000000
1939#define INSN_ADD_SP 0x9c03a000 /* add %sp, nn, %sp */
1940#define INSN_SUB_SP 0x9c23a000 /* sub %sp, nn, %sp */
1941
1942 uint32_t start_insn, end_insn1, end_insn2, skip_insn;
1943 uint8_t *p;
1944 p = (void *)(p_end - 8);
1945#if 0
1946 /* XXX: check why it occurs */
1947 if (p <= p_start)
1948 error("empty code for %s", name);
1949#endif
1950 start_insn = get32((uint32_t *)(p_start + 0x0));
1951 end_insn1 = get32((uint32_t *)(p + 0x0));
1952 end_insn2 = get32((uint32_t *)(p + 0x4));
1953 if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1954 (start_insn & ~0x1fff) == INSN_ADD_SP) {
1955 p_start += 0x4;
1956 start_offset += 0x4;
1957 if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
1958 /* SPARC v7: ret; restore; */ ;
1959 else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
1960 /* SPARC v9: return; nop; */ ;
1961 else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
1962 /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
1963 else
1964
1965 error("ret; restore; not found at end of %s", name);
1966 } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1967 ;
1968 } else {
1969 error("No save at the beginning of %s", name);
1970 }
1971
1972 /* Skip a preceeding nop, if present. */
1973 if (p > p_start) {
1974 skip_insn = get32((uint32_t *)(p - 0x4));
1975 if (skip_insn == 0x01000000)
1976 p -= 4;
1977 }
1978
1979 copy_size = p - p_start;
1980 }
1981#elif defined(HOST_ARM)
1982 {
1983 uint32_t insn;
1984
1985 if ((p_end - p_start) <= 16)
1986 error("%s: function too small", name);
1987 if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
1988 (get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 ||
1989 get32((uint32_t *)(p_start + 8)) != 0xe24cb004)
1990 error("%s: invalid prolog", name);
1991 p_start += 12;
1992 start_offset += 12;
1993 insn = get32((uint32_t *)p_start);
1994 if ((insn & 0xffffff00) == 0xe24dd000) {
1995 /* Stack adjustment. Assume op uses the frame pointer. */
1996 p_start -= 4;
1997 start_offset -= 4;
1998 }
1999 copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
2000 relocs, nb_relocs);
2001 }
2002#elif defined(HOST_M68K)
2003 {
2004 uint8_t *p;
2005 p = (void *)(p_end - 2);
2006 if (p == p_start)
2007 error("empty code for %s", name);
2008 /* remove NOP's, probably added for alignment */
2009 while ((get16((uint16_t *)p) == 0x4e71) &&
2010 (p>p_start))
2011 p -= 2;
2012 if (get16((uint16_t *)p) != 0x4e75)
2013 error("rts expected at the end of %s", name);
2014 copy_size = p - p_start;
2015 }
2016#else
2017#error unsupported CPU
2018#endif
2019
2020 /* compute the number of arguments by looking at the relocations */
2021 for(i = 0;i < MAX_ARGS; i++)
2022 args_present[i] = 0;
2023
2024 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2025 host_ulong offset = get_rel_offset(rel);
2026 if (offset >= start_offset &&
2027 offset < start_offset + (p_end - p_start)) {
2028 sym_name = get_rel_sym_name(rel);
2029 if(!sym_name)
2030 continue;
2031 if (strstart(sym_name, "__op_param", &p) ||
2032 strstart(sym_name, "__op_gen_label", &p)) {
2033 n = strtoul(p, NULL, 10);
2034 if (n > MAX_ARGS)
2035 error("too many arguments in %s", name);
2036 args_present[n - 1] = 1;
2037 }
2038 }
2039 }
2040
2041 nb_args = 0;
2042 while (nb_args < MAX_ARGS && args_present[nb_args])
2043 nb_args++;
2044 for(i = nb_args; i < MAX_ARGS; i++) {
2045 if (args_present[i])
2046 error("inconsistent argument numbering in %s", name);
2047 }
2048
2049 if (gen_switch == 2) {
2050 fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
2051 } else if (gen_switch == 1) {
2052
2053 /* output C code */
2054 fprintf(outfile, "case INDEX_%s: {\n", name);
2055 if (nb_args > 0) {
2056 fprintf(outfile, " long ");
2057 for(i = 0; i < nb_args; i++) {
2058 if (i != 0)
2059 fprintf(outfile, ", ");
2060 fprintf(outfile, "param%d", i + 1);
2061 }
2062 fprintf(outfile, ";\n");
2063 }
2064#if defined(HOST_IA64)
2065 fprintf(outfile, " extern char %s;\n", name);
2066#else
2067 fprintf(outfile, " extern void %s();\n", name);
2068#endif
2069
2070 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2071 host_ulong offset = get_rel_offset(rel);
2072 if (offset >= start_offset &&
2073 offset < start_offset + (p_end - p_start)) {
2074 sym_name = get_rel_sym_name(rel);
2075 if(!sym_name)
2076 continue;
2077 if (*sym_name &&
2078#ifdef VBOX
2079 !strstart(sym_name, "remR3PhysWrite", NULL) &&
2080 !strstart(sym_name, "remR3PhysRead", NULL) &&
2081#endif
2082 !strstart(sym_name, "__op_param", NULL) &&
2083 !strstart(sym_name, "__op_jmp", NULL) &&
2084 !strstart(sym_name, "__op_gen_label", NULL)) {
2085#if defined(HOST_SPARC)
2086 if (sym_name[0] == '.') {
2087 fprintf(outfile,
2088 "extern char __dot_%s __asm__(\"%s\");\n",
2089 sym_name+1, sym_name);
2090 continue;
2091 }
2092#endif
2093#if defined(__APPLE__)
2094/* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */
2095 fprintf(outfile, "extern char %s __attribute__((unused));\n", sym_name);
2096#elif defined(HOST_IA64)
2097 if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
2098 /*
2099 * PCREL21 br.call targets generally
2100 * are out of range and need to go
2101 * through an "import stub".
2102 */
2103 fprintf(outfile, " extern char %s;\n",
2104 sym_name);
2105#else
2106 /* don't include memcpy here as this external reference wouldn't work anyway! */
2107 if (strcmp(sym_name, "memcpy"))
2108 fprintf(outfile, "extern char %s;\n", sym_name);
2109#endif
2110 }
2111 }
2112 }
2113
2114 fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n",
2115 name, (int)(start_offset - offset), copy_size);
2116
2117 /* emit code offset information */
2118 {
2119 EXE_SYM *sym;
2120 const char *sym_name, *p;
2121 unsigned long val;
2122 int n;
2123
2124 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2125 sym_name = get_sym_name(sym);
2126 if (strstart(sym_name, "__op_label", &p)) {
2127 uint8_t *ptr;
2128 unsigned long offset;
2129
2130 /* test if the variable refers to a label inside
2131 the code we are generating */
2132#ifdef CONFIG_FORMAT_COFF
2133 if (sym->st_shndx == text_shndx) {
2134 ptr = sdata[coff_text_shndx];
2135 } else if (sym->st_shndx == data_shndx) {
2136 ptr = sdata[coff_data_shndx];
2137 } else {
2138 ptr = NULL;
2139 }
2140#elif defined(CONFIG_FORMAT_MACH)
2141 if(!sym->n_sect)
2142 continue;
2143 ptr = sdata[sym->n_sect-1];
2144#elif defined(CONFIG_FORMAT_AOUT)
2145 switch (type_to_sec_number(sym->n_type))
2146 {
2147 case N_TEXT: ptr = (uint8_t *)aout_hdr + N_TXTOFF(*aout_hdr); break;
2148 case N_DATA: ptr = (uint8_t *)aout_hdr + N_DATOFF(*aout_hdr); break;
2149 default: ptr = NULL;
2150 }
2151#else
2152 ptr = sdata[sym->st_shndx];
2153#endif
2154 if (!ptr)
2155 error("__op_labelN in invalid section");
2156 offset = sym->st_value;
2157#ifdef CONFIG_FORMAT_MACH
2158 offset -= section_hdr[sym->n_sect-1].addr;
2159#elif defined(CONFIG_FORMAT_AOUT)
2160 if (type_to_sec_number(sym->n_type) == N_DATA)
2161 offset -= aout_hdr->a_text;
2162#endif
2163 val = *(unsigned long *)(ptr + offset);
2164#ifdef ELF_USES_RELOCA
2165 {
2166 int reloc_shndx, nb_relocs1, j;
2167
2168 /* try to find a matching relocation */
2169 reloc_shndx = find_reloc(sym->st_shndx);
2170 if (reloc_shndx) {
2171 nb_relocs1 = shdr[reloc_shndx].sh_size /
2172 shdr[reloc_shndx].sh_entsize;
2173 rel = (ELF_RELOC *)sdata[reloc_shndx];
2174 for(j = 0; j < nb_relocs1; j++) {
2175 if (rel->r_offset == offset) {
2176 val = rel->r_addend;
2177 break;
2178 }
2179 rel++;
2180 }
2181 }
2182 }
2183#endif
2184 if (val >= start_offset && val <= start_offset + copy_size) {
2185 n = strtol(p, NULL, 10);
2186 fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset));
2187 }
2188 }
2189 }
2190 }
2191
2192 /* load parameres in variables */
2193 for(i = 0; i < nb_args; i++) {
2194 fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1);
2195 }
2196
2197 /* patch relocations */
2198#if defined(HOST_I386)
2199 {
2200 char name[256];
2201 int type;
2202 int addend;
2203 int reloc_offset;
2204 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2205 host_ulong offset = get_rel_offset(rel);
2206 if (offset >= start_offset &&
2207 offset < start_offset + copy_size) {
2208#if defined(CONFIG_FORMAT_AOUT) || defined(CONFIG_FORMAT_MACH)
2209 sym_name = get_rel_sym_name_and_addend(rel, &addend);
2210#else
2211 sym_name = get_rel_sym_name(rel);
2212#endif
2213 if (!sym_name)
2214 continue;
2215 reloc_offset = offset - start_offset;
2216 if (strstart(sym_name, "__op_jmp", &p)) {
2217 int n;
2218 n = strtol(p, NULL, 10);
2219 /* __op_jmp relocations are done at
2220 runtime to do translated block
2221 chaining: the offset of the instruction
2222 needs to be stored */
2223 fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
2224 n, reloc_offset);
2225 continue;
2226 }
2227
2228 get_reloc_expr(name, sizeof(name), sym_name);
2229#if !defined(CONFIG_FORMAT_AOUT) && !defined(CONFIG_FORMAT_MACH)
2230 addend = get32((uint32_t *)(text + offset));
2231#endif
2232#ifdef CONFIG_FORMAT_ELF
2233 type = ELF32_R_TYPE(rel->r_info);
2234 switch(type) {
2235 case R_386_32:
2236 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2237 reloc_offset, name, addend);
2238 break;
2239 case R_386_PC32:
2240 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
2241 reloc_offset, name, reloc_offset, addend);
2242 break;
2243 default:
2244 error("unsupported i386 relocation (%d)", type);
2245 }
2246#elif defined(CONFIG_FORMAT_COFF)
2247 {
2248 char *temp_name;
2249 int j;
2250 EXE_SYM *sym;
2251 temp_name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
2252 if (!strcmp(temp_name, ".data")) {
2253 for (j = 0, sym = symtab; j < nb_syms; j++, sym++) {
2254 if (strstart(sym->st_name, sym_name, NULL)) {
2255 addend -= sym->st_value;
2256 }
2257 }
2258 }
2259 }
2260 type = rel->r_type;
2261 switch(type) {
2262 case DIR32:
2263 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2264 reloc_offset, name, addend);
2265 break;
2266 case DISP32:
2267 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
2268 reloc_offset, name, reloc_offset, addend);
2269 break;
2270 default:
2271 error("unsupported i386 relocation (%d)", type);
2272 }
2273#elif defined(CONFIG_FORMAT_AOUT) || defined(CONFIG_FORMAT_MACH)
2274 if (rel->r_pcrel) {
2275 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
2276 offset - start_offset, name, offset - start_offset, addend);
2277 } else {
2278 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2279 offset - start_offset, name, addend);
2280 }
2281 (void)type;
2282#else
2283#error unsupport object format
2284#endif
2285 }
2286 }
2287 }
2288#elif defined(HOST_X86_64)
2289 {
2290 char name[256];
2291 int type;
2292 int addend;
2293 int reloc_offset;
2294 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2295 if (rel->r_offset >= start_offset &&
2296 rel->r_offset < start_offset + copy_size) {
2297 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2298 get_reloc_expr(name, sizeof(name), sym_name);
2299 type = ELF32_R_TYPE(rel->r_info);
2300 addend = rel->r_addend;
2301 reloc_offset = rel->r_offset - start_offset;
2302 switch(type) {
2303 case R_X86_64_32:
2304 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
2305 reloc_offset, name, addend);
2306 break;
2307 case R_X86_64_32S:
2308 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
2309 reloc_offset, name, addend);
2310 break;
2311 case R_X86_64_PC32:
2312 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
2313 reloc_offset, name, reloc_offset, addend);
2314 break;
2315#ifdef VBOX /** @todo Re-check the sanity of this */
2316 case R_X86_64_64:
2317 fprintf(outfile, " *(uint64_t *)(gen_code_ptr + %d) = (uint64_t)%s + %d;\n",
2318 reloc_offset, name, addend);
2319 break;
2320#endif
2321 default:
2322 error("unsupported X86_64 relocation (%d)", type);
2323 }
2324 }
2325 }
2326 }
2327#elif defined(HOST_PPC)
2328 {
2329#ifdef CONFIG_FORMAT_ELF
2330 char name[256];
2331 int type;
2332 int addend;
2333 int reloc_offset;
2334 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2335 if (rel->r_offset >= start_offset &&
2336 rel->r_offset < start_offset + copy_size) {
2337 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2338 reloc_offset = rel->r_offset - start_offset;
2339 if (strstart(sym_name, "__op_jmp", &p)) {
2340 int n;
2341 n = strtol(p, NULL, 10);
2342 /* __op_jmp relocations are done at
2343 runtime to do translated block
2344 chaining: the offset of the instruction
2345 needs to be stored */
2346 fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
2347 n, reloc_offset);
2348 continue;
2349 }
2350
2351 get_reloc_expr(name, sizeof(name), sym_name);
2352 type = ELF32_R_TYPE(rel->r_info);
2353 addend = rel->r_addend;
2354 switch(type) {
2355 case R_PPC_ADDR32:
2356 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2357 reloc_offset, name, addend);
2358 break;
2359 case R_PPC_ADDR16_LO:
2360 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
2361 reloc_offset, name, addend);
2362 break;
2363 case R_PPC_ADDR16_HI:
2364 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
2365 reloc_offset, name, addend);
2366 break;
2367 case R_PPC_ADDR16_HA:
2368 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
2369 reloc_offset, name, addend);
2370 break;
2371 case R_PPC_REL24:
2372 /* warning: must be at 32 MB distancy */
2373 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
2374 reloc_offset, reloc_offset, name, reloc_offset, addend);
2375 break;
2376 default:
2377 error("unsupported powerpc relocation (%d)", type);
2378 }
2379 }
2380 }
2381#elif defined(CONFIG_FORMAT_MACH)
2382 struct scattered_relocation_info *scarel;
2383 struct relocation_info * rel;
2384 char final_sym_name[256];
2385 const char *sym_name;
2386 const char *p;
2387 int slide, sslide;
2388 int i;
2389
2390 for(i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
2391 unsigned int offset, length, value = 0;
2392 unsigned int type, pcrel, isym = 0;
2393 unsigned int usesym = 0;
2394
2395 if(R_SCATTERED & rel->r_address) {
2396 scarel = (struct scattered_relocation_info*)rel;
2397 offset = (unsigned int)scarel->r_address;
2398 length = scarel->r_length;
2399 pcrel = scarel->r_pcrel;
2400 type = scarel->r_type;
2401 value = scarel->r_value;
2402 } else {
2403 value = isym = rel->r_symbolnum;
2404 usesym = (rel->r_extern);
2405 offset = rel->r_address;
2406 length = rel->r_length;
2407 pcrel = rel->r_pcrel;
2408 type = rel->r_type;
2409 }
2410
2411 slide = offset - start_offset;
2412
2413 if (!(offset >= start_offset && offset < start_offset + size))
2414 continue; /* not in our range */
2415
2416 sym_name = get_reloc_name(rel, &sslide);
2417
2418 if(usesym && symtab[isym].n_type & N_STAB)
2419 continue; /* don't handle STAB (debug sym) */
2420
2421 if (sym_name && strstart(sym_name, "__op_jmp", &p)) {
2422 int n;
2423 n = strtol(p, NULL, 10);
2424 fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
2425 n, slide);
2426 continue; /* Nothing more to do */
2427 }
2428
2429 if(!sym_name)
2430 {
2431 fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n",
2432 name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type);
2433 continue; /* dunno how to handle without final_sym_name */
2434 }
2435
2436 get_reloc_expr(final_sym_name, sizeof(final_sym_name),
2437 sym_name);
2438 switch(type) {
2439 case PPC_RELOC_BR24:
2440 if (!strstart(sym_name,"__op_gen_label",&p)) {
2441 fprintf(outfile, "{\n");
2442 fprintf(outfile, " uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
2443 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",
2444 slide, slide, name, sslide );
2445 fprintf(outfile, "}\n");
2446 } else {
2447 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
2448 slide, slide, final_sym_name, slide);
2449 }
2450 break;
2451 case PPC_RELOC_HI16:
2452 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n",
2453 slide, final_sym_name, sslide);
2454 break;
2455 case PPC_RELOC_LO16:
2456 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n",
2457 slide, final_sym_name, sslide);
2458 break;
2459 case PPC_RELOC_HA16:
2460 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n",
2461 slide, final_sym_name, sslide);
2462 break;
2463 default:
2464 error("unsupported powerpc relocation (%d)", type);
2465 }
2466 }
2467#else
2468#error unsupport object format
2469#endif
2470 }
2471#elif defined(HOST_S390)
2472 {
2473 char name[256];
2474 int type;
2475 int addend;
2476 int reloc_offset;
2477 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2478 if (rel->r_offset >= start_offset &&
2479 rel->r_offset < start_offset + copy_size) {
2480 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2481 get_reloc_expr(name, sizeof(name), sym_name);
2482 type = ELF32_R_TYPE(rel->r_info);
2483 addend = rel->r_addend;
2484 reloc_offset = rel->r_offset - start_offset;
2485 switch(type) {
2486 case R_390_32:
2487 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2488 reloc_offset, name, addend);
2489 break;
2490 case R_390_16:
2491 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
2492 reloc_offset, name, addend);
2493 break;
2494 case R_390_8:
2495 fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
2496 reloc_offset, name, addend);
2497 break;
2498 default:
2499 error("unsupported s390 relocation (%d)", type);
2500 }
2501 }
2502 }
2503 }
2504#elif defined(HOST_ALPHA)
2505 {
2506 for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
2507 if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
2508 int type;
2509 long reloc_offset;
2510
2511 type = ELF64_R_TYPE(rel->r_info);
2512 sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
2513 reloc_offset = rel->r_offset - start_offset;
2514 switch (type) {
2515 case R_ALPHA_GPDISP:
2516 /* The gp is just 32 bit, and never changes, so it's easiest to emit it
2517 as an immediate instead of constructing it from the pv or ra. */
2518 fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, gp);\n",
2519 reloc_offset);
2520 fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n",
2521 reloc_offset + (int)rel->r_addend);
2522 break;
2523 case R_ALPHA_LITUSE:
2524 /* jsr to literal hint. Could be used to optimize to bsr. Ignore for
2525 now, since some called functions (libc) need pv to be set up. */
2526 break;
2527 case R_ALPHA_HINT:
2528 /* Branch target prediction hint. Ignore for now. Should be already
2529 correct for in-function jumps. */
2530 break;
2531 case R_ALPHA_LITERAL:
2532 /* Load a literal from the GOT relative to the gp. Since there's only a
2533 single gp, nothing is to be done. */
2534 break;
2535 case R_ALPHA_GPRELHIGH:
2536 /* Handle fake relocations against __op_param symbol. Need to emit the
2537 high part of the immediate value instead. Other symbols need no
2538 special treatment. */
2539 if (strstart(sym_name, "__op_param", &p))
2540 fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, param%s);\n",
2541 reloc_offset, p);
2542 break;
2543 case R_ALPHA_GPRELLOW:
2544 if (strstart(sym_name, "__op_param", &p))
2545 fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, param%s);\n",
2546 reloc_offset, p);
2547 break;
2548 case R_ALPHA_BRSGP:
2549 /* PC-relative jump. Tweak offset to skip the two instructions that try to
2550 set up the gp from the pv. */
2551 fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
2552 reloc_offset, sym_name, reloc_offset);
2553 break;
2554 default:
2555 error("unsupported Alpha relocation (%d)", type);
2556 }
2557 }
2558 }
2559 }
2560#elif defined(HOST_IA64)
2561 {
2562 unsigned long sym_idx;
2563 long code_offset;
2564 char name[256];
2565 int type;
2566 long addend;
2567
2568 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2569 sym_idx = ELF64_R_SYM(rel->r_info);
2570 if (rel->r_offset < start_offset
2571 || rel->r_offset >= start_offset + copy_size)
2572 continue;
2573 sym_name = (strtab + symtab[sym_idx].st_name);
2574 code_offset = rel->r_offset - start_offset;
2575 if (strstart(sym_name, "__op_jmp", &p)) {
2576 int n;
2577 n = strtol(p, NULL, 10);
2578 /* __op_jmp relocations are done at
2579 runtime to do translated block
2580 chaining: the offset of the instruction
2581 needs to be stored */
2582 fprintf(outfile, " jmp_offsets[%d] ="
2583 "%ld + (gen_code_ptr - gen_code_buf);\n",
2584 n, code_offset);
2585 continue;
2586 }
2587 get_reloc_expr(name, sizeof(name), sym_name);
2588 type = ELF64_R_TYPE(rel->r_info);
2589 addend = rel->r_addend;
2590 switch(type) {
2591 case R_IA64_IMM64:
2592 fprintf(outfile,
2593 " ia64_imm64(gen_code_ptr + %ld, "
2594 "%s + %ld);\n",
2595 code_offset, name, addend);
2596 break;
2597 case R_IA64_LTOFF22X:
2598 case R_IA64_LTOFF22:
2599 fprintf(outfile, " IA64_LTOFF(gen_code_ptr + %ld,"
2600 " %s + %ld, %d);\n",
2601 code_offset, name, addend,
2602 (type == R_IA64_LTOFF22X));
2603 break;
2604 case R_IA64_LDXMOV:
2605 fprintf(outfile,
2606 " ia64_ldxmov(gen_code_ptr + %ld,"
2607 " %s + %ld);\n", code_offset, name, addend);
2608 break;
2609
2610 case R_IA64_PCREL21B:
2611 if (strstart(sym_name, "__op_gen_label", NULL)) {
2612 fprintf(outfile,
2613 " ia64_imm21b(gen_code_ptr + %ld,"
2614 " (long) (%s + %ld -\n\t\t"
2615 "((long) gen_code_ptr + %ld)) >> 4);\n",
2616 code_offset, name, addend,
2617 code_offset & ~0xfUL);
2618 } else {
2619 fprintf(outfile,
2620 " IA64_PLT(gen_code_ptr + %ld, "
2621 "%d);\t/* %s + %ld */\n",
2622 code_offset,
2623 get_plt_index(sym_name, addend),
2624 sym_name, addend);
2625 }
2626 break;
2627 default:
2628 error("unsupported ia64 relocation (0x%x)",
2629 type);
2630 }
2631 }
2632 fprintf(outfile, " ia64_nop_b(gen_code_ptr + %d);\n",
2633 copy_size - 16 + 2);
2634 }
2635#elif defined(HOST_SPARC)
2636 {
2637 char name[256];
2638 int type;
2639 int addend;
2640 int reloc_offset;
2641 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2642 if (rel->r_offset >= start_offset &&
2643 rel->r_offset < start_offset + copy_size) {
2644 sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
2645 get_reloc_expr(name, sizeof(name), sym_name);
2646 type = ELF32_R_TYPE(rel->r_info);
2647 addend = rel->r_addend;
2648 reloc_offset = rel->r_offset - start_offset;
2649 switch(type) {
2650 case R_SPARC_32:
2651 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2652 reloc_offset, name, addend);
2653 break;
2654 case R_SPARC_HI22:
2655 fprintf(outfile,
2656 " *(uint32_t *)(gen_code_ptr + %d) = "
2657 "((*(uint32_t *)(gen_code_ptr + %d)) "
2658 " & ~0x3fffff) "
2659 " | (((%s + %d) >> 10) & 0x3fffff);\n",
2660 reloc_offset, reloc_offset, name, addend);
2661 break;
2662 case R_SPARC_LO10:
2663 fprintf(outfile,
2664 " *(uint32_t *)(gen_code_ptr + %d) = "
2665 "((*(uint32_t *)(gen_code_ptr + %d)) "
2666 " & ~0x3ff) "
2667 " | ((%s + %d) & 0x3ff);\n",
2668 reloc_offset, reloc_offset, name, addend);
2669 break;
2670 case R_SPARC_WDISP30:
2671 fprintf(outfile,
2672 " *(uint32_t *)(gen_code_ptr + %d) = "
2673 "((*(uint32_t *)(gen_code_ptr + %d)) "
2674 " & ~0x3fffffff) "
2675 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2676 " & 0x3fffffff);\n",
2677 reloc_offset, reloc_offset, name, addend,
2678 reloc_offset);
2679 break;
2680 case R_SPARC_WDISP22:
2681 fprintf(outfile,
2682 " *(uint32_t *)(gen_code_ptr + %d) = "
2683 "((*(uint32_t *)(gen_code_ptr + %d)) "
2684 " & ~0x3fffff) "
2685 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2686 " & 0x3fffff);\n",
2687 rel->r_offset - start_offset,
2688 rel->r_offset - start_offset,
2689 name, addend,
2690 rel->r_offset - start_offset);
2691 break;
2692 default:
2693 error("unsupported sparc relocation (%d)", type);
2694 }
2695 }
2696 }
2697 }
2698#elif defined(HOST_SPARC64)
2699 {
2700 char name[256];
2701 int type;
2702 int addend;
2703 int reloc_offset;
2704 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2705 if (rel->r_offset >= start_offset &&
2706 rel->r_offset < start_offset + copy_size) {
2707 sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
2708 get_reloc_expr(name, sizeof(name), sym_name);
2709 type = ELF32_R_TYPE(rel->r_info);
2710 addend = rel->r_addend;
2711 reloc_offset = rel->r_offset - start_offset;
2712 switch(type) {
2713 case R_SPARC_32:
2714 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2715 reloc_offset, name, addend);
2716 break;
2717 case R_SPARC_HI22:
2718 fprintf(outfile,
2719 " *(uint32_t *)(gen_code_ptr + %d) = "
2720 "((*(uint32_t *)(gen_code_ptr + %d)) "
2721 " & ~0x3fffff) "
2722 " | (((%s + %d) >> 10) & 0x3fffff);\n",
2723 reloc_offset, reloc_offset, name, addend);
2724 break;
2725 case R_SPARC_LO10:
2726 fprintf(outfile,
2727 " *(uint32_t *)(gen_code_ptr + %d) = "
2728 "((*(uint32_t *)(gen_code_ptr + %d)) "
2729 " & ~0x3ff) "
2730 " | ((%s + %d) & 0x3ff);\n",
2731 reloc_offset, reloc_offset, name, addend);
2732 break;
2733 case R_SPARC_OLO10:
2734 addend += ELF64_R_TYPE_DATA (rel->r_info);
2735 fprintf(outfile,
2736 " *(uint32_t *)(gen_code_ptr + %d) = "
2737 "((*(uint32_t *)(gen_code_ptr + %d)) "
2738 " & ~0x3ff) "
2739 " | ((%s + %d) & 0x3ff);\n",
2740 reloc_offset, reloc_offset, name, addend);
2741 break;
2742 case R_SPARC_WDISP30:
2743 fprintf(outfile,
2744 " *(uint32_t *)(gen_code_ptr + %d) = "
2745 "((*(uint32_t *)(gen_code_ptr + %d)) "
2746 " & ~0x3fffffff) "
2747 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2748 " & 0x3fffffff);\n",
2749 reloc_offset, reloc_offset, name, addend,
2750 reloc_offset);
2751 break;
2752 case R_SPARC_WDISP22:
2753 fprintf(outfile,
2754 " *(uint32_t *)(gen_code_ptr + %d) = "
2755 "((*(uint32_t *)(gen_code_ptr + %d)) "
2756 " & ~0x3fffff) "
2757 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2758 " & 0x3fffff);\n",
2759 reloc_offset, reloc_offset, name, addend,
2760 reloc_offset);
2761 break;
2762 default:
2763 error("unsupported sparc64 relocation (%d) for symbol %s", type, name);
2764 }
2765 }
2766 }
2767 }
2768#elif defined(HOST_ARM)
2769 {
2770 char name[256];
2771 int type;
2772 int addend;
2773 int reloc_offset;
2774 uint32_t insn;
2775
2776 insn = get32((uint32_t *)(p_start + 4));
2777 /* If prologue ends in sub sp, sp, #const then assume
2778 op has a stack frame and needs the frame pointer. */
2779 if ((insn & 0xffffff00) == 0xe24dd000) {
2780 int i;
2781 uint32_t opcode;
2782 opcode = 0xe28db000; /* add fp, sp, #0. */
2783#if 0
2784/* ??? Need to undo the extra stack adjustment at the end of the op.
2785 For now just leave the stack misaligned and hope it doesn't break anything
2786 too important. */
2787 if ((insn & 4) != 0) {
2788 /* Preserve doubleword stack alignment. */
2789 fprintf(outfile,
2790 " *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n",
2791 insn + 4);
2792 opcode -= 4;
2793 }
2794#endif
2795 insn = get32((uint32_t *)(p_start - 4));
2796 /* Calculate the size of the saved registers,
2797 excluding pc. */
2798 for (i = 0; i < 15; i++) {
2799 if (insn & (1 << i))
2800 opcode += 4;
2801 }
2802 fprintf(outfile,
2803 " *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
2804 }
2805 arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
2806 relocs, nb_relocs);
2807
2808 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2809 if (rel->r_offset >= start_offset &&
2810 rel->r_offset < start_offset + copy_size) {
2811 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2812 /* the compiler leave some unnecessary references to the code */
2813 if (sym_name[0] == '\0')
2814 continue;
2815 get_reloc_expr(name, sizeof(name), sym_name);
2816 type = ELF32_R_TYPE(rel->r_info);
2817 addend = get32((uint32_t *)(text + rel->r_offset));
2818 reloc_offset = rel->r_offset - start_offset;
2819 switch(type) {
2820 case R_ARM_ABS32:
2821 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2822 reloc_offset, name, addend);
2823 break;
2824 case R_ARM_PC24:
2825 case R_ARM_JUMP24:
2826 case R_ARM_CALL:
2827 fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
2828 reloc_offset, addend, name);
2829 break;
2830 default:
2831 error("unsupported arm relocation (%d)", type);
2832 }
2833 }
2834 }
2835 }
2836#elif defined(HOST_M68K)
2837 {
2838 char name[256];
2839 int type;
2840 int addend;
2841 int reloc_offset;
2842 Elf32_Sym *sym;
2843 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2844 if (rel->r_offset >= start_offset &&
2845 rel->r_offset < start_offset + copy_size) {
2846 sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
2847 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2848 get_reloc_expr(name, sizeof(name), sym_name);
2849 type = ELF32_R_TYPE(rel->r_info);
2850 addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
2851 reloc_offset = rel->r_offset - start_offset;
2852 switch(type) {
2853 case R_68K_32:
2854 fprintf(outfile, " /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
2855 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
2856 reloc_offset, name, addend );
2857 break;
2858 case R_68K_PC32:
2859 fprintf(outfile, " /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
2860 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
2861 reloc_offset, name, reloc_offset, /*sym->st_value+*/ addend);
2862 break;
2863 default:
2864 error("unsupported m68k relocation (%d)", type);
2865 }
2866 }
2867 }
2868 }
2869#else
2870#error unsupported CPU
2871#endif
2872 fprintf(outfile, " gen_code_ptr += %d;\n", copy_size);
2873 fprintf(outfile, "}\n");
2874 fprintf(outfile, "break;\n\n");
2875 } else {
2876 fprintf(outfile, "static inline void gen_%s(", name);
2877 if (nb_args == 0) {
2878 fprintf(outfile, "void");
2879 } else {
2880 for(i = 0; i < nb_args; i++) {
2881 if (i != 0)
2882 fprintf(outfile, ", ");
2883 fprintf(outfile, "long param%d", i + 1);
2884 }
2885 }
2886 fprintf(outfile, ")\n");
2887 fprintf(outfile, "{\n");
2888 for(i = 0; i < nb_args; i++) {
2889 fprintf(outfile, " *gen_opparam_ptr++ = param%d;\n", i + 1);
2890 }
2891 fprintf(outfile, " *gen_opc_ptr++ = INDEX_%s;\n", name);
2892 fprintf(outfile, "}\n\n");
2893 }
2894}
2895
2896int gen_file(FILE *outfile, int out_type)
2897{
2898 int i;
2899 EXE_SYM *sym;
2900
2901 if (out_type == OUT_INDEX_OP) {
2902 fprintf(outfile, "DEF(end, 0, 0)\n");
2903 fprintf(outfile, "DEF(nop, 0, 0)\n");
2904 fprintf(outfile, "DEF(nop1, 1, 0)\n");
2905 fprintf(outfile, "DEF(nop2, 2, 0)\n");
2906 fprintf(outfile, "DEF(nop3, 3, 0)\n");
2907 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2908 const char *name;
2909 name = get_sym_name(sym);
2910 if (strstart(name, OP_PREFIX, NULL)) {
2911 gen_code(name, sym->st_value, sym->st_size, outfile, 2);
2912 }
2913 }
2914 } else if (out_type == OUT_GEN_OP) {
2915 /* generate gen_xxx functions */
2916 fprintf(outfile, "#include \"dyngen-op.h\"\n");
2917 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2918 const char *name;
2919 name = get_sym_name(sym);
2920 if (strstart(name, OP_PREFIX, NULL)) {
2921#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
2922 if (sym->st_shndx != text_shndx)
2923 error("invalid section for opcode (0x%x)", sym->st_shndx);
2924#endif
2925 gen_code(name, sym->st_value, sym->st_size, outfile, 0);
2926 }
2927 }
2928
2929 } else {
2930 /* generate big code generation switch */
2931
2932#ifdef HOST_ARM
2933 /* We need to know the size of all the ops so we can figure out when
2934 to emit constant pools. This must be consistent with opc.h. */
2935fprintf(outfile,
2936"static const uint32_t arm_opc_size[] = {\n"
2937" 0,\n" /* end */
2938" 0,\n" /* nop */
2939" 0,\n" /* nop1 */
2940" 0,\n" /* nop2 */
2941" 0,\n"); /* nop3 */
2942 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2943 const char *name;
2944 name = get_sym_name(sym);
2945 if (strstart(name, OP_PREFIX, NULL)) {
2946 fprintf(outfile, " %d,\n", sym->st_size);
2947 }
2948 }
2949fprintf(outfile,
2950"};\n");
2951#endif
2952
2953fprintf(outfile,
2954"int dyngen_code(uint8_t *gen_code_buf,\n"
2955" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
2956" const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n"
2957"{\n"
2958" uint8_t *gen_code_ptr;\n"
2959" const uint16_t *opc_ptr;\n"
2960" const uint32_t *opparam_ptr;\n");
2961
2962#ifdef HOST_ARM
2963/* Arm is tricky because it uses constant pools for loading immediate values.
2964 We assume (and require) each function is code followed by a constant pool.
2965 All the ops are small so this should be ok. For each op we figure
2966 out how much "spare" range we have in the load instructions. This allows
2967 us to insert subsequent ops in between the op and the constant pool,
2968 eliminating the neeed to jump around the pool.
2969
2970 We currently generate:
2971
2972 [ For this example we assume merging would move op1_pool out of range.
2973 In practice we should be able to combine many ops before the offset
2974 limits are reached. ]
2975 op1_code;
2976 op2_code;
2977 goto op3;
2978 op2_pool;
2979 op1_pool;
2980op3:
2981 op3_code;
2982 ret;
2983 op3_pool;
2984
2985 Ideally we'd put op1_pool before op2_pool, but that requires two passes.
2986 */
2987fprintf(outfile,
2988" uint8_t *last_gen_code_ptr = gen_code_buf;\n"
2989" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
2990" uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
2991/* Initialise the parmissible pool offset to an arbitary large value. */
2992" uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
2993#endif
2994#ifdef HOST_IA64
2995 {
2996 long addend, not_first = 0;
2997 unsigned long sym_idx;
2998 int index, max_index;
2999 const char *sym_name;
3000 EXE_RELOC *rel;
3001
3002 max_index = -1;
3003 for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
3004 sym_idx = ELF64_R_SYM(rel->r_info);
3005 sym_name = (strtab + symtab[sym_idx].st_name);
3006 if (strstart(sym_name, "__op_gen_label", NULL))
3007 continue;
3008 if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
3009 continue;
3010
3011 addend = rel->r_addend;
3012 index = get_plt_index(sym_name, addend);
3013 if (index <= max_index)
3014 continue;
3015 max_index = index;
3016 fprintf(outfile, " extern void %s(void);\n", sym_name);
3017 }
3018
3019 fprintf(outfile,
3020 " struct ia64_fixup *plt_fixes = NULL, "
3021 "*ltoff_fixes = NULL;\n"
3022 " static long plt_target[] = {\n\t");
3023
3024 max_index = -1;
3025 for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
3026 sym_idx = ELF64_R_SYM(rel->r_info);
3027 sym_name = (strtab + symtab[sym_idx].st_name);
3028 if (strstart(sym_name, "__op_gen_label", NULL))
3029 continue;
3030 if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
3031 continue;
3032
3033 addend = rel->r_addend;
3034 index = get_plt_index(sym_name, addend);
3035 if (index <= max_index)
3036 continue;
3037 max_index = index;
3038
3039 if (not_first)
3040 fprintf(outfile, ",\n\t");
3041 not_first = 1;
3042 if (addend)
3043 fprintf(outfile, "(long) &%s + %ld", sym_name, addend);
3044 else
3045 fprintf(outfile, "(long) &%s", sym_name);
3046 }
3047 fprintf(outfile, "\n };\n"
3048 " unsigned int plt_offset[%u] = { 0 };\n", max_index + 1);
3049 }
3050#endif
3051
3052fprintf(outfile,
3053"\n"
3054" gen_code_ptr = gen_code_buf;\n"
3055" opc_ptr = opc_buf;\n"
3056" opparam_ptr = opparam_buf;\n");
3057
3058 /* Generate prologue, if needed. */
3059
3060fprintf(outfile,
3061" for(;;) {\n");
3062
3063#ifdef HOST_ARM
3064/* Generate constant pool if needed */
3065fprintf(outfile,
3066" if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
3067" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
3068"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n"
3069" last_gen_code_ptr = gen_code_ptr;\n"
3070" arm_ldr_ptr = arm_ldr_table;\n"
3071" arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
3072" arm_pool_ptr = gen_code_ptr + 0x1000000;\n"
3073" }\n");
3074#endif
3075
3076fprintf(outfile,
3077" switch(*opc_ptr++) {\n");
3078
3079 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
3080 const char *name;
3081 name = get_sym_name(sym);
3082 if (strstart(name, OP_PREFIX, NULL)) {
3083#if 0
3084 printf("%4d: %s pos=0x%08x len=%d\n",
3085 i, name, sym->st_value, sym->st_size);
3086#endif
3087#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
3088 if (sym->st_shndx != text_shndx)
3089 error("invalid section for opcode (0x%x)", sym->st_shndx);
3090#endif
3091 gen_code(name, sym->st_value, sym->st_size, outfile, 1);
3092 }
3093 }
3094
3095fprintf(outfile,
3096" case INDEX_op_nop:\n"
3097" break;\n"
3098" case INDEX_op_nop1:\n"
3099" opparam_ptr++;\n"
3100" break;\n"
3101" case INDEX_op_nop2:\n"
3102" opparam_ptr += 2;\n"
3103" break;\n"
3104" case INDEX_op_nop3:\n"
3105" opparam_ptr += 3;\n"
3106" break;\n"
3107" default:\n"
3108" goto the_end;\n"
3109" }\n");
3110
3111
3112fprintf(outfile,
3113" }\n"
3114" the_end:\n"
3115);
3116#ifdef HOST_IA64
3117 fprintf(outfile,
3118 " {\n"
3119 " extern char code_gen_buffer[];\n"
3120 " ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
3121 "(uint64_t) code_gen_buffer + 2*(1<<20), plt_fixes,\n\t\t\t"
3122 "sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t"
3123 "plt_target, plt_offset);\n }\n");
3124#endif
3125
3126/* generate some code patching */
3127#ifdef HOST_ARM
3128fprintf(outfile,
3129"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
3130" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
3131"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");
3132#endif
3133 /* flush instruction cache */
3134 fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
3135
3136 fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
3137 fprintf(outfile, "}\n\n");
3138
3139 }
3140
3141 return 0;
3142}
3143
3144void usage(void)
3145{
3146 printf("dyngen (c) 2003 Fabrice Bellard\n"
3147 "usage: dyngen [-o outfile] [-c] objfile\n"
3148 "Generate a dynamic code generator from an object file\n"
3149 "-c output enum of operations\n"
3150 "-g output gen_op_xx() functions\n"
3151 );
3152 exit(1);
3153}
3154
3155int main(int argc, char **argv)
3156{
3157 int c, out_type;
3158 const char *filename, *outfilename;
3159 FILE *outfile;
3160
3161 outfilename = "out.c";
3162 out_type = OUT_CODE;
3163 for(;;) {
3164 c = getopt(argc, argv, "ho:cg");
3165 if (c == -1)
3166 break;
3167 switch(c) {
3168 case 'h':
3169 usage();
3170 break;
3171 case 'o':
3172 outfilename = optarg;
3173 break;
3174 case 'c':
3175 out_type = OUT_INDEX_OP;
3176 break;
3177 case 'g':
3178 out_type = OUT_GEN_OP;
3179 break;
3180 }
3181 }
3182 if (optind >= argc)
3183 usage();
3184 filename = argv[optind];
3185 outfile = fopen(outfilename, "w");
3186 if (!outfile)
3187 error("could not open '%s'", outfilename);
3188
3189 load_object(filename);
3190 gen_file(outfile, out_type);
3191 fclose(outfile);
3192 return 0;
3193}
3194
3195/* bird added: */
3196/*
3197 * Local Variables:
3198 * mode: c
3199 * c-file-style: k&r
3200 * c-basic-offset: 4
3201 * tab-width: 4
3202 * indent-tabs-mode: t
3203 * End:
3204 */
3205
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette