dyngen.c revision d65680efa46fa49e8bf14e67b29b782510ff934c
/*
* Generic Dynamic compiler generator
*
* Copyright (c) 2003 Fabrice Bellard
*
* The COFF object format support was extracted from Kazu's QEMU port
* to Win32.
*
* Mach-O Support by Matt Reda and Pierre d'Herbemont
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Sun GPL Disclaimer: For the avoidance of doubt, except that if any license choice
* other than GPL or LGPL is available it will apply instead, Sun elects to use only
* the General Public License version 2 (GPLv2) at this time for any software where
* a choice of GPL license versions is made available with the language indicating
* that GPLv2 or any later version may be used, or where a choice of which version
* of the GPL is applied is otherwise unspecified.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <inttypes.h>
#include <unistd.h>
#include <fcntl.h>
#include "config-host.h"
/* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross
compilation */
#if defined(CONFIG_WIN32)
#define CONFIG_FORMAT_COFF
#elif defined(CONFIG_DARWIN)
#define CONFIG_FORMAT_MACH
#elif defined(CONFIG_OS2)
#define CONFIG_FORMAT_AOUT
#else
#define CONFIG_FORMAT_ELF
#endif
#ifdef CONFIG_FORMAT_ELF
/* elf format definitions. We use these macros to test the CPU to
allow cross compilation (this tool must be ran on the build
platform) */
#if defined(HOST_I386)
#define ELF_CLASS ELFCLASS32
#elif defined(HOST_X86_64)
#define ELF_CLASS ELFCLASS64
#define elf_check_arch(x) ((x) == EM_X86_64)
#define ELF_USES_RELOCA
#define ELF_CLASS ELFCLASS32
#define elf_check_arch(x) ((x) == EM_PPC)
#define ELF_USES_RELOCA
#define ELF_CLASS ELFCLASS32
#define elf_check_arch(x) ((x) == EM_S390)
#define ELF_USES_RELOCA
#elif defined(HOST_ALPHA)
#define ELF_CLASS ELFCLASS64
#define elf_check_arch(x) ((x) == EM_ALPHA)
#define ELF_USES_RELOCA
#define ELF_CLASS ELFCLASS64
#define elf_check_arch(x) ((x) == EM_IA_64)
#define ELF_USES_RELOCA
#elif defined(HOST_SPARC)
#define ELF_CLASS ELFCLASS32
#define ELF_USES_RELOCA
#elif defined(HOST_SPARC64)
#define ELF_CLASS ELFCLASS64
#define ELF_ARCH EM_SPARCV9
#define elf_check_arch(x) ((x) == EM_SPARCV9)
#define ELF_USES_RELOCA
#define ELF_CLASS ELFCLASS32
#define elf_check_arch(x) ((x) == EM_ARM)
#define ELF_USES_RELOC
#define ELF_CLASS ELFCLASS32
#define elf_check_arch(x) ((x) == EM_68K)
#define ELF_USES_RELOCA
#else
#endif
#include "elf.h"
#if ELF_CLASS == ELFCLASS32
typedef uint32_t host_ulong;
#else
typedef uint64_t host_ulong;
#endif
#ifdef ELF_USES_RELOCA
#else
#endif
#endif /* CONFIG_FORMAT_ELF */
#ifdef CONFIG_FORMAT_COFF
#include "a.out.h"
typedef uint32_t host_ulong;
#define FILENAMELEN 256
typedef struct coff_sym {
struct external_syment *st_syment;
char st_name[FILENAMELEN];
int st_size;
} coff_Sym;
typedef struct coff_rel {
struct external_reloc *r_reloc;
int r_offset;
} coff_Rel;
#endif /* CONFIG_FORMAT_COFF */
#ifdef CONFIG_FORMAT_MACH
#if !defined(HOST_I386)
#endif
typedef uint32_t host_ulong;
struct nlist_extended
{
union {
char *n_name;
long n_strx;
} n_un;
unsigned char n_type;
unsigned char n_sect;
short st_desc;
unsigned long st_value;
unsigned long st_size;
};
#define EXE_RELOC struct relocation_info
#define EXE_SYM struct nlist_extended
#if defined(HOST_I386)
#endif
#endif /* CONFIG_FORMAT_MACH */
#ifdef CONFIG_FORMAT_AOUT
#include "a_out.h"
typedef uint32_t host_ulong;
struct nlist_extended
{
union {
char *n_name;
long n_strx;
} n_un;
unsigned char n_type;
char n_other;
short n_desc;
unsigned long st_value; /* n_value -> st_value */
unsigned long st_size; /* added */
};
#define EXE_RELOC struct relocation_info
#define EXE_SYM struct nlist_extended
#endif /* CONFIG_FORMAT_AOUT */
#include "bswap.h"
enum {
};
/* all dynamically generated functions begin with this code */
#define OP_PREFIX "op_"
int do_swap;
{
exit(1);
}
{
char *data;
if (!data)
return NULL;
return NULL;
}
return data;
}
{
const char *p, *q;
p = str;
q = val;
while (*q != '\0') {
if (*p != *q)
return 0;
p++;
q++;
}
if (ptr)
*ptr = p;
return 1;
}
{
int c;
char *q = buf;
if (buf_size <= 0)
return;
for(;;) {
c = *str++;
break;
*q++ = c;
}
*q = '\0';
}
{
*p = bswap16(*p);
}
{
*p = bswap32(*p);
}
{
*p = bswap32(*p);
}
{
*p = bswap64(*p);
}
{
*p = bswap64(*p);
}
{
val = *p;
if (do_swap)
return val;
}
{
val = *p;
if (do_swap)
return val;
}
{
if (do_swap)
*p = val;
}
{
if (do_swap)
*p = val;
}
/* executable information */
int nb_syms;
int text_shndx;
int nb_relocs;
#ifdef CONFIG_FORMAT_ELF
/* ELF file info */
char *strtab;
int elf_must_swap(struct elfhdr *h)
{
union {
uint32_t i;
uint8_t b[4];
} swaptest;
swaptest.i = 1;
(swaptest.b[0] == 0);
}
void elf_swap_ehdr(struct elfhdr *h)
{
}
void elf_swap_shdr(struct elf_shdr *h)
{
}
void elf_swap_phdr(struct elf_phdr *h)
{
}
{
#ifdef ELF_USES_RELOCA
#endif
}
const char *name)
{
int i;
const char *shname;
for(i = 0; i < shnum; i++) {
continue;
return sec;
}
return NULL;
}
int find_reloc(int sh_index)
{
int i;
return i;
}
return 0;
}
{
}
{
}
{
}
/* load an elf object file */
int load_object(const char *filename)
{
int fd;
int i, j;
char *shstr;
#ifdef O_BINARY
| O_BINARY
#endif
);
if (fd < 0)
/* Read ELF header. */
error("unable to read file header");
/* Check ELF identification. */
error("bad ELF header");
}
if (do_swap)
error("ELF object file expected");
error("Invalid ELF version");
/* read section headers */
if (do_swap) {
elf_swap_shdr(&shdr[i]);
}
}
/* read all section data */
}
/* swap relocations */
if (do_swap) {
}
}
}
/* text section */
if (!text_sec)
error("could not find .text section");
/* find text relocations, if any */
nb_relocs = 0;
i = find_reloc(text_shndx);
if (i != 0) {
}
if (!symtab_sec)
error("could not find .symtab section");
if (do_swap) {
}
}
return 0;
}
#endif /* CONFIG_FORMAT_ELF */
#ifdef CONFIG_FORMAT_COFF
/* COFF file info */
struct external_scnhdr *shdr;
struct external_filehdr fhdr;
struct external_syment *coff_symtab;
char *strtab;
int data_shndx;
#define STRTAB_SIZE 4
#define DIR32 0x06
#define DISP32 0x14
#define T_FUNCTION 0x20
#define C_EXTERNAL 2
{
char *q;
int c, i, len;
for(i = 0; i < 8; i++) {
if (c == '\0')
break;
*q++ = c;
}
*q = '\0';
} else {
}
/* now convert the name to a C name (suppress the leading '_') */
}
}
{
int i;
}
}
return NULL;
}
{
}
{
char *name;
if (name[0] == '.')
return NULL;
return name;
}
{
}
struct external_scnhdr *find_coff_section(struct external_scnhdr *shdr, int shnum, const char *name)
{
int i;
const char *shname;
struct external_scnhdr *sec;
for(i = 0; i < shnum; i++) {
continue;
return sec;
}
return NULL;
}
/* load a coff object file */
int load_object(const char *filename)
{
int fd;
int i;
struct external_syment *ext_sym;
struct external_reloc *coff_relocs;
struct external_reloc *ext_rel;
#ifdef O_BINARY
| O_BINARY
#endif
);
if (fd < 0)
/* Read COFF header. */
error("unable to read file header");
/* Check COFF identification. */
error("bad COFF header");
}
do_swap = 0;
/* read section headers */
shdr = load_data(fd, sizeof(struct external_filehdr) + fhdr.f_opthdr, fhdr.f_nscns * sizeof(struct external_scnhdr));
/* read all section data */
const char *p;
}
/* text section */
if (!text_sec)
error("could not find .text section");
/* data section */
if (!data_sec)
error("could not find .data section");
for(i=0;i<8;i++)
printf("\n");
}
}
/* set coff symbol */
int aux_size, j;
break;
} else if (j == nb_syms - i - 1) {
break;
}
}
break;
} else if (j == nb_syms - i - 1) {
break;
}
}
} else {
}
}
/* find text relocations, if any */
/* set coff relocation */
}
return 0;
}
#endif /* CONFIG_FORMAT_COFF */
#ifdef CONFIG_FORMAT_MACH
/* File Header */
struct mach_header mach_hdr;
/* commands */
struct segment_command *segment = 0;
struct dysymtab_command *dysymtabcmd = 0;
struct symtab_command *symtabcmd = 0;
/* section */
struct section *section_hdr;
struct section *text_sec_hdr;
/* relocs */
struct relocation_info *relocs;
/* symbols */
struct nlist *symtab_std;
char *strtab;
/* indirect symbols */
/* Utility functions */
static inline char *find_str_by_index(int index)
{
}
/* Used by dyngen common code */
{
return "debug";
if(!name)
return name;
if(name[0]=='_')
return name + 1;
else
return name;
}
/* find a section index given its segname, sectname */
const char *sectname)
{
int i;
continue;
return i;
}
return -1;
}
/* find a section header given its segname, sectname */
const char *sectname)
{
if(index == -1)
return NULL;
return section_hdr+index;
}
#if defined(HOST_PPC)
{
struct scattered_relocation_info * scarel;
error("fetch_next_pair_value: looking for a pair which was not found (1)");
} else {
error("fetch_next_pair_value: looking for a pair which was not found (2)");
}
}
#endif
/* find a sym name given its value, in a section number */
{
int i, ret = -1;
for( i = 0 ; i < nb_syms; i++ )
{
{
ret = i;
}
}
if( ret < 0 ) {
*offset = 0;
return 0;
} else {
}
}
/*
* Find symbol name given a (virtual) address, and a section which is of type
* S_NON_LAZY_SYMBOL_POINTERS or S_LAZY_SYMBOL_POINTERS or S_SYMBOL_STUBS
*/
{
const char *name = 0;
/* Sanity check */
return (char*)0;
if(size == 0)
error("size = 0");
}
size = sizeof(unsigned long);
else
return 0;
/* Compute our index in toc */
return name;
}
static const char * find_reloc_name_given_its_address(int address)
{
unsigned int i;
{
if((long)name != -1)
return name;
}
return 0;
}
{
char * name = 0;
int sectoffset;
int other_half=0;
/* init the slide value */
*sslide = 0;
{
/* ignore debug sym */
return 0;
}
#if defined(HOST_I386)
/* ignore internal pc relative fixups where both ends are in the text section. */
return NULL;
#endif
/* Intruction contains an offset to the symbols pointed to, in the rel->r_symbolnum section */
if(sectnum==0xffffff)
return 0;
/* Sanity Check */
error("sectnum > segment->nsects");
#if defined(HOST_PPC)
{
break;
case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) | (uint16_t)(other_half & 0xffff);
break;
case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) + (int16_t)(other_half & 0xffff);
break;
case PPC_RELOC_BR24:
break;
default:
error("switch(rel->type) not found");
}
/* The intruction contains the addend. */
#else
#endif
#if defined(HOST_PPC)
#endif
/* search it in the full symbol list, if not found */
if(!name)
return name;
}
#if defined(HOST_I386)
{
unsigned int i;
error("Fully implement R_SCATTERED! r_address=%#x r_type=%#x r_length=%d r_pcrel=%d r_value=%#x\n",
}
/* this seems to be the way to calc the addend. */
/* todo: do we need to ignore internal relocations? */
#if 0
return NULL;
#endif
/* find_reloc_name_given_its_address doesn't do the right thing here, so
we locate the section and use find_sym_with_value_and_sec_number */
int off = 0;
if (name) {
break;
}
}
}
if (!name)
error("Fully implement R_SCATTERED! r_address=%#x r_type=%#x r_length=%d r_pcrel=%d r_value=%#x\n",
}
else
{
/* ignore debug syms (paranoia). */
return NULL;
/* ignore internal pc relative fixups where both ends are in the text section. */
return NULL;
/* get the addend, it is in the instruction stream. */
/* external fixups are easy. */
{
}
else
{
/* sanity checks. */
return NULL;
error("internal pcrel fixups not implemented");
/* search for the symbol. */
}
}
return name;
}
#endif /* HOST_I386 */
/* Used by dyngen common code */
{
int sslide;
#if defined(HOST_I386)
#else
#endif
}
/* Used by dyngen common code */
{
else
}
/* load a mach-o object file */
int load_object(const char *filename)
{
int fd;
unsigned int offset_to_segment = 0;
unsigned int offset_to_dysymtab = 0;
unsigned int offset_to_symtab = 0;
struct load_command lc;
unsigned int i, j;
#ifdef O_BINARY
| O_BINARY
#endif
);
if (fd < 0)
/* Read Mach header. */
error("unable to read file header");
/* Check Mach identification. */
if (!check_mach_header(mach_hdr)) {
error("bad Mach header");
}
#if defined(HOST_PPC)
#else
#endif
error("Unsupported CPU");
error("Unsupported Mach Object");
/* read segment headers */
{
error("unable to read load_command");
{
offset_to_segment = j;
error("unable to read LC_SEGMENT");
}
{
offset_to_dysymtab = j;
error("unable to read LC_DYSYMTAB");
}
{
offset_to_symtab = j;
error("unable to read LC_SYMTAB");
}
}
if(!segment)
error("unable to find LC_SEGMENT");
/* read section headers */
section_hdr = load_data(fd, offset_to_segment + sizeof(struct segment_command), segment->nsects * sizeof(struct section));
/* read all section data */
/* Load the data in section data */
}
/* text section */
if (i == -1 || !text_sec_hdr)
error("could not find __TEXT,__text section");
/* Make sure dysym was loaded */
if(!(int)dysymtabcmd)
error("could not find __DYSYMTAB segment");
/* read the table of content of the indirect sym */
tocdylib = load_data( fd, dysymtabcmd->indirectsymoff, dysymtabcmd->nindirectsyms * sizeof(uint32_t) );
/* Make sure symtab was loaded */
if(!(int)symtabcmd)
error("could not find __SYMTAB segment");
/* Now transform the symtab, to an extended version, with the sym size, and the C name */
unsigned int j;
continue;
#if defined(VBOX)
/* don't bother calcing size of internal symbol local symbols. */
continue;
}
#endif
/* Find the following symbol in order to get the current symbol size */
continue;
if ( sym_next
continue;
#if defined(HOST_I386)
/* Ignore local labels (.Lxxx). */
continue;
#endif
/* a good one */
}
if(sym_next)
else
}
/* Find Reloc */
relocs = load_data(fd, text_sec_hdr->reloff, text_sec_hdr->nreloc * sizeof(struct relocation_info));
return 0;
}
#endif /* CONFIG_FORMAT_MACH */
#ifdef CONFIG_FORMAT_AOUT
struct nlist *symtab_std;
char *strtab;
/* Utility functions */
static inline char *find_str_by_index(int index)
{
}
/* Used by dyngen common code */
{
return "debug";
return name + 1;
return name;
}
static int type_to_sec_number(unsigned type)
{
switch (type)
{
default:
return type;
}
}
/* find a sym name given its value, in a section number */
{
int i, ret = -1;
for (i = 0; i < nb_syms; i++) {
&& ( ret < 0
ret = i;
}
}
if (ret < 0) {
*offset = 0;
return 0;
}
}
{
int sec;
int off;
*sslide = 0;
{
/* ignore debug sym */
return 0;
/* The intruction contains the addend. */
}
return 0;
/* sanity */
switch (sec)
{
}
/* The intruction contains the addend. */
/* search it in the full symbol list, if not found */
}
/* Used by dyngen common code */
{
int ignored;
}
/* Used by dyngen common code */
{
}
/* load an a.out object file */
int load_object(const char *filename)
{
long file_size;
unsigned i;
/*
* Open the file and validate the header.
*/
if (!pf)
/* we're optimistic, read the entire file first. */
if (!aout_hdr)
/* validate the header. */
/* setup globals. */
text_shndx = 1;
/*
* Now transform the symtab, to an extended version, with the sym size, and the C name
*/
if (!dst_sym)
unsigned sec;
unsigned j;
/* copy the symbol and find the name. */
continue; /* skip debug symbols. */
/* Find the following symbol in order to get the current symbol size */
continue;
if ( sym_next
continue;
/* good one */
}
if (sym_next)
else
}
return 0;
}
#endif /* CONFIG_FORMAT_AOUT */
{
const char *p;
} else {
#ifdef HOST_SPARC
if (sym_name[0] == '.')
"(long)(&__dot_%s)",
sym_name + 1);
else
#endif
}
}
#ifdef HOST_IA64
struct plt_entry {
const char *name;
unsigned long addend;
} *plt_list;
static int
{
int index = 0;
/* see if we already have an entry for this target: */
return index;
/* nope; create a new PLT entry: */
if (!plt) {
perror("malloc");
exit(1);
}
/* append to plt-list: */
if (prev)
else
return index;
}
#endif
#ifdef HOST_ARM
{
uint8_t *p;
unsigned int data_index;
int type;
p = p_start;
spare = 0x7fffffff;
while (p < p_start + min_offset) {
/* TODO: Armv5e ldrd. */
/* TODO: VFP load. */
/* ldr reg, [pc, #im] */
if (!(insn & 0x00800000))
max_pool = 4096;
type = 0;
/* FPA ldf. */
if (!(insn & 0x00800000))
max_pool = 1024;
type = 1;
/* Some gcc load a doubleword immediate with
add regN, pc, #imm
ldmia regN, {regN, regM}
Hope and pray the compiler never generates somethin like
add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */
int r;
max_pool = 1024;
type = 2;
} else {
max_pool = 0;
type = -1;
}
if (type >= 0) {
/* PC-relative load needs fixing up. */
if ((offset & 3) !=0)
error("%s:%04x: pc offset must be 32 bit aligned",
if (offset < 0)
error("%s:%04x: Embedded literal value",
error("%s:%04x: pc offset must point inside the function code",
if (pc_offset < min_offset)
if (outfile) {
/* The intruction position */
p - p_start);
/* The position of the constant pool data. */
}
}
p += 4;
}
/* Copy and relocate the constant pool data. */
spare += min_offset;
" arm_pool_ptr = gen_code_ptr + %d;\n",
data_index = 0;
for (pc_offset = min_offset;
pc_offset += 4) {
const char *sym_name;
char relname[1024];
/* data value */
relname[0] = '\0';
/* the compiler leave some unnecessary references to the code */
if (type != R_ARM_ABS32)
break;
}
}
data_index, addend);
if (relname[0] != '\0')
data_index++;
}
}
if (p == p_start)
goto arm_ret_error;
p -= 4;
/* The last instruction must be an ldm instruction. There are several
forms generated by gcc:
ldmib sp, {..., pc} (implies a sp adjustment of +4)
ldmia sp, {..., pc}
ldmea fp, {..., pc} */
if (outfile) {
" *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n",
p - p_start);
}
p += 4;
if (!outfile)
}
return p - p_start;
}
#endif
#define MAX_ARGS 3
/* generate op code */
{
int copy_size = 0;
int nb_args, i, n;
const char *sym_name, *p;
/* Compute exact size excluding prologue and epilogue instructions.
* Increment start_offset to skip epilogue instructions, then compute
* copy_size the indicate the size of the remaining instructions (in
* bytes).
*/
#if defined(HOST_I386) || defined(HOST_X86_64)
{
uint8_t *p;
p = p_end - 1;
if (p == p_start)
while (*p != 0xc3) {
p--;
if (p <= p_start)
}
}
#else
{
int len;
if (len == 0)
len--;
} else {
}
}
#endif
{
uint8_t *p;
p = (void *)(p_end - 4);
if (p == p_start)
}
{
uint8_t *p;
p = (void *)(p_end - 2);
if (p == p_start)
}
#elif defined(HOST_ALPHA)
{
uint8_t *p;
p = p_end - 4;
#if 0
/* XXX: check why it occurs */
if (p == p_start)
#endif
}
{
uint8_t *p;
p = (void *)(p_end - 4);
if (p == p_start)
/* br.ret.sptk.many b0;; */
/* 08 00 84 00 */
}
#elif defined(HOST_SPARC)
{
#define INSN_SAVE 0x9de3a000
#define INSN_RET 0x81c7e008
#define INSN_RETL 0x81c3e008
#define INSN_RESTORE 0x81e80000
#define INSN_RETURN 0x81cfe008
#define INSN_NOP 0x01000000
uint8_t *p;
p = (void *)(p_end - 8);
if (p <= p_start)
p_start += 0x4;
start_offset += 0x4;
/* SPARC v7: ret; restore; */ ;
/* SPARC v9: return; nop; */ ;
/* SPARC v7: retl; sub %sp, nn, %sp; */ ;
else
;
} else {
}
#if 0
/* Skip a preceeding nop, if present. */
if (p > p_start) {
p -= 4;
}
#endif
}
#elif defined(HOST_SPARC64)
{
#define INSN_SAVE 0x9de3a000
#define INSN_RET 0x81c7e008
#define INSN_RETL 0x81c3e008
#define INSN_RESTORE 0x81e80000
#define INSN_RETURN 0x81cfe008
#define INSN_NOP 0x01000000
uint8_t *p;
p = (void *)(p_end - 8);
#if 0
/* XXX: check why it occurs */
if (p <= p_start)
#endif
p_start += 0x4;
start_offset += 0x4;
/* SPARC v7: ret; restore; */ ;
/* SPARC v9: return; nop; */ ;
/* SPARC v7: retl; sub %sp, nn, %sp; */ ;
else
;
} else {
}
/* Skip a preceeding nop, if present. */
if (p > p_start) {
if (skip_insn == 0x01000000)
p -= 4;
}
}
{
p_start += 12;
start_offset += 12;
/* Stack adjustment. Assume op uses the frame pointer. */
p_start -= 4;
start_offset -= 4;
}
}
{
uint8_t *p;
p = (void *)(p_end - 2);
if (p == p_start)
/* remove NOP's, probably added for alignment */
(p>p_start))
p -= 2;
}
#else
#endif
/* compute the number of arguments by looking at the relocations */
for(i = 0;i < MAX_ARGS; i++)
args_present[i] = 0;
if (offset >= start_offset &&
if(!sym_name)
continue;
if (n > MAX_ARGS)
}
}
}
nb_args = 0;
nb_args++;
if (args_present[i])
}
if (gen_switch == 2) {
} else if (gen_switch == 1) {
/* output C code */
if (nb_args > 0) {
for(i = 0; i < nb_args; i++) {
if (i != 0)
}
}
#if defined(HOST_IA64)
#else
#endif
if (offset >= start_offset &&
if(!sym_name)
continue;
if (*sym_name &&
#ifdef VBOX
#endif
#if defined(HOST_SPARC)
if (sym_name[0] == '.') {
"extern char __dot_%s __asm__(\"%s\");\n",
continue;
}
#endif
#if defined(__APPLE__)
/* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */
/*
* PCREL21 br.call targets generally
* are out of range and need to go
* through an "import stub".
*/
sym_name);
#else
/* don't include memcpy here as this external reference wouldn't work anyway! */
#endif
}
}
}
/* emit code offset information */
{
const char *sym_name, *p;
unsigned long val;
int n;
unsigned long offset;
/* test if the variable refers to a label inside
the code we are generating */
#ifdef CONFIG_FORMAT_COFF
} else {
}
#elif defined(CONFIG_FORMAT_MACH)
continue;
#elif defined(CONFIG_FORMAT_AOUT)
{
}
#else
#endif
if (!ptr)
error("__op_labelN in invalid section");
#ifdef CONFIG_FORMAT_MACH
#elif defined(CONFIG_FORMAT_AOUT)
#endif
#ifdef ELF_USES_RELOCA
{
int reloc_shndx, nb_relocs1, j;
/* try to find a matching relocation */
if (reloc_shndx) {
for(j = 0; j < nb_relocs1; j++) {
break;
}
rel++;
}
}
}
#endif
fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset));
}
}
}
}
/* load parameres in variables */
for(i = 0; i < nb_args; i++) {
}
/* patch relocations */
#if defined(HOST_I386)
{
char name[256];
int type;
int addend;
int reloc_offset;
if (offset >= start_offset &&
#if defined(CONFIG_FORMAT_AOUT) || defined(CONFIG_FORMAT_MACH)
#else
#endif
if (!sym_name)
continue;
int n;
/* __op_jmp relocations are done at
runtime to do translated block
chaining: the offset of the instruction
needs to be stored */
n, reloc_offset);
continue;
}
#if !defined(CONFIG_FORMAT_AOUT) && !defined(CONFIG_FORMAT_MACH)
#endif
#ifdef CONFIG_FORMAT_ELF
switch(type) {
case R_386_32:
break;
case R_386_PC32:
break;
default:
}
#elif defined(CONFIG_FORMAT_COFF)
{
char *temp_name;
int j;
}
}
}
}
switch(type) {
case DIR32:
break;
case DISP32:
break;
default:
}
} else {
}
(void)type;
#else
#endif
}
}
}
#elif defined(HOST_X86_64)
{
char name[256];
int type;
int addend;
int reloc_offset;
switch(type) {
case R_X86_64_32:
break;
case R_X86_64_32S:
break;
case R_X86_64_PC32:
break;
#ifdef VBOX /** @todo Re-check the sanity of this */
case R_X86_64_64:
break;
#endif
default:
}
}
}
}
{
#ifdef CONFIG_FORMAT_ELF
char name[256];
int type;
int addend;
int reloc_offset;
int n;
/* __op_jmp relocations are done at
runtime to do translated block
chaining: the offset of the instruction
needs to be stored */
n, reloc_offset);
continue;
}
switch(type) {
case R_PPC_ADDR32:
break;
case R_PPC_ADDR16_LO:
break;
case R_PPC_ADDR16_HI:
break;
case R_PPC_ADDR16_HA:
break;
case R_PPC_REL24:
/* warning: must be at 32 MB distancy */
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
break;
default:
}
}
}
#elif defined(CONFIG_FORMAT_MACH)
struct scattered_relocation_info *scarel;
struct relocation_info * rel;
char final_sym_name[256];
const char *sym_name;
const char *p;
int i;
unsigned int usesym = 0;
} else {
}
continue; /* not in our range */
continue; /* don't handle STAB (debug sym) */
int n;
n, slide);
continue; /* Nothing more to do */
}
if(!sym_name)
{
fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n",
continue; /* dunno how to handle without final_sym_name */
}
sym_name);
switch(type) {
case PPC_RELOC_BR24:
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",
} else {
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
}
break;
case PPC_RELOC_HI16:
break;
case PPC_RELOC_LO16:
break;
case PPC_RELOC_HA16:
break;
default:
}
}
#else
#endif
}
{
char name[256];
int type;
int addend;
int reloc_offset;
switch(type) {
case R_390_32:
break;
case R_390_16:
break;
case R_390_8:
break;
default:
}
}
}
}
#elif defined(HOST_ALPHA)
{
int type;
long reloc_offset;
switch (type) {
case R_ALPHA_GPDISP:
/* The gp is just 32 bit, and never changes, so it's easiest to emit it
as an immediate instead of constructing it from the pv or ra. */
break;
case R_ALPHA_LITUSE:
/* jsr to literal hint. Could be used to optimize to bsr. Ignore for
now, since some called functions (libc) need pv to be set up. */
break;
case R_ALPHA_HINT:
/* Branch target prediction hint. Ignore for now. Should be already
correct for in-function jumps. */
break;
case R_ALPHA_LITERAL:
/* Load a literal from the GOT relative to the gp. Since there's only a
single gp, nothing is to be done. */
break;
case R_ALPHA_GPRELHIGH:
/* Handle fake relocations against __op_param symbol. Need to emit the
high part of the immediate value instead. Other symbols need no
special treatment. */
reloc_offset, p);
break;
case R_ALPHA_GPRELLOW:
reloc_offset, p);
break;
case R_ALPHA_BRSGP:
/* PC-relative jump. Tweak offset to skip the two instructions that try to
set up the gp from the pv. */
break;
default:
}
}
}
}
{
unsigned long sym_idx;
long code_offset;
char name[256];
int type;
long addend;
continue;
int n;
/* __op_jmp relocations are done at
runtime to do translated block
chaining: the offset of the instruction
needs to be stored */
"%ld + (gen_code_ptr - gen_code_buf);\n",
n, code_offset);
continue;
}
switch(type) {
case R_IA64_IMM64:
" ia64_imm64(gen_code_ptr + %ld, "
"%s + %ld);\n",
break;
case R_IA64_LTOFF22X:
case R_IA64_LTOFF22:
" %s + %ld, %d);\n",
(type == R_IA64_LTOFF22X));
break;
case R_IA64_LDXMOV:
" ia64_ldxmov(gen_code_ptr + %ld,"
break;
case R_IA64_PCREL21B:
" ia64_imm21b(gen_code_ptr + %ld,"
" (long) (%s + %ld -\n\t\t"
"((long) gen_code_ptr + %ld)) >> 4);\n",
code_offset & ~0xfUL);
} else {
" IA64_PLT(gen_code_ptr + %ld, "
"%d);\t/* %s + %ld */\n",
}
break;
default:
error("unsupported ia64 relocation (0x%x)",
type);
}
}
}
#elif defined(HOST_SPARC)
{
char name[256];
int type;
int addend;
int reloc_offset;
switch(type) {
case R_SPARC_32:
break;
case R_SPARC_HI22:
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | (((%s + %d) >> 10) & 0x3fffff);\n",
break;
case R_SPARC_LO10:
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3ff) "
" | ((%s + %d) & 0x3ff);\n",
break;
case R_SPARC_WDISP30:
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffffff);\n",
break;
case R_SPARC_WDISP22:
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffff);\n",
break;
default:
}
}
}
}
#elif defined(HOST_SPARC64)
{
char name[256];
int type;
int addend;
int reloc_offset;
switch(type) {
case R_SPARC_32:
break;
case R_SPARC_HI22:
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | (((%s + %d) >> 10) & 0x3fffff);\n",
break;
case R_SPARC_LO10:
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3ff) "
" | ((%s + %d) & 0x3ff);\n",
break;
case R_SPARC_OLO10:
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3ff) "
" | ((%s + %d) & 0x3ff);\n",
break;
case R_SPARC_WDISP30:
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffffff);\n",
break;
case R_SPARC_WDISP22:
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffff);\n",
break;
default:
}
}
}
}
{
char name[256];
int type;
int addend;
int reloc_offset;
/* If prologue ends in sub sp, sp, #const then assume
op has a stack frame and needs the frame pointer. */
int i;
#if 0
/* ??? Need to undo the extra stack adjustment at the end of the op.
For now just leave the stack misaligned and hope it doesn't break anything
too important. */
if ((insn & 4) != 0) {
/* Preserve doubleword stack alignment. */
" *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n",
insn + 4);
opcode -= 4;
}
#endif
/* Calculate the size of the saved registers,
excluding pc. */
for (i = 0; i < 15; i++) {
if (insn & (1 << i))
opcode += 4;
}
" *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
}
/* the compiler leave some unnecessary references to the code */
if (sym_name[0] == '\0')
continue;
switch(type) {
case R_ARM_ABS32:
break;
case R_ARM_PC24:
case R_ARM_JUMP24:
case R_ARM_CALL:
break;
default:
}
}
}
}
{
char name[256];
int type;
int addend;
int reloc_offset;
switch(type) {
case R_68K_32:
break;
case R_68K_PC32:
break;
default:
}
}
}
}
#else
#endif
} else {
if (nb_args == 0) {
} else {
for(i = 0; i < nb_args; i++) {
if (i != 0)
}
}
for(i = 0; i < nb_args; i++) {
}
}
}
{
int i;
if (out_type == OUT_INDEX_OP) {
const char *name;
}
}
} else if (out_type == OUT_GEN_OP) {
/* generate gen_xxx functions */
const char *name;
#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
#endif
}
}
} else {
/* generate big code generation switch */
#ifdef HOST_ARM
/* We need to know the size of all the ops so we can figure out when
to emit constant pools. This must be consistent with opc.h. */
"static const uint32_t arm_opc_size[] = {\n"
" 0,\n" /* end */
" 0,\n" /* nop */
" 0,\n" /* nop1 */
" 0,\n" /* nop2 */
" 0,\n"); /* nop3 */
const char *name;
}
}
"};\n");
#endif
"int dyngen_code(uint8_t *gen_code_buf,\n"
" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
" const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n"
"{\n"
" uint8_t *gen_code_ptr;\n"
" const uint16_t *opc_ptr;\n"
" const uint32_t *opparam_ptr;\n");
#ifdef HOST_ARM
/* Arm is tricky because it uses constant pools for loading immediate values.
We assume (and require) each function is code followed by a constant pool.
All the ops are small so this should be ok. For each op we figure
out how much "spare" range we have in the load instructions. This allows
us to insert subsequent ops in between the op and the constant pool,
eliminating the neeed to jump around the pool.
We currently generate:
[ For this example we assume merging would move op1_pool out of range.
In practice we should be able to combine many ops before the offset
limits are reached. ]
op1_code;
op2_code;
goto op3;
op2_pool;
op1_pool;
op3:
op3_code;
ret;
op3_pool;
Ideally we'd put op1_pool before op2_pool, but that requires two passes.
*/
" uint8_t *last_gen_code_ptr = gen_code_buf;\n"
" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
" uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
/* Initialise the parmissible pool offset to an arbitary large value. */
" uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
#endif
#ifdef HOST_IA64
{
unsigned long sym_idx;
const char *sym_name;
max_index = -1;
continue;
continue;
continue;
}
" struct ia64_fixup *plt_fixes = NULL, "
"*ltoff_fixes = NULL;\n"
" static long plt_target[] = {\n\t");
max_index = -1;
continue;
continue;
continue;
if (not_first)
not_first = 1;
if (addend)
else
}
}
#endif
"\n"
" gen_code_ptr = gen_code_buf;\n"
" opc_ptr = opc_buf;\n"
" opparam_ptr = opparam_buf;\n");
/* Generate prologue, if needed. */
" for(;;) {\n");
#ifdef HOST_ARM
/* Generate constant pool if needed */
" if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n"
" last_gen_code_ptr = gen_code_ptr;\n"
" arm_ldr_ptr = arm_ldr_table;\n"
" arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n"
" arm_pool_ptr = gen_code_ptr + 0x1000000;\n"
" }\n");
#endif
" switch(*opc_ptr++) {\n");
const char *name;
#if 0
printf("%4d: %s pos=0x%08x len=%d\n",
#endif
#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
#endif
}
}
" case INDEX_op_nop:\n"
" break;\n"
" case INDEX_op_nop1:\n"
" opparam_ptr++;\n"
" break;\n"
" case INDEX_op_nop2:\n"
" opparam_ptr += 2;\n"
" break;\n"
" case INDEX_op_nop3:\n"
" opparam_ptr += 3;\n"
" break;\n"
" default:\n"
" goto the_end;\n"
" }\n");
" }\n"
" the_end:\n"
);
#ifdef HOST_IA64
" {\n"
" extern char code_gen_buffer[];\n"
" ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
"(uint64_t) code_gen_buffer + 2*(1<<20), plt_fixes,\n\t\t\t"
"sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t"
"plt_target, plt_offset);\n }\n");
#endif
/* generate some code patching */
#ifdef HOST_ARM
"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");
#endif
/* flush instruction cache */
fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
}
return 0;
}
void usage(void)
{
printf("dyngen (c) 2003 Fabrice Bellard\n"
"usage: dyngen [-o outfile] [-c] objfile\n"
"Generate a dynamic code generator from an object file\n"
"-c output enum of operations\n"
"-g output gen_op_xx() functions\n"
);
exit(1);
}
{
int c, out_type;
const char *filename, *outfilename;
outfilename = "out.c";
for(;;) {
if (c == -1)
break;
switch(c) {
case 'h':
usage();
break;
case 'o':
break;
case 'c':
break;
case 'g':
break;
}
}
usage();
if (!outfile)
return 0;
}
/* bird added: */
/*
* Local Variables:
* mode: c
* c-file-style: k&r
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: t
* End:
*/