VirtualBox

source: vbox/trunk/src/recompiler/new/dyngen.c@ 1631

Last change on this file since 1631 was 1631, checked in by vboxsync, 18 years ago

warnings

  • Property svn:eol-style set to native
File size: 100.4 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 (sca_rel->r_pcrel ...) */
1113 // return NULL;
1114
1115 /* find_reloc_name_given_its_address doesn't do the right thing here, so
1116 we locate the section and use find_sym_with_value_and_sec_number */
1117 for (i = 0; i < segment->nsects ; i++) {
1118 if ((uintptr_t)sca_rel->r_value - section_hdr[i].addr < section_hdr[i].size) {
1119 int off = 0;
1120 name = find_sym_with_value_and_sec_number(sca_rel->r_value, i + 1, &off);
1121 if (name) {
1122 *addend += off;
1123 break;
1124 }
1125 }
1126 }
1127 if (!name)
1128 error("Fully implement R_SCATTERED! r_address=%#x r_type=%#x r_length=%d r_pcrel=%d r_value=%#x\n",
1129 (int)sca_rel->r_address, sca_rel->r_type, sca_rel->r_length, sca_rel->r_pcrel, sca_rel->r_value);
1130 }
1131 else
1132 {
1133 /* ignore debug syms (paranoia). */
1134 if (symtab[rel->r_symbolnum].n_type & N_STAB)
1135 return NULL;
1136
1137 /* ignore internal pc relative fixups where both ends are in the text section. */
1138 if (rel->r_pcrel && !rel->r_extern && rel->r_symbolnum == 1 /* ASSUMES text */)
1139 return NULL;
1140
1141 /* get the addend, it is in the instruction stream. */
1142 *addend = *(int32_t *)(text + rel->r_address);
1143 if (rel->r_pcrel)
1144 *addend += rel->r_address;
1145
1146 /* external fixups are easy. */
1147 if (rel->r_extern)
1148 {
1149 if (rel->r_symbolnum >= nb_syms)
1150 error("rel->r_symbolnum (%d) >= nb_syms (%d)", rel->r_symbolnum, nb_syms);
1151 name = get_sym_name(&symtab[rel->r_symbolnum]);
1152 }
1153 else
1154 {
1155 /* sanity checks. */
1156 if (rel->r_symbolnum == 0xffffff)
1157 return NULL;
1158 if (rel->r_symbolnum > segment->nsects)
1159 error("sectnum (%d) > segment->nsects (%d)", rel->r_symbolnum, segment->nsects);
1160 if (rel->r_pcrel)
1161 error("internal pcrel fixups not implemented");
1162
1163 /* search for the symbol. */
1164 name = find_sym_with_value_and_sec_number(*addend, rel->r_symbolnum, addend);
1165 }
1166 }
1167 return name;
1168}
1169#endif /* HOST_I386 */
1170
1171/* Used by dyngen common code */
1172static const char * get_rel_sym_name(EXE_RELOC * rel)
1173{
1174 int sslide;
1175#if defined(HOST_I386)
1176 return get_rel_sym_name_and_addend(rel, &sslide);
1177#else
1178 return get_reloc_name( rel, &sslide);
1179#endif
1180}
1181
1182/* Used by dyngen common code */
1183static host_ulong get_rel_offset(EXE_RELOC *rel)
1184{
1185 struct scattered_relocation_info * sca_rel = (struct scattered_relocation_info*)rel;
1186 if(R_SCATTERED & rel->r_address)
1187 return sca_rel->r_address;
1188 else
1189 return rel->r_address;
1190}
1191
1192/* load a mach-o object file */
1193int load_object(const char *filename)
1194{
1195 int fd;
1196 unsigned int offset_to_segment = 0;
1197 unsigned int offset_to_dysymtab = 0;
1198 unsigned int offset_to_symtab = 0;
1199 struct load_command lc;
1200 unsigned int i, j;
1201 EXE_SYM *sym;
1202 struct nlist *syment;
1203
1204 fd = open(filename, O_RDONLY
1205#ifdef O_BINARY
1206 | O_BINARY
1207#endif
1208 );
1209 if (fd < 0)
1210 error("can't open file '%s'", filename);
1211
1212 /* Read Mach header. */
1213 if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
1214 error("unable to read file header");
1215
1216 /* Check Mach identification. */
1217 if (!check_mach_header(mach_hdr)) {
1218 error("bad Mach header");
1219 }
1220
1221#if defined(HOST_PPC)
1222 if (mach_hdr.cputype != CPU_TYPE_POWERPC)
1223#elif defined(HOST_I386)
1224 if (mach_hdr.cputype != CPU_TYPE_X86)
1225#else
1226#error unsupported host
1227#endif
1228 error("Unsupported CPU");
1229
1230 if (mach_hdr.filetype != MH_OBJECT)
1231 error("Unsupported Mach Object");
1232
1233 /* read segment headers */
1234 for(i=0, j=sizeof(mach_hdr); i<mach_hdr.ncmds ; i++)
1235 {
1236 if(read(fd, &lc, sizeof(struct load_command)) != sizeof(struct load_command))
1237 error("unable to read load_command");
1238 if(lc.cmd == LC_SEGMENT)
1239 {
1240 offset_to_segment = j;
1241 lseek(fd, offset_to_segment, SEEK_SET);
1242 segment = malloc(sizeof(struct segment_command));
1243 if(read(fd, segment, sizeof(struct segment_command)) != sizeof(struct segment_command))
1244 error("unable to read LC_SEGMENT");
1245 }
1246 if(lc.cmd == LC_DYSYMTAB)
1247 {
1248 offset_to_dysymtab = j;
1249 lseek(fd, offset_to_dysymtab, SEEK_SET);
1250 dysymtabcmd = malloc(sizeof(struct dysymtab_command));
1251 if(read(fd, dysymtabcmd, sizeof(struct dysymtab_command)) != sizeof(struct dysymtab_command))
1252 error("unable to read LC_DYSYMTAB");
1253 }
1254 if(lc.cmd == LC_SYMTAB)
1255 {
1256 offset_to_symtab = j;
1257 lseek(fd, offset_to_symtab, SEEK_SET);
1258 symtabcmd = malloc(sizeof(struct symtab_command));
1259 if(read(fd, symtabcmd, sizeof(struct symtab_command)) != sizeof(struct symtab_command))
1260 error("unable to read LC_SYMTAB");
1261 }
1262 j+=lc.cmdsize;
1263
1264 lseek(fd, j, SEEK_SET);
1265 }
1266
1267 if(!segment)
1268 error("unable to find LC_SEGMENT");
1269
1270 /* read section headers */
1271 section_hdr = load_data(fd, offset_to_segment + sizeof(struct segment_command), segment->nsects * sizeof(struct section));
1272
1273 /* read all section data */
1274 sdata = (uint8_t **)malloc(sizeof(void *) * segment->nsects);
1275 memset(sdata, 0, sizeof(void *) * segment->nsects);
1276
1277 /* Load the data in section data */
1278 for(i = 0; i < segment->nsects; i++) {
1279 sdata[i] = load_data(fd, section_hdr[i].offset, section_hdr[i].size);
1280 }
1281
1282 /* text section */
1283 text_sec_hdr = find_mach_sec_hdr(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
1284 i = find_mach_sec_index(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
1285 if (i == -1 || !text_sec_hdr)
1286 error("could not find __TEXT,__text section");
1287 text = sdata[i];
1288
1289 /* Make sure dysym was loaded */
1290 if(!(int)dysymtabcmd)
1291 error("could not find __DYSYMTAB segment");
1292
1293 /* read the table of content of the indirect sym */
1294 tocdylib = load_data( fd, dysymtabcmd->indirectsymoff, dysymtabcmd->nindirectsyms * sizeof(uint32_t) );
1295
1296 /* Make sure symtab was loaded */
1297 if(!(int)symtabcmd)
1298 error("could not find __SYMTAB segment");
1299 nb_syms = symtabcmd->nsyms;
1300
1301 symtab_std = load_data(fd, symtabcmd->symoff, symtabcmd->nsyms * sizeof(struct nlist));
1302 strtab = load_data(fd, symtabcmd->stroff, symtabcmd->strsize);
1303
1304 symtab = malloc(sizeof(EXE_SYM) * nb_syms);
1305
1306 /* Now transform the symtab, to an extended version, with the sym size, and the C name */
1307 for(i = 0, sym = symtab, syment = symtab_std; i < nb_syms; i++, sym++, syment++) {
1308 struct nlist *sym_cur, *sym_next = 0;
1309 unsigned int j;
1310 memset(sym, 0, sizeof(*sym));
1311
1312 if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
1313 continue;
1314
1315 memcpy(sym, syment, sizeof(*syment));
1316
1317#if defined(VBOX)
1318 /* don't bother calcing size of internal symbol local symbols. */
1319 if (strstart(find_str_by_index(sym->n_un.n_strx), ".L", NULL)) {
1320 sym->st_size = 0;
1321 continue;
1322 }
1323#endif
1324
1325 /* Find the following symbol in order to get the current symbol size */
1326 for (j = 0, sym_cur = symtab_std; j < nb_syms; j++, sym_cur++) {
1327 if ( sym_cur->n_sect != /*syment->n_sect*/ 1
1328 || (sym_cur->n_type & N_STAB)
1329 || sym_cur->n_value <= syment->n_value)
1330 continue;
1331 if ( sym_next
1332 && sym_next->n_value <= sym_cur->n_value)
1333 continue;
1334#if defined(HOST_I386)
1335 /* Ignore local labels (.Lxxx). */
1336 if (strstart(find_str_by_index(sym_cur->n_un.n_strx), ".L", NULL))
1337 continue;
1338#endif
1339 /* a good one */
1340 sym_next = sym_cur;
1341 }
1342 if(sym_next)
1343 sym->st_size = sym_next->n_value - sym->st_value;
1344 else
1345 sym->st_size = text_sec_hdr->size - sym->st_value;
1346 }
1347
1348 /* Find Reloc */
1349 relocs = load_data(fd, text_sec_hdr->reloff, text_sec_hdr->nreloc * sizeof(struct relocation_info));
1350 nb_relocs = text_sec_hdr->nreloc;
1351
1352 close(fd);
1353 return 0;
1354}
1355
1356#endif /* CONFIG_FORMAT_MACH */
1357
1358#ifdef CONFIG_FORMAT_AOUT
1359
1360struct exec *aout_hdr;
1361struct nlist *symtab_std;
1362char *strtab;
1363
1364
1365/* Utility functions */
1366
1367static inline char *find_str_by_index(int index)
1368{
1369 return strtab+index;
1370}
1371
1372/* Used by dyngen common code */
1373static char *get_sym_name(EXE_SYM *sym)
1374{
1375 char *name = find_str_by_index(sym->n_un.n_strx);
1376
1377 if (sym->n_type & N_STAB) /* Debug symbols are ignored */
1378 return "debug";
1379 if (name && name[0] == '_')
1380 return name + 1;
1381 return name;
1382}
1383
1384static int type_to_sec_number(unsigned type)
1385{
1386 switch (type)
1387 {
1388 case 0: case 0 |N_EXT: case N_WEAKU: return N_UNDF;
1389 case N_ABS: case N_ABS |N_EXT: case N_WEAKA: return N_ABS;
1390 case N_TEXT: case N_TEXT|N_EXT: case N_WEAKT: return N_TEXT;
1391 case N_DATA: case N_DATA|N_EXT: case N_WEAKD: return N_DATA;
1392 case N_BSS: case N_BSS |N_EXT: case N_WEAKB: return N_BSS;
1393 case N_SETA: case N_SETA|N_EXT: return N_SETA;
1394 case N_SETT: case N_SETT|N_EXT: return N_SETT;
1395 case N_SETD: case N_SETD|N_EXT: return N_SETD;
1396
1397 default:
1398 return type;
1399 }
1400}
1401
1402/* find a sym name given its value, in a section number */
1403static const char *find_sym_with_value_and_sec_number(long value, int sec, int *offset)
1404{
1405 int i, ret = -1;
1406
1407 for (i = 0; i < nb_syms; i++) {
1408 if ( !(symtab[i].n_type & N_STAB)
1409 && type_to_sec_number(symtab[i].n_type) == sec
1410 && symtab[i].st_value <= value
1411 && ( ret < 0
1412 || symtab[i].st_value >= symtab[ret].st_value)) {
1413 ret = i;
1414 }
1415 }
1416 if (ret < 0) {
1417 *offset = 0;
1418 return 0;
1419 }
1420 *offset = value - symtab[ret].st_value;
1421 return get_sym_name(&symtab[ret]);
1422}
1423
1424static const char *get_rel_sym_name_and_addend(EXE_RELOC *rel, int *sslide)
1425{
1426 int sec;
1427 int off;
1428
1429 *sslide = 0;
1430
1431 if (rel->r_extern)
1432 {
1433 /* ignore debug sym */
1434 if (symtab[rel->r_symbolnum].n_type & N_STAB)
1435 return 0;
1436
1437 /* The intruction contains the addend. */
1438 off = *(uint32_t *)(text + rel->r_address);
1439 if (rel->r_pcrel)
1440 off += rel->r_address;
1441 *sslide = off;
1442 return get_sym_name(&symtab[rel->r_symbolnum]);
1443 }
1444 if (rel->r_symbolnum == 0xffffff)
1445 return 0;
1446
1447 sec = rel->r_symbolnum & ~N_EXT;
1448 /* sanity */
1449 switch (sec)
1450 {
1451 case N_TEXT: case N_DATA: case N_BSS: case N_ABS: break;
1452 default: error("invalid section %d", sec);
1453 }
1454
1455 /* The intruction contains the addend. */
1456 off = *(uint32_t *)(text + rel->r_address);
1457 if (rel->r_pcrel)
1458 off += rel->r_address;
1459
1460 /* search it in the full symbol list, if not found */
1461 return find_sym_with_value_and_sec_number(off, sec, sslide);
1462}
1463
1464/* Used by dyngen common code */
1465static const char * get_rel_sym_name(EXE_RELOC *rel)
1466{
1467 int ignored;
1468 return get_rel_sym_name_and_addend(rel, &ignored);
1469}
1470
1471/* Used by dyngen common code */
1472static host_ulong get_rel_offset(EXE_RELOC *rel)
1473{
1474 return rel->r_address;
1475}
1476
1477/* load an a.out object file */
1478int load_object(const char *filename)
1479{
1480 FILE *pf;
1481 long file_size;
1482 unsigned i;
1483 EXE_SYM *dst_sym;
1484 struct nlist *src_sym;
1485
1486 /*
1487 * Open the file and validate the header.
1488 */
1489 pf = fopen(filename, "rb");
1490 if (!pf)
1491 error("can't open file '%s'", filename);
1492
1493 /* we're optimistic, read the entire file first. */
1494 if (fseek(pf, 0, SEEK_END) != 0)
1495 error("Input file '%s' is not seekable", filename);
1496 file_size = ftell(pf);
1497 fseek(pf, 0L, SEEK_SET);
1498
1499 aout_hdr = malloc(file_size + 1);
1500 if (!aout_hdr)
1501 error("malloc(%ld) failed", file_size + 1);
1502 if (fread(aout_hdr, 1, file_size, pf) != file_size)
1503 error("error reading '%s'", filename);
1504 fclose(pf);
1505
1506 /* validate the header. */
1507 if (N_MAGIC(*aout_hdr) != OMAGIC)
1508 error("unknown magic: %lo", N_MAGIC(*aout_hdr));
1509 if (N_MACHTYPE(*aout_hdr) != M_386 && N_MACHTYPE(*aout_hdr) != 0)
1510 error("unsupported machtype: %d", N_MACHTYPE(*aout_hdr));
1511
1512 /* setup globals. */
1513 strtab = (char *)((uint8_t *)aout_hdr + N_STROFF(*aout_hdr));
1514 symtab_std = (struct nlist *)((uint8_t *)aout_hdr + N_SYMOFF(*aout_hdr));
1515
1516 relocs = (struct relocation_info *)((uint8_t *)aout_hdr + N_TRELOFF(*aout_hdr));
1517 nb_syms = aout_hdr->a_syms / sizeof(struct nlist);
1518 text_shndx = 1;
1519 text = (uint8_t *)aout_hdr + N_TXTOFF(*aout_hdr);
1520 nb_relocs = aout_hdr->a_trsize / sizeof(relocs[0]);
1521
1522 /*
1523 * Now transform the symtab, to an extended version, with the sym size, and the C name
1524 */
1525 src_sym = symtab_std;
1526 dst_sym = symtab = malloc(sizeof(EXE_SYM) * nb_syms);
1527 if (!dst_sym)
1528 error("malloc(%zd) failed", sizeof(EXE_SYM) * nb_syms);
1529 for (i = 0; i < nb_syms; i++, src_sym++, dst_sym++) {
1530 struct nlist *sym_next = NULL;
1531 struct nlist *sym_cur;
1532 unsigned sec;
1533 unsigned j;
1534
1535 /* copy the symbol and find the name. */
1536 dst_sym->n_un.n_strx = src_sym->n_un.n_strx;
1537 dst_sym->n_type = src_sym->n_type;
1538 dst_sym->n_other = src_sym->n_other;
1539 dst_sym->n_desc = src_sym->n_desc;
1540 dst_sym->st_value = src_sym->n_value;
1541 dst_sym->st_size = 0;
1542 if (src_sym->n_type & N_STAB)
1543 continue; /* skip debug symbols. */
1544
1545 /* Find the following symbol in order to get the current symbol size */
1546 sec = type_to_sec_number(dst_sym->n_type);
1547 for (j = 0, sym_cur = symtab_std; j < nb_syms; j++, sym_cur++) {
1548 if ( type_to_sec_number(sym_cur->n_type) != sec
1549 || (sym_cur->n_type & N_STAB)
1550 || sym_cur->n_value <= dst_sym->st_value)
1551 continue;
1552 if ( sym_next
1553 && sym_next->n_value <= sym_cur->n_value)
1554 continue;
1555 /* good one */
1556 sym_next = sym_cur;
1557 }
1558 if (sym_next)
1559 dst_sym->st_size = sym_next->n_value - dst_sym->st_value;
1560 else
1561 dst_sym->st_size = aout_hdr->a_text - dst_sym->st_value;
1562 }
1563
1564 return 0;
1565}
1566
1567#endif /* CONFIG_FORMAT_AOUT */
1568
1569
1570void get_reloc_expr(char *name, int name_size, const char *sym_name)
1571{
1572 const char *p;
1573
1574 if (strstart(sym_name, "__op_param", &p)) {
1575 snprintf(name, name_size, "param%s", p);
1576 } else if (strstart(sym_name, "__op_gen_label", &p)) {
1577 snprintf(name, name_size, "gen_labels[param%s]", p);
1578 } else {
1579#ifdef HOST_SPARC
1580 if (sym_name[0] == '.')
1581 snprintf(name, name_size,
1582 "(long)(&__dot_%s)",
1583 sym_name + 1);
1584 else
1585#endif
1586 snprintf(name, name_size, "(long)(&%s)", sym_name);
1587 }
1588}
1589
1590#ifdef HOST_IA64
1591
1592#define PLT_ENTRY_SIZE 16 /* 1 bundle containing "brl" */
1593
1594struct plt_entry {
1595 struct plt_entry *next;
1596 const char *name;
1597 unsigned long addend;
1598} *plt_list;
1599
1600static int
1601get_plt_index (const char *name, unsigned long addend)
1602{
1603 struct plt_entry *plt, *prev= NULL;
1604 int index = 0;
1605
1606 /* see if we already have an entry for this target: */
1607 for (plt = plt_list; plt; ++index, prev = plt, plt = plt->next)
1608 if (strcmp(plt->name, name) == 0 && plt->addend == addend)
1609 return index;
1610
1611 /* nope; create a new PLT entry: */
1612
1613 plt = malloc(sizeof(*plt));
1614 if (!plt) {
1615 perror("malloc");
1616 exit(1);
1617 }
1618 memset(plt, 0, sizeof(*plt));
1619 plt->name = strdup(name);
1620 plt->addend = addend;
1621
1622 /* append to plt-list: */
1623 if (prev)
1624 prev->next = plt;
1625 else
1626 plt_list = plt;
1627 return index;
1628}
1629
1630#endif
1631
1632#ifdef HOST_ARM
1633
1634int arm_emit_ldr_info(const char *name, unsigned long start_offset,
1635 FILE *outfile, uint8_t *p_start, uint8_t *p_end,
1636 ELF_RELOC *relocs, int nb_relocs)
1637{
1638 uint8_t *p;
1639 uint32_t insn;
1640 int offset, min_offset, pc_offset, data_size, spare, max_pool;
1641 uint8_t data_allocated[1024];
1642 unsigned int data_index;
1643 int type;
1644
1645 memset(data_allocated, 0, sizeof(data_allocated));
1646
1647 p = p_start;
1648 min_offset = p_end - p_start;
1649 spare = 0x7fffffff;
1650 while (p < p_start + min_offset) {
1651 insn = get32((uint32_t *)p);
1652 /* TODO: Armv5e ldrd. */
1653 /* TODO: VFP load. */
1654 if ((insn & 0x0d5f0000) == 0x051f0000) {
1655 /* ldr reg, [pc, #im] */
1656 offset = insn & 0xfff;
1657 if (!(insn & 0x00800000))
1658 offset = -offset;
1659 max_pool = 4096;
1660 type = 0;
1661 } else if ((insn & 0x0e5f0f00) == 0x0c1f0100) {
1662 /* FPA ldf. */
1663 offset = (insn & 0xff) << 2;
1664 if (!(insn & 0x00800000))
1665 offset = -offset;
1666 max_pool = 1024;
1667 type = 1;
1668 } else if ((insn & 0x0fff0000) == 0x028f0000) {
1669 /* Some gcc load a doubleword immediate with
1670 add regN, pc, #imm
1671 ldmia regN, {regN, regM}
1672 Hope and pray the compiler never generates somethin like
1673 add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */
1674 int r;
1675
1676 r = (insn & 0xf00) >> 7;
1677 offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r));
1678 max_pool = 1024;
1679 type = 2;
1680 } else {
1681 max_pool = 0;
1682 type = -1;
1683 }
1684 if (type >= 0) {
1685 /* PC-relative load needs fixing up. */
1686 if (spare > max_pool - offset)
1687 spare = max_pool - offset;
1688 if ((offset & 3) !=0)
1689 error("%s:%04x: pc offset must be 32 bit aligned",
1690 name, start_offset + p - p_start);
1691 if (offset < 0)
1692 error("%s:%04x: Embedded literal value",
1693 name, start_offset + p - p_start);
1694 pc_offset = p - p_start + offset + 8;
1695 if (pc_offset <= (p - p_start) ||
1696 pc_offset >= (p_end - p_start))
1697 error("%s:%04x: pc offset must point inside the function code",
1698 name, start_offset + p - p_start);
1699 if (pc_offset < min_offset)
1700 min_offset = pc_offset;
1701 if (outfile) {
1702 /* The intruction position */
1703 fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
1704 p - p_start);
1705 /* The position of the constant pool data. */
1706 data_index = ((p_end - p_start) - pc_offset) >> 2;
1707 fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n",
1708 data_index);
1709 fprintf(outfile, " arm_ldr_ptr->type = %d;\n", type);
1710 fprintf(outfile, " arm_ldr_ptr++;\n");
1711 }
1712 }
1713 p += 4;
1714 }
1715
1716 /* Copy and relocate the constant pool data. */
1717 data_size = (p_end - p_start) - min_offset;
1718 if (data_size > 0 && outfile) {
1719 spare += min_offset;
1720 fprintf(outfile, " arm_data_ptr -= %d;\n", data_size >> 2);
1721 fprintf(outfile, " arm_pool_ptr -= %d;\n", data_size);
1722 fprintf(outfile, " if (arm_pool_ptr > gen_code_ptr + %d)\n"
1723 " arm_pool_ptr = gen_code_ptr + %d;\n",
1724 spare, spare);
1725
1726 data_index = 0;
1727 for (pc_offset = min_offset;
1728 pc_offset < p_end - p_start;
1729 pc_offset += 4) {
1730
1731 ELF_RELOC *rel;
1732 int i, addend, type;
1733 const char *sym_name;
1734 char relname[1024];
1735
1736 /* data value */
1737 addend = get32((uint32_t *)(p_start + pc_offset));
1738 relname[0] = '\0';
1739 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
1740 if (rel->r_offset == (pc_offset + start_offset)) {
1741 sym_name = get_rel_sym_name(rel);
1742 /* the compiler leave some unnecessary references to the code */
1743 get_reloc_expr(relname, sizeof(relname), sym_name);
1744 type = ELF32_R_TYPE(rel->r_info);
1745 if (type != R_ARM_ABS32)
1746 error("%s: unsupported data relocation", name);
1747 break;
1748 }
1749 }
1750 fprintf(outfile, " arm_data_ptr[%d] = 0x%x",
1751 data_index, addend);
1752 if (relname[0] != '\0')
1753 fprintf(outfile, " + %s", relname);
1754 fprintf(outfile, ";\n");
1755
1756 data_index++;
1757 }
1758 }
1759
1760 if (p == p_start)
1761 goto arm_ret_error;
1762 p -= 4;
1763 insn = get32((uint32_t *)p);
1764 /* The last instruction must be an ldm instruction. There are several
1765 forms generated by gcc:
1766 ldmib sp, {..., pc} (implies a sp adjustment of +4)
1767 ldmia sp, {..., pc}
1768 ldmea fp, {..., pc} */
1769 if ((insn & 0xffff8000) == 0xe99d8000) {
1770 if (outfile) {
1771 fprintf(outfile,
1772 " *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n",
1773 p - p_start);
1774 }
1775 p += 4;
1776 } else if ((insn & 0xffff8000) != 0xe89d8000
1777 && (insn & 0xffff8000) != 0xe91b8000) {
1778 arm_ret_error:
1779 if (!outfile)
1780 printf("%s: invalid epilog\n", name);
1781 }
1782 return p - p_start;
1783}
1784#endif
1785
1786
1787#define MAX_ARGS 3
1788
1789/* generate op code */
1790void gen_code(const char *name, host_ulong offset, host_ulong size,
1791 FILE *outfile, int gen_switch)
1792{
1793 int copy_size = 0;
1794 uint8_t *p_start, *p_end;
1795 host_ulong start_offset;
1796 int nb_args, i, n;
1797 uint8_t args_present[MAX_ARGS];
1798 const char *sym_name, *p;
1799 EXE_RELOC *rel;
1800
1801 /* Compute exact size excluding prologue and epilogue instructions.
1802 * Increment start_offset to skip epilogue instructions, then compute
1803 * copy_size the indicate the size of the remaining instructions (in
1804 * bytes).
1805 */
1806 p_start = text + offset;
1807 p_end = p_start + size;
1808 start_offset = offset;
1809#if defined(HOST_I386) || defined(HOST_X86_64)
1810#if defined(CONFIG_FORMAT_COFF) || defined(CONFIG_FORMAT_AOUT) || defined(CONFIG_FORMAT_MACH)
1811 {
1812 uint8_t *p;
1813 p = p_end - 1;
1814 if (p == p_start)
1815 error("empty code for %s", name);
1816 while (*p != 0xc3) {
1817 p--;
1818 if (p <= p_start)
1819 error("ret or jmp expected at the end of %s", name);
1820 }
1821 copy_size = p - p_start;
1822 }
1823#else
1824 {
1825 int len;
1826 len = p_end - p_start;
1827 if (len == 0)
1828 error("empty code for %s", name);
1829 if (p_end[-1] == 0xc3) {
1830 len--;
1831 } else {
1832 error("ret or jmp expected at the end of %s", name);
1833 }
1834 copy_size = len;
1835 }
1836#endif
1837#elif defined(HOST_PPC)
1838 {
1839 uint8_t *p;
1840 p = (void *)(p_end - 4);
1841 if (p == p_start)
1842 error("empty code for %s", name);
1843 if (get32((uint32_t *)p) != 0x4e800020)
1844 error("blr expected at the end of %s", name);
1845 copy_size = p - p_start;
1846 }
1847#elif defined(HOST_S390)
1848 {
1849 uint8_t *p;
1850 p = (void *)(p_end - 2);
1851 if (p == p_start)
1852 error("empty code for %s", name);
1853 if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
1854 error("br %%r14 expected at the end of %s", name);
1855 copy_size = p - p_start;
1856 }
1857#elif defined(HOST_ALPHA)
1858 {
1859 uint8_t *p;
1860 p = p_end - 4;
1861#if 0
1862 /* XXX: check why it occurs */
1863 if (p == p_start)
1864 error("empty code for %s", name);
1865#endif
1866 if (get32((uint32_t *)p) != 0x6bfa8001)
1867 error("ret expected at the end of %s", name);
1868 copy_size = p - p_start;
1869 }
1870#elif defined(HOST_IA64)
1871 {
1872 uint8_t *p;
1873 p = (void *)(p_end - 4);
1874 if (p == p_start)
1875 error("empty code for %s", name);
1876 /* br.ret.sptk.many b0;; */
1877 /* 08 00 84 00 */
1878 if (get32((uint32_t *)p) != 0x00840008)
1879 error("br.ret.sptk.many b0;; expected at the end of %s", name);
1880 copy_size = p_end - p_start;
1881 }
1882#elif defined(HOST_SPARC)
1883 {
1884#define INSN_SAVE 0x9de3a000
1885#define INSN_RET 0x81c7e008
1886#define INSN_RETL 0x81c3e008
1887#define INSN_RESTORE 0x81e80000
1888#define INSN_RETURN 0x81cfe008
1889#define INSN_NOP 0x01000000
1890#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
1891#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
1892
1893 uint32_t start_insn, end_insn1, end_insn2;
1894 uint8_t *p;
1895 p = (void *)(p_end - 8);
1896 if (p <= p_start)
1897 error("empty code for %s", name);
1898 start_insn = get32((uint32_t *)(p_start + 0x0));
1899 end_insn1 = get32((uint32_t *)(p + 0x0));
1900 end_insn2 = get32((uint32_t *)(p + 0x4));
1901 if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1902 (start_insn & ~0x1fff) == INSN_ADD_SP) {
1903 p_start += 0x4;
1904 start_offset += 0x4;
1905 if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
1906 /* SPARC v7: ret; restore; */ ;
1907 else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
1908 /* SPARC v9: return; nop; */ ;
1909 else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
1910 /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
1911 else
1912
1913 error("ret; restore; not found at end of %s", name);
1914 } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1915 ;
1916 } else {
1917 error("No save at the beginning of %s", name);
1918 }
1919#if 0
1920 /* Skip a preceeding nop, if present. */
1921 if (p > p_start) {
1922 skip_insn = get32((uint32_t *)(p - 0x4));
1923 if (skip_insn == INSN_NOP)
1924 p -= 4;
1925 }
1926#endif
1927 copy_size = p - p_start;
1928 }
1929#elif defined(HOST_SPARC64)
1930 {
1931#define INSN_SAVE 0x9de3a000
1932#define INSN_RET 0x81c7e008
1933#define INSN_RETL 0x81c3e008
1934#define INSN_RESTORE 0x81e80000
1935#define INSN_RETURN 0x81cfe008
1936#define INSN_NOP 0x01000000
1937#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
1938#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
1939
1940 uint32_t start_insn, end_insn1, end_insn2, skip_insn;
1941 uint8_t *p;
1942 p = (void *)(p_end - 8);
1943#if 0
1944 /* XXX: check why it occurs */
1945 if (p <= p_start)
1946 error("empty code for %s", name);
1947#endif
1948 start_insn = get32((uint32_t *)(p_start + 0x0));
1949 end_insn1 = get32((uint32_t *)(p + 0x0));
1950 end_insn2 = get32((uint32_t *)(p + 0x4));
1951 if (((start_insn & ~0x1fff) == INSN_SAVE) ||
1952 (start_insn & ~0x1fff) == INSN_ADD_SP) {
1953 p_start += 0x4;
1954 start_offset += 0x4;
1955 if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
1956 /* SPARC v7: ret; restore; */ ;
1957 else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
1958 /* SPARC v9: return; nop; */ ;
1959 else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
1960 /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
1961 else
1962
1963 error("ret; restore; not found at end of %s", name);
1964 } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
1965 ;
1966 } else {
1967 error("No save at the beginning of %s", name);
1968 }
1969
1970 /* Skip a preceeding nop, if present. */
1971 if (p > p_start) {
1972 skip_insn = get32((uint32_t *)(p - 0x4));
1973 if (skip_insn == 0x01000000)
1974 p -= 4;
1975 }
1976
1977 copy_size = p - p_start;
1978 }
1979#elif defined(HOST_ARM)
1980 {
1981 uint32_t insn;
1982
1983 if ((p_end - p_start) <= 16)
1984 error("%s: function too small", name);
1985 if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
1986 (get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 ||
1987 get32((uint32_t *)(p_start + 8)) != 0xe24cb004)
1988 error("%s: invalid prolog", name);
1989 p_start += 12;
1990 start_offset += 12;
1991 insn = get32((uint32_t *)p_start);
1992 if ((insn & 0xffffff00) == 0xe24dd000) {
1993 /* Stack adjustment. Assume op uses the frame pointer. */
1994 p_start -= 4;
1995 start_offset -= 4;
1996 }
1997 copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
1998 relocs, nb_relocs);
1999 }
2000#elif defined(HOST_M68K)
2001 {
2002 uint8_t *p;
2003 p = (void *)(p_end - 2);
2004 if (p == p_start)
2005 error("empty code for %s", name);
2006 // remove NOP's, probably added for alignment
2007 while ((get16((uint16_t *)p) == 0x4e71) &&
2008 (p>p_start))
2009 p -= 2;
2010 if (get16((uint16_t *)p) != 0x4e75)
2011 error("rts expected at the end of %s", name);
2012 copy_size = p - p_start;
2013 }
2014#else
2015#error unsupported CPU
2016#endif
2017
2018 /* compute the number of arguments by looking at the relocations */
2019 for(i = 0;i < MAX_ARGS; i++)
2020 args_present[i] = 0;
2021
2022 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2023 host_ulong offset = get_rel_offset(rel);
2024 if (offset >= start_offset &&
2025 offset < start_offset + (p_end - p_start)) {
2026 sym_name = get_rel_sym_name(rel);
2027 if(!sym_name)
2028 continue;
2029 if (strstart(sym_name, "__op_param", &p) ||
2030 strstart(sym_name, "__op_gen_label", &p)) {
2031 n = strtoul(p, NULL, 10);
2032 if (n > MAX_ARGS)
2033 error("too many arguments in %s", name);
2034 args_present[n - 1] = 1;
2035 }
2036 }
2037 }
2038
2039 nb_args = 0;
2040 while (nb_args < MAX_ARGS && args_present[nb_args])
2041 nb_args++;
2042 for(i = nb_args; i < MAX_ARGS; i++) {
2043 if (args_present[i])
2044 error("inconsistent argument numbering in %s", name);
2045 }
2046
2047 if (gen_switch == 2) {
2048 fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
2049 } else if (gen_switch == 1) {
2050
2051 /* output C code */
2052 fprintf(outfile, "case INDEX_%s: {\n", name);
2053 if (nb_args > 0) {
2054 fprintf(outfile, " long ");
2055 for(i = 0; i < nb_args; i++) {
2056 if (i != 0)
2057 fprintf(outfile, ", ");
2058 fprintf(outfile, "param%d", i + 1);
2059 }
2060 fprintf(outfile, ";\n");
2061 }
2062#if defined(HOST_IA64)
2063 fprintf(outfile, " extern char %s;\n", name);
2064#else
2065 fprintf(outfile, " extern void %s();\n", name);
2066#endif
2067
2068 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2069 host_ulong offset = get_rel_offset(rel);
2070 if (offset >= start_offset &&
2071 offset < start_offset + (p_end - p_start)) {
2072 sym_name = get_rel_sym_name(rel);
2073 if(!sym_name)
2074 continue;
2075 if (*sym_name &&
2076#ifdef VBOX
2077 !strstart(sym_name, "remR3PhysWrite", NULL) &&
2078 !strstart(sym_name, "remR3PhysRead", NULL) &&
2079#endif
2080 !strstart(sym_name, "__op_param", NULL) &&
2081 !strstart(sym_name, "__op_jmp", NULL) &&
2082 !strstart(sym_name, "__op_gen_label", NULL)) {
2083#if defined(HOST_SPARC)
2084 if (sym_name[0] == '.') {
2085 fprintf(outfile,
2086 "extern char __dot_%s __asm__(\"%s\");\n",
2087 sym_name+1, sym_name);
2088 continue;
2089 }
2090#endif
2091#if defined(__APPLE__)
2092/* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */
2093 fprintf(outfile, "extern char %s __attribute__((unused));\n", sym_name);
2094#elif defined(HOST_IA64)
2095 if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
2096 /*
2097 * PCREL21 br.call targets generally
2098 * are out of range and need to go
2099 * through an "import stub".
2100 */
2101 fprintf(outfile, " extern char %s;\n",
2102 sym_name);
2103#else
2104 fprintf(outfile, "extern char %s;\n", sym_name);
2105#endif
2106 }
2107 }
2108 }
2109
2110 fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n",
2111 name, (int)(start_offset - offset), copy_size);
2112
2113 /* emit code offset information */
2114 {
2115 EXE_SYM *sym;
2116 const char *sym_name, *p;
2117 unsigned long val;
2118 int n;
2119
2120 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2121 sym_name = get_sym_name(sym);
2122 if (strstart(sym_name, "__op_label", &p)) {
2123 uint8_t *ptr;
2124 unsigned long offset;
2125
2126 /* test if the variable refers to a label inside
2127 the code we are generating */
2128#ifdef CONFIG_FORMAT_COFF
2129 if (sym->st_shndx == text_shndx) {
2130 ptr = sdata[coff_text_shndx];
2131 } else if (sym->st_shndx == data_shndx) {
2132 ptr = sdata[coff_data_shndx];
2133 } else {
2134 ptr = NULL;
2135 }
2136#elif defined(CONFIG_FORMAT_MACH)
2137 if(!sym->n_sect)
2138 continue;
2139 ptr = sdata[sym->n_sect-1];
2140#elif defined(CONFIG_FORMAT_AOUT)
2141 switch (type_to_sec_number(sym->n_type))
2142 {
2143 case N_TEXT: ptr = (uint8_t *)aout_hdr + N_TXTOFF(*aout_hdr); break;
2144 case N_DATA: ptr = (uint8_t *)aout_hdr + N_DATOFF(*aout_hdr); break;
2145 default: ptr = NULL;
2146 }
2147#else
2148 ptr = sdata[sym->st_shndx];
2149#endif
2150 if (!ptr)
2151 error("__op_labelN in invalid section");
2152 offset = sym->st_value;
2153#ifdef CONFIG_FORMAT_MACH
2154 offset -= section_hdr[sym->n_sect-1].addr;
2155#elif defined(CONFIG_FORMAT_AOUT)
2156 if (type_to_sec_number(sym->n_type) == N_DATA)
2157 offset -= aout_hdr->a_text;
2158#endif
2159 val = *(unsigned long *)(ptr + offset);
2160#ifdef ELF_USES_RELOCA
2161 {
2162 int reloc_shndx, nb_relocs1, j;
2163
2164 /* try to find a matching relocation */
2165 reloc_shndx = find_reloc(sym->st_shndx);
2166 if (reloc_shndx) {
2167 nb_relocs1 = shdr[reloc_shndx].sh_size /
2168 shdr[reloc_shndx].sh_entsize;
2169 rel = (ELF_RELOC *)sdata[reloc_shndx];
2170 for(j = 0; j < nb_relocs1; j++) {
2171 if (rel->r_offset == offset) {
2172 val = rel->r_addend;
2173 break;
2174 }
2175 rel++;
2176 }
2177 }
2178 }
2179#endif
2180 if (val >= start_offset && val <= start_offset + copy_size) {
2181 n = strtol(p, NULL, 10);
2182 fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset));
2183 }
2184 }
2185 }
2186 }
2187
2188 /* load parameres in variables */
2189 for(i = 0; i < nb_args; i++) {
2190 fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1);
2191 }
2192
2193 /* patch relocations */
2194#if defined(HOST_I386)
2195 {
2196 char name[256];
2197 int type;
2198 int addend;
2199 int reloc_offset;
2200 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2201 host_ulong offset = get_rel_offset(rel);
2202 if (offset >= start_offset &&
2203 offset < start_offset + copy_size) {
2204#if defined(CONFIG_FORMAT_AOUT) || defined(CONFIG_FORMAT_MACH)
2205 sym_name = get_rel_sym_name_and_addend(rel, &addend);
2206#else
2207 sym_name = get_rel_sym_name(rel);
2208#endif
2209 if (!sym_name)
2210 continue;
2211 reloc_offset = offset - start_offset;
2212 if (strstart(sym_name, "__op_jmp", &p)) {
2213 int n;
2214 n = strtol(p, NULL, 10);
2215 /* __op_jmp relocations are done at
2216 runtime to do translated block
2217 chaining: the offset of the instruction
2218 needs to be stored */
2219 fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
2220 n, reloc_offset);
2221 continue;
2222 }
2223
2224 get_reloc_expr(name, sizeof(name), sym_name);
2225#if !defined(CONFIG_FORMAT_AOUT) && !defined(CONFIG_FORMAT_MACH)
2226 addend = get32((uint32_t *)(text + offset));
2227#endif
2228#ifdef CONFIG_FORMAT_ELF
2229 type = ELF32_R_TYPE(rel->r_info);
2230 switch(type) {
2231 case R_386_32:
2232 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2233 reloc_offset, name, addend);
2234 break;
2235 case R_386_PC32:
2236 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
2237 reloc_offset, name, reloc_offset, addend);
2238 break;
2239 default:
2240 error("unsupported i386 relocation (%d)", type);
2241 }
2242#elif defined(CONFIG_FORMAT_COFF)
2243 {
2244 char *temp_name;
2245 int j;
2246 EXE_SYM *sym;
2247 temp_name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
2248 if (!strcmp(temp_name, ".data")) {
2249 for (j = 0, sym = symtab; j < nb_syms; j++, sym++) {
2250 if (strstart(sym->st_name, sym_name, NULL)) {
2251 addend -= sym->st_value;
2252 }
2253 }
2254 }
2255 }
2256 type = rel->r_type;
2257 switch(type) {
2258 case DIR32:
2259 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2260 reloc_offset, name, addend);
2261 break;
2262 case DISP32:
2263 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
2264 reloc_offset, name, reloc_offset, addend);
2265 break;
2266 default:
2267 error("unsupported i386 relocation (%d)", type);
2268 }
2269#elif defined(CONFIG_FORMAT_AOUT) || defined(CONFIG_FORMAT_MACH)
2270 if (rel->r_pcrel) {
2271 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
2272 offset - start_offset, name, offset - start_offset, addend);
2273 } else {
2274 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2275 offset - start_offset, name, addend);
2276 }
2277 (void)type;
2278#else
2279#error unsupport object format
2280#endif
2281 }
2282 }
2283 }
2284#elif defined(HOST_X86_64)
2285 {
2286 char name[256];
2287 int type;
2288 int addend;
2289 int reloc_offset;
2290 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2291 if (rel->r_offset >= start_offset &&
2292 rel->r_offset < start_offset + copy_size) {
2293 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2294 get_reloc_expr(name, sizeof(name), sym_name);
2295 type = ELF32_R_TYPE(rel->r_info);
2296 addend = rel->r_addend;
2297 reloc_offset = rel->r_offset - start_offset;
2298 switch(type) {
2299 case R_X86_64_32:
2300 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
2301 reloc_offset, name, addend);
2302 break;
2303 case R_X86_64_32S:
2304 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
2305 reloc_offset, name, addend);
2306 break;
2307 case R_X86_64_PC32:
2308 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
2309 reloc_offset, name, reloc_offset, addend);
2310 break;
2311#ifdef VBOX /** @todo Re-check the sanity of this */
2312 case R_X86_64_64:
2313 fprintf(outfile, " *(uint64_t *)(gen_code_ptr + %d) = (uint64_t)%s + %d;\n",
2314 reloc_offset, name, addend);
2315 break;
2316#endif
2317 default:
2318 error("unsupported X86_64 relocation (%d)", type);
2319 }
2320 }
2321 }
2322 }
2323#elif defined(HOST_PPC)
2324 {
2325#ifdef CONFIG_FORMAT_ELF
2326 char name[256];
2327 int type;
2328 int addend;
2329 int reloc_offset;
2330 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2331 if (rel->r_offset >= start_offset &&
2332 rel->r_offset < start_offset + copy_size) {
2333 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2334 reloc_offset = rel->r_offset - start_offset;
2335 if (strstart(sym_name, "__op_jmp", &p)) {
2336 int n;
2337 n = strtol(p, NULL, 10);
2338 /* __op_jmp relocations are done at
2339 runtime to do translated block
2340 chaining: the offset of the instruction
2341 needs to be stored */
2342 fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
2343 n, reloc_offset);
2344 continue;
2345 }
2346
2347 get_reloc_expr(name, sizeof(name), sym_name);
2348 type = ELF32_R_TYPE(rel->r_info);
2349 addend = rel->r_addend;
2350 switch(type) {
2351 case R_PPC_ADDR32:
2352 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2353 reloc_offset, name, addend);
2354 break;
2355 case R_PPC_ADDR16_LO:
2356 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
2357 reloc_offset, name, addend);
2358 break;
2359 case R_PPC_ADDR16_HI:
2360 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
2361 reloc_offset, name, addend);
2362 break;
2363 case R_PPC_ADDR16_HA:
2364 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
2365 reloc_offset, name, addend);
2366 break;
2367 case R_PPC_REL24:
2368 /* warning: must be at 32 MB distancy */
2369 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
2370 reloc_offset, reloc_offset, name, reloc_offset, addend);
2371 break;
2372 default:
2373 error("unsupported powerpc relocation (%d)", type);
2374 }
2375 }
2376 }
2377#elif defined(CONFIG_FORMAT_MACH)
2378 struct scattered_relocation_info *scarel;
2379 struct relocation_info * rel;
2380 char final_sym_name[256];
2381 const char *sym_name;
2382 const char *p;
2383 int slide, sslide;
2384 int i;
2385
2386 for(i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
2387 unsigned int offset, length, value = 0;
2388 unsigned int type, pcrel, isym = 0;
2389 unsigned int usesym = 0;
2390
2391 if(R_SCATTERED & rel->r_address) {
2392 scarel = (struct scattered_relocation_info*)rel;
2393 offset = (unsigned int)scarel->r_address;
2394 length = scarel->r_length;
2395 pcrel = scarel->r_pcrel;
2396 type = scarel->r_type;
2397 value = scarel->r_value;
2398 } else {
2399 value = isym = rel->r_symbolnum;
2400 usesym = (rel->r_extern);
2401 offset = rel->r_address;
2402 length = rel->r_length;
2403 pcrel = rel->r_pcrel;
2404 type = rel->r_type;
2405 }
2406
2407 slide = offset - start_offset;
2408
2409 if (!(offset >= start_offset && offset < start_offset + size))
2410 continue; /* not in our range */
2411
2412 sym_name = get_reloc_name(rel, &sslide);
2413
2414 if(usesym && symtab[isym].n_type & N_STAB)
2415 continue; /* don't handle STAB (debug sym) */
2416
2417 if (sym_name && strstart(sym_name, "__op_jmp", &p)) {
2418 int n;
2419 n = strtol(p, NULL, 10);
2420 fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
2421 n, slide);
2422 continue; /* Nothing more to do */
2423 }
2424
2425 if(!sym_name)
2426 {
2427 fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n",
2428 name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type);
2429 continue; /* dunno how to handle without final_sym_name */
2430 }
2431
2432 get_reloc_expr(final_sym_name, sizeof(final_sym_name),
2433 sym_name);
2434 switch(type) {
2435 case PPC_RELOC_BR24:
2436 if (!strstart(sym_name,"__op_gen_label",&p)) {
2437 fprintf(outfile, "{\n");
2438 fprintf(outfile, " uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
2439 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",
2440 slide, slide, name, sslide );
2441 fprintf(outfile, "}\n");
2442 } else {
2443 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
2444 slide, slide, final_sym_name, slide);
2445 }
2446 break;
2447 case PPC_RELOC_HI16:
2448 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n",
2449 slide, final_sym_name, sslide);
2450 break;
2451 case PPC_RELOC_LO16:
2452 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n",
2453 slide, final_sym_name, sslide);
2454 break;
2455 case PPC_RELOC_HA16:
2456 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n",
2457 slide, final_sym_name, sslide);
2458 break;
2459 default:
2460 error("unsupported powerpc relocation (%d)", type);
2461 }
2462 }
2463#else
2464#error unsupport object format
2465#endif
2466 }
2467#elif defined(HOST_S390)
2468 {
2469 char name[256];
2470 int type;
2471 int addend;
2472 int reloc_offset;
2473 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2474 if (rel->r_offset >= start_offset &&
2475 rel->r_offset < start_offset + copy_size) {
2476 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2477 get_reloc_expr(name, sizeof(name), sym_name);
2478 type = ELF32_R_TYPE(rel->r_info);
2479 addend = rel->r_addend;
2480 reloc_offset = rel->r_offset - start_offset;
2481 switch(type) {
2482 case R_390_32:
2483 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2484 reloc_offset, name, addend);
2485 break;
2486 case R_390_16:
2487 fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
2488 reloc_offset, name, addend);
2489 break;
2490 case R_390_8:
2491 fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
2492 reloc_offset, name, addend);
2493 break;
2494 default:
2495 error("unsupported s390 relocation (%d)", type);
2496 }
2497 }
2498 }
2499 }
2500#elif defined(HOST_ALPHA)
2501 {
2502 for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
2503 if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
2504 int type;
2505 long reloc_offset;
2506
2507 type = ELF64_R_TYPE(rel->r_info);
2508 sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
2509 reloc_offset = rel->r_offset - start_offset;
2510 switch (type) {
2511 case R_ALPHA_GPDISP:
2512 /* The gp is just 32 bit, and never changes, so it's easiest to emit it
2513 as an immediate instead of constructing it from the pv or ra. */
2514 fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, gp);\n",
2515 reloc_offset);
2516 fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n",
2517 reloc_offset + (int)rel->r_addend);
2518 break;
2519 case R_ALPHA_LITUSE:
2520 /* jsr to literal hint. Could be used to optimize to bsr. Ignore for
2521 now, since some called functions (libc) need pv to be set up. */
2522 break;
2523 case R_ALPHA_HINT:
2524 /* Branch target prediction hint. Ignore for now. Should be already
2525 correct for in-function jumps. */
2526 break;
2527 case R_ALPHA_LITERAL:
2528 /* Load a literal from the GOT relative to the gp. Since there's only a
2529 single gp, nothing is to be done. */
2530 break;
2531 case R_ALPHA_GPRELHIGH:
2532 /* Handle fake relocations against __op_param symbol. Need to emit the
2533 high part of the immediate value instead. Other symbols need no
2534 special treatment. */
2535 if (strstart(sym_name, "__op_param", &p))
2536 fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, param%s);\n",
2537 reloc_offset, p);
2538 break;
2539 case R_ALPHA_GPRELLOW:
2540 if (strstart(sym_name, "__op_param", &p))
2541 fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, param%s);\n",
2542 reloc_offset, p);
2543 break;
2544 case R_ALPHA_BRSGP:
2545 /* PC-relative jump. Tweak offset to skip the two instructions that try to
2546 set up the gp from the pv. */
2547 fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
2548 reloc_offset, sym_name, reloc_offset);
2549 break;
2550 default:
2551 error("unsupported Alpha relocation (%d)", type);
2552 }
2553 }
2554 }
2555 }
2556#elif defined(HOST_IA64)
2557 {
2558 unsigned long sym_idx;
2559 long code_offset;
2560 char name[256];
2561 int type;
2562 long addend;
2563
2564 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2565 sym_idx = ELF64_R_SYM(rel->r_info);
2566 if (rel->r_offset < start_offset
2567 || rel->r_offset >= start_offset + copy_size)
2568 continue;
2569 sym_name = (strtab + symtab[sym_idx].st_name);
2570 code_offset = rel->r_offset - start_offset;
2571 if (strstart(sym_name, "__op_jmp", &p)) {
2572 int n;
2573 n = strtol(p, NULL, 10);
2574 /* __op_jmp relocations are done at
2575 runtime to do translated block
2576 chaining: the offset of the instruction
2577 needs to be stored */
2578 fprintf(outfile, " jmp_offsets[%d] ="
2579 "%ld + (gen_code_ptr - gen_code_buf);\n",
2580 n, code_offset);
2581 continue;
2582 }
2583 get_reloc_expr(name, sizeof(name), sym_name);
2584 type = ELF64_R_TYPE(rel->r_info);
2585 addend = rel->r_addend;
2586 switch(type) {
2587 case R_IA64_IMM64:
2588 fprintf(outfile,
2589 " ia64_imm64(gen_code_ptr + %ld, "
2590 "%s + %ld);\n",
2591 code_offset, name, addend);
2592 break;
2593 case R_IA64_LTOFF22X:
2594 case R_IA64_LTOFF22:
2595 fprintf(outfile, " IA64_LTOFF(gen_code_ptr + %ld,"
2596 " %s + %ld, %d);\n",
2597 code_offset, name, addend,
2598 (type == R_IA64_LTOFF22X));
2599 break;
2600 case R_IA64_LDXMOV:
2601 fprintf(outfile,
2602 " ia64_ldxmov(gen_code_ptr + %ld,"
2603 " %s + %ld);\n", code_offset, name, addend);
2604 break;
2605
2606 case R_IA64_PCREL21B:
2607 if (strstart(sym_name, "__op_gen_label", NULL)) {
2608 fprintf(outfile,
2609 " ia64_imm21b(gen_code_ptr + %ld,"
2610 " (long) (%s + %ld -\n\t\t"
2611 "((long) gen_code_ptr + %ld)) >> 4);\n",
2612 code_offset, name, addend,
2613 code_offset & ~0xfUL);
2614 } else {
2615 fprintf(outfile,
2616 " IA64_PLT(gen_code_ptr + %ld, "
2617 "%d);\t/* %s + %ld */\n",
2618 code_offset,
2619 get_plt_index(sym_name, addend),
2620 sym_name, addend);
2621 }
2622 break;
2623 default:
2624 error("unsupported ia64 relocation (0x%x)",
2625 type);
2626 }
2627 }
2628 fprintf(outfile, " ia64_nop_b(gen_code_ptr + %d);\n",
2629 copy_size - 16 + 2);
2630 }
2631#elif defined(HOST_SPARC)
2632 {
2633 char name[256];
2634 int type;
2635 int addend;
2636 int reloc_offset;
2637 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2638 if (rel->r_offset >= start_offset &&
2639 rel->r_offset < start_offset + copy_size) {
2640 sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
2641 get_reloc_expr(name, sizeof(name), sym_name);
2642 type = ELF32_R_TYPE(rel->r_info);
2643 addend = rel->r_addend;
2644 reloc_offset = rel->r_offset - start_offset;
2645 switch(type) {
2646 case R_SPARC_32:
2647 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2648 reloc_offset, name, addend);
2649 break;
2650 case R_SPARC_HI22:
2651 fprintf(outfile,
2652 " *(uint32_t *)(gen_code_ptr + %d) = "
2653 "((*(uint32_t *)(gen_code_ptr + %d)) "
2654 " & ~0x3fffff) "
2655 " | (((%s + %d) >> 10) & 0x3fffff);\n",
2656 reloc_offset, reloc_offset, name, addend);
2657 break;
2658 case R_SPARC_LO10:
2659 fprintf(outfile,
2660 " *(uint32_t *)(gen_code_ptr + %d) = "
2661 "((*(uint32_t *)(gen_code_ptr + %d)) "
2662 " & ~0x3ff) "
2663 " | ((%s + %d) & 0x3ff);\n",
2664 reloc_offset, reloc_offset, name, addend);
2665 break;
2666 case R_SPARC_WDISP30:
2667 fprintf(outfile,
2668 " *(uint32_t *)(gen_code_ptr + %d) = "
2669 "((*(uint32_t *)(gen_code_ptr + %d)) "
2670 " & ~0x3fffffff) "
2671 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2672 " & 0x3fffffff);\n",
2673 reloc_offset, reloc_offset, name, addend,
2674 reloc_offset);
2675 break;
2676 case R_SPARC_WDISP22:
2677 fprintf(outfile,
2678 " *(uint32_t *)(gen_code_ptr + %d) = "
2679 "((*(uint32_t *)(gen_code_ptr + %d)) "
2680 " & ~0x3fffff) "
2681 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2682 " & 0x3fffff);\n",
2683 rel->r_offset - start_offset,
2684 rel->r_offset - start_offset,
2685 name, addend,
2686 rel->r_offset - start_offset);
2687 break;
2688 default:
2689 error("unsupported sparc relocation (%d)", type);
2690 }
2691 }
2692 }
2693 }
2694#elif defined(HOST_SPARC64)
2695 {
2696 char name[256];
2697 int type;
2698 int addend;
2699 int reloc_offset;
2700 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2701 if (rel->r_offset >= start_offset &&
2702 rel->r_offset < start_offset + copy_size) {
2703 sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
2704 get_reloc_expr(name, sizeof(name), sym_name);
2705 type = ELF32_R_TYPE(rel->r_info);
2706 addend = rel->r_addend;
2707 reloc_offset = rel->r_offset - start_offset;
2708 switch(type) {
2709 case R_SPARC_32:
2710 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2711 reloc_offset, name, addend);
2712 break;
2713 case R_SPARC_HI22:
2714 fprintf(outfile,
2715 " *(uint32_t *)(gen_code_ptr + %d) = "
2716 "((*(uint32_t *)(gen_code_ptr + %d)) "
2717 " & ~0x3fffff) "
2718 " | (((%s + %d) >> 10) & 0x3fffff);\n",
2719 reloc_offset, reloc_offset, name, addend);
2720 break;
2721 case R_SPARC_LO10:
2722 fprintf(outfile,
2723 " *(uint32_t *)(gen_code_ptr + %d) = "
2724 "((*(uint32_t *)(gen_code_ptr + %d)) "
2725 " & ~0x3ff) "
2726 " | ((%s + %d) & 0x3ff);\n",
2727 reloc_offset, reloc_offset, name, addend);
2728 break;
2729 case R_SPARC_OLO10:
2730 addend += ELF64_R_TYPE_DATA (rel->r_info);
2731 fprintf(outfile,
2732 " *(uint32_t *)(gen_code_ptr + %d) = "
2733 "((*(uint32_t *)(gen_code_ptr + %d)) "
2734 " & ~0x3ff) "
2735 " | ((%s + %d) & 0x3ff);\n",
2736 reloc_offset, reloc_offset, name, addend);
2737 break;
2738 case R_SPARC_WDISP30:
2739 fprintf(outfile,
2740 " *(uint32_t *)(gen_code_ptr + %d) = "
2741 "((*(uint32_t *)(gen_code_ptr + %d)) "
2742 " & ~0x3fffffff) "
2743 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2744 " & 0x3fffffff);\n",
2745 reloc_offset, reloc_offset, name, addend,
2746 reloc_offset);
2747 break;
2748 case R_SPARC_WDISP22:
2749 fprintf(outfile,
2750 " *(uint32_t *)(gen_code_ptr + %d) = "
2751 "((*(uint32_t *)(gen_code_ptr + %d)) "
2752 " & ~0x3fffff) "
2753 " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
2754 " & 0x3fffff);\n",
2755 reloc_offset, reloc_offset, name, addend,
2756 reloc_offset);
2757 break;
2758 default:
2759 error("unsupported sparc64 relocation (%d) for symbol %s", type, name);
2760 }
2761 }
2762 }
2763 }
2764#elif defined(HOST_ARM)
2765 {
2766 char name[256];
2767 int type;
2768 int addend;
2769 int reloc_offset;
2770 uint32_t insn;
2771
2772 insn = get32((uint32_t *)(p_start + 4));
2773 /* If prologue ends in sub sp, sp, #const then assume
2774 op has a stack frame and needs the frame pointer. */
2775 if ((insn & 0xffffff00) == 0xe24dd000) {
2776 int i;
2777 uint32_t opcode;
2778 opcode = 0xe28db000; /* add fp, sp, #0. */
2779#if 0
2780/* ??? Need to undo the extra stack adjustment at the end of the op.
2781 For now just leave the stack misaligned and hope it doesn't break anything
2782 too important. */
2783 if ((insn & 4) != 0) {
2784 /* Preserve doubleword stack alignment. */
2785 fprintf(outfile,
2786 " *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n",
2787 insn + 4);
2788 opcode -= 4;
2789 }
2790#endif
2791 insn = get32((uint32_t *)(p_start - 4));
2792 /* Calculate the size of the saved registers,
2793 excluding pc. */
2794 for (i = 0; i < 15; i++) {
2795 if (insn & (1 << i))
2796 opcode += 4;
2797 }
2798 fprintf(outfile,
2799 " *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
2800 }
2801 arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
2802 relocs, nb_relocs);
2803
2804 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2805 if (rel->r_offset >= start_offset &&
2806 rel->r_offset < start_offset + copy_size) {
2807 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2808 /* the compiler leave some unnecessary references to the code */
2809 if (sym_name[0] == '\0')
2810 continue;
2811 get_reloc_expr(name, sizeof(name), sym_name);
2812 type = ELF32_R_TYPE(rel->r_info);
2813 addend = get32((uint32_t *)(text + rel->r_offset));
2814 reloc_offset = rel->r_offset - start_offset;
2815 switch(type) {
2816 case R_ARM_ABS32:
2817 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
2818 reloc_offset, name, addend);
2819 break;
2820 case R_ARM_PC24:
2821 case R_ARM_JUMP24:
2822 case R_ARM_CALL:
2823 fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
2824 reloc_offset, addend, name);
2825 break;
2826 default:
2827 error("unsupported arm relocation (%d)", type);
2828 }
2829 }
2830 }
2831 }
2832#elif defined(HOST_M68K)
2833 {
2834 char name[256];
2835 int type;
2836 int addend;
2837 int reloc_offset;
2838 Elf32_Sym *sym;
2839 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
2840 if (rel->r_offset >= start_offset &&
2841 rel->r_offset < start_offset + copy_size) {
2842 sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
2843 sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
2844 get_reloc_expr(name, sizeof(name), sym_name);
2845 type = ELF32_R_TYPE(rel->r_info);
2846 addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
2847 reloc_offset = rel->r_offset - start_offset;
2848 switch(type) {
2849 case R_68K_32:
2850 fprintf(outfile, " /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
2851 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
2852 reloc_offset, name, addend );
2853 break;
2854 case R_68K_PC32:
2855 fprintf(outfile, " /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
2856 fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
2857 reloc_offset, name, reloc_offset, /*sym->st_value+*/ addend);
2858 break;
2859 default:
2860 error("unsupported m68k relocation (%d)", type);
2861 }
2862 }
2863 }
2864 }
2865#else
2866#error unsupported CPU
2867#endif
2868 fprintf(outfile, " gen_code_ptr += %d;\n", copy_size);
2869 fprintf(outfile, "}\n");
2870 fprintf(outfile, "break;\n\n");
2871 } else {
2872 fprintf(outfile, "static inline void gen_%s(", name);
2873 if (nb_args == 0) {
2874 fprintf(outfile, "void");
2875 } else {
2876 for(i = 0; i < nb_args; i++) {
2877 if (i != 0)
2878 fprintf(outfile, ", ");
2879 fprintf(outfile, "long param%d", i + 1);
2880 }
2881 }
2882 fprintf(outfile, ")\n");
2883 fprintf(outfile, "{\n");
2884 for(i = 0; i < nb_args; i++) {
2885 fprintf(outfile, " *gen_opparam_ptr++ = param%d;\n", i + 1);
2886 }
2887 fprintf(outfile, " *gen_opc_ptr++ = INDEX_%s;\n", name);
2888 fprintf(outfile, "}\n\n");
2889 }
2890}
2891
2892int gen_file(FILE *outfile, int out_type)
2893{
2894 int i;
2895 EXE_SYM *sym;
2896
2897 if (out_type == OUT_INDEX_OP) {
2898 fprintf(outfile, "DEF(end, 0, 0)\n");
2899 fprintf(outfile, "DEF(nop, 0, 0)\n");
2900 fprintf(outfile, "DEF(nop1, 1, 0)\n");
2901 fprintf(outfile, "DEF(nop2, 2, 0)\n");
2902 fprintf(outfile, "DEF(nop3, 3, 0)\n");
2903 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2904 const char *name;
2905 name = get_sym_name(sym);
2906 if (strstart(name, OP_PREFIX, NULL)) {
2907 gen_code(name, sym->st_value, sym->st_size, outfile, 2);
2908 }
2909 }
2910 } else if (out_type == OUT_GEN_OP) {
2911 /* generate gen_xxx functions */
2912 fprintf(outfile, "#include \"dyngen-op.h\"\n");
2913 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2914 const char *name;
2915 name = get_sym_name(sym);
2916 if (strstart(name, OP_PREFIX, NULL)) {
2917#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
2918 if (sym->st_shndx != text_shndx)
2919 error("invalid section for opcode (0x%x)", sym->st_shndx);
2920#endif
2921 gen_code(name, sym->st_value, sym->st_size, outfile, 0);
2922 }
2923 }
2924
2925 } else {
2926 /* generate big code generation switch */
2927
2928#ifdef HOST_ARM
2929 /* We need to know the size of all the ops so we can figure out when
2930 to emit constant pools. This must be consistent with opc.h. */
2931fprintf(outfile,
2932"static const uint32_t arm_opc_size[] = {\n"
2933" 0,\n" /* end */
2934" 0,\n" /* nop */
2935" 0,\n" /* nop1 */
2936" 0,\n" /* nop2 */
2937" 0,\n"); /* nop3 */
2938 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2939 const char *name;
2940 name = get_sym_name(sym);
2941 if (strstart(name, OP_PREFIX, NULL)) {
2942 fprintf(outfile, " %d,\n", sym->st_size);
2943 }
2944 }
2945fprintf(outfile,
2946"};\n");
2947#endif
2948
2949fprintf(outfile,
2950"int dyngen_code(uint8_t *gen_code_buf,\n"
2951" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
2952" const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n"
2953"{\n"
2954" uint8_t *gen_code_ptr;\n"
2955" const uint16_t *opc_ptr;\n"
2956" const uint32_t *opparam_ptr;\n");
2957
2958#ifdef HOST_ARM
2959/* Arm is tricky because it uses constant pools for loading immediate values.
2960 We assume (and require) each function is code followed by a constant pool.
2961 All the ops are small so this should be ok. For each op we figure
2962 out how much "spare" range we have in the load instructions. This allows
2963 us to insert subsequent ops in between the op and the constant pool,
2964 eliminating the neeed to jump around the pool.
2965
2966 We currently generate:
2967
2968 [ For this example we assume merging would move op1_pool out of range.
2969 In practice we should be able to combine many ops before the offset
2970 limits are reached. ]
2971 op1_code;
2972 op2_code;
2973 goto op3;
2974 op2_pool;
2975 op1_pool;
2976op3:
2977 op3_code;
2978 ret;
2979 op3_pool;
2980
2981 Ideally we'd put op1_pool before op2_pool, but that requires two passes.
2982 */
2983fprintf(outfile,
2984" uint8_t *last_gen_code_ptr = gen_code_buf;\n"
2985" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
2986" uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
2987/* Initialise the parmissible pool offset to an arbitary large value. */
2988" uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
2989#endif
2990#ifdef HOST_IA64
2991 {
2992 long addend, not_first = 0;
2993 unsigned long sym_idx;
2994 int index, max_index;
2995 const char *sym_name;
2996 EXE_RELOC *rel;
2997
2998 max_index = -1;
2999 for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
3000 sym_idx = ELF64_R_SYM(rel->r_info);
3001 sym_name = (strtab + symtab[sym_idx].st_name);
3002 if (strstart(sym_name, "__op_gen_label", NULL))
3003 continue;
3004 if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
3005 continue;
3006
3007 addend = rel->r_addend;
3008 index = get_plt_index(sym_name, addend);
3009 if (index <= max_index)
3010 continue;
3011 max_index = index;
3012 fprintf(outfile, " extern void %s(void);\n", sym_name);
3013 }
3014
3015 fprintf(outfile,
3016 " struct ia64_fixup *plt_fixes = NULL, "
3017 "*ltoff_fixes = NULL;\n"
3018 " static long plt_target[] = {\n\t");
3019
3020 max_index = -1;
3021 for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
3022 sym_idx = ELF64_R_SYM(rel->r_info);
3023 sym_name = (strtab + symtab[sym_idx].st_name);
3024 if (strstart(sym_name, "__op_gen_label", NULL))
3025 continue;
3026 if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
3027 continue;
3028
3029 addend = rel->r_addend;
3030 index = get_plt_index(sym_name, addend);
3031 if (index <= max_index)
3032 continue;
3033 max_index = index;
3034
3035 if (not_first)
3036 fprintf(outfile, ",\n\t");
3037 not_first = 1;
3038 if (addend)
3039 fprintf(outfile, "(long) &%s + %ld", sym_name, addend);
3040 else
3041 fprintf(outfile, "(long) &%s", sym_name);
3042 }
3043 fprintf(outfile, "\n };\n"
3044 " unsigned int plt_offset[%u] = { 0 };\n", max_index + 1);
3045 }
3046#endif
3047
3048fprintf(outfile,
3049"\n"
3050" gen_code_ptr = gen_code_buf;\n"
3051" opc_ptr = opc_buf;\n"
3052" opparam_ptr = opparam_buf;\n");
3053
3054 /* Generate prologue, if needed. */
3055
3056fprintf(outfile,
3057" for(;;) {\n");
3058
3059#ifdef HOST_ARM
3060/* Generate constant pool if needed */
3061fprintf(outfile,
3062" if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
3063" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
3064"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n"
3065" last_gen_code_ptr = gen_code_ptr;\n"
3066" arm_ldr_ptr = arm_ldr_table;\n"
3067" arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
3068" arm_pool_ptr = gen_code_ptr + 0x1000000;\n"
3069" }\n");
3070#endif
3071
3072fprintf(outfile,
3073" switch(*opc_ptr++) {\n");
3074
3075 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
3076 const char *name;
3077 name = get_sym_name(sym);
3078 if (strstart(name, OP_PREFIX, NULL)) {
3079#if 0
3080 printf("%4d: %s pos=0x%08x len=%d\n",
3081 i, name, sym->st_value, sym->st_size);
3082#endif
3083#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
3084 if (sym->st_shndx != text_shndx)
3085 error("invalid section for opcode (0x%x)", sym->st_shndx);
3086#endif
3087 gen_code(name, sym->st_value, sym->st_size, outfile, 1);
3088 }
3089 }
3090
3091fprintf(outfile,
3092" case INDEX_op_nop:\n"
3093" break;\n"
3094" case INDEX_op_nop1:\n"
3095" opparam_ptr++;\n"
3096" break;\n"
3097" case INDEX_op_nop2:\n"
3098" opparam_ptr += 2;\n"
3099" break;\n"
3100" case INDEX_op_nop3:\n"
3101" opparam_ptr += 3;\n"
3102" break;\n"
3103" default:\n"
3104" goto the_end;\n"
3105" }\n");
3106
3107
3108fprintf(outfile,
3109" }\n"
3110" the_end:\n"
3111);
3112#ifdef HOST_IA64
3113 fprintf(outfile,
3114 " {\n"
3115 " extern char code_gen_buffer[];\n"
3116 " ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
3117 "(uint64_t) code_gen_buffer + 2*(1<<20), plt_fixes,\n\t\t\t"
3118 "sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t"
3119 "plt_target, plt_offset);\n }\n");
3120#endif
3121
3122/* generate some code patching */
3123#ifdef HOST_ARM
3124fprintf(outfile,
3125"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
3126" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
3127"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");
3128#endif
3129 /* flush instruction cache */
3130 fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
3131
3132 fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
3133 fprintf(outfile, "}\n\n");
3134
3135 }
3136
3137 return 0;
3138}
3139
3140void usage(void)
3141{
3142 printf("dyngen (c) 2003 Fabrice Bellard\n"
3143 "usage: dyngen [-o outfile] [-c] objfile\n"
3144 "Generate a dynamic code generator from an object file\n"
3145 "-c output enum of operations\n"
3146 "-g output gen_op_xx() functions\n"
3147 );
3148 exit(1);
3149}
3150
3151int main(int argc, char **argv)
3152{
3153 int c, out_type;
3154 const char *filename, *outfilename;
3155 FILE *outfile;
3156
3157 outfilename = "out.c";
3158 out_type = OUT_CODE;
3159 for(;;) {
3160 c = getopt(argc, argv, "ho:cg");
3161 if (c == -1)
3162 break;
3163 switch(c) {
3164 case 'h':
3165 usage();
3166 break;
3167 case 'o':
3168 outfilename = optarg;
3169 break;
3170 case 'c':
3171 out_type = OUT_INDEX_OP;
3172 break;
3173 case 'g':
3174 out_type = OUT_GEN_OP;
3175 break;
3176 }
3177 }
3178 if (optind >= argc)
3179 usage();
3180 filename = argv[optind];
3181 outfile = fopen(outfilename, "w");
3182 if (!outfile)
3183 error("could not open '%s'", outfilename);
3184
3185 load_object(filename);
3186 gen_file(outfile, out_type);
3187 fclose(outfile);
3188 return 0;
3189}
3190
3191/* bird added: */
3192/*
3193 * Local Variables:
3194 * mode: c
3195 * c-file-style: k&r
3196 * c-basic-offset: 4
3197 * tab-width: 4
3198 * indent-tabs-mode: t
3199 * End:
3200 */
3201
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