VirtualBox

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

Last change on this file since 2676 was 2422, checked in by vboxsync, 17 years ago

Removed the old recompiler code.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use