File:  [Qemu by Fabrice Bellard] / qemu / dyngen.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:42:57 2018 UTC (2 years, 4 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0082, HEAD
qemu 0.8.2

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

unix.superglobalmegacorp.com