VirtualBox

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

Last change on this file since 16560 was 11982, checked in by vboxsync, 16 years ago

All: license header changes for 2.0 (OSE headers, add Sun GPL/LGPL disclaimer)

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

© 2023 Oracle
ContactPrivacy policyTerms of Use