Alien-TinyCC
view release on metacpan or search on metacpan
src/i386-gen.c view on Meta::CPAN
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef TARGET_DEFS_ONLY
/* number of available registers */
#define NB_REGS 4
#define NB_ASM_REGS 8
/* a register can belong to several classes. The classes must be
sorted from more general to more precise (see gv2() code which does
assumptions on it). */
#define RC_INT 0x0001 /* generic integer register */
#define RC_FLOAT 0x0002 /* generic float register */
#define RC_EAX 0x0004
#define RC_ST0 0x0008
#define RC_ECX 0x0010
#define RC_EDX 0x0020
#define RC_IRET RC_EAX /* function return: integer register */
#define RC_LRET RC_EDX /* function return: second integer register */
#define RC_FRET RC_ST0 /* function return: float register */
/* pretty names for the registers */
enum {
TREG_EAX = 0,
TREG_ECX,
TREG_EDX,
TREG_ST0,
TREG_ESP = 4
};
/* return registers for function */
#define REG_IRET TREG_EAX /* single word int return register */
#define REG_LRET TREG_EDX /* second word return register (for long long) */
#define REG_FRET TREG_ST0 /* float return register */
/* defined if function parameters must be evaluated in reverse order */
#define INVERT_FUNC_PARAMS
/* defined if structures are passed as pointers. Otherwise structures
are directly pushed on stack. */
/* #define FUNC_STRUCT_PARAM_AS_PTR */
/* pointer size, in bytes */
#define PTR_SIZE 4
/* long double size and alignment, in bytes */
#define LDOUBLE_SIZE 12
#define LDOUBLE_ALIGN 4
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
#define psym oad
/******************************************************/
/* ELF defines */
#define EM_TCC_TARGET EM_386
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_386_32
#define R_DATA_PTR R_386_32
#define R_JMP_SLOT R_386_JMP_SLOT
#define R_COPY R_386_COPY
#define ELF_START_ADDR 0x08048000
#define ELF_PAGE_SIZE 0x1000
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#include "tcc.h"
ST_DATA const int reg_classes[NB_REGS] = {
/* eax */ RC_INT | RC_EAX,
/* ecx */ RC_INT | RC_ECX,
/* edx */ RC_INT | RC_EDX,
/* st0 */ RC_FLOAT | RC_ST0,
};
static unsigned long func_sub_sp_offset;
static int func_ret_sub;
#ifdef CONFIG_TCC_BCHECK
static unsigned long func_bound_offset;
#endif
/* XXX: make it faster ? */
ST_FUNC void g(int c)
{
int ind1;
ind1 = ind + 1;
if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1);
cur_text_section->data[ind] = c;
ind = ind1;
}
ST_FUNC void o(unsigned int c)
{
while (c) {
g(c);
c = c >> 8;
}
}
ST_FUNC void gen_le16(int v)
{
g(v);
g(v >> 8);
}
ST_FUNC void gen_le32(int c)
{
g(c);
g(c >> 8);
g(c >> 16);
g(c >> 24);
}
/* output a symbol and patch all calls to it */
ST_FUNC void gsym_addr(int t, int a)
{
int n, *ptr;
while (t) {
ptr = (int *)(cur_text_section->data + t);
n = *ptr; /* next value */
*ptr = a - t - 4;
t = n;
}
}
ST_FUNC void gsym(int t)
{
gsym_addr(t, ind);
}
/* psym is used to put an instruction with a data field which is a
reference to a symbol. It is in fact the same as oad ! */
#define psym oad
/* instruction + 4 bytes data. Return the address of the data */
ST_FUNC int oad(int c, int s)
{
int ind1;
o(c);
ind1 = ind + 4;
if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1);
*(int *)(cur_text_section->data + ind) = s;
s = ind;
ind = ind1;
return s;
}
/* output constant with relocation if 'r & VT_SYM' is true */
ST_FUNC void gen_addr32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
greloc(cur_text_section, sym, ind, R_386_32);
gen_le32(c);
}
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
greloc(cur_text_section, sym, ind, R_386_PC32);
gen_le32(c - 4);
}
/* generate a modrm reference. 'op_reg' contains the addtionnal 3
opcode bits */
static void gen_modrm(int op_reg, int r, Sym *sym, int c)
{
op_reg = op_reg << 3;
if ((r & VT_VALMASK) == VT_CONST) {
/* constant memory reference */
o(0x05 | op_reg);
gen_addr32(r, sym, c);
} else if ((r & VT_VALMASK) == VT_LOCAL) {
/* currently, we use only ebp as base */
if (c == (char)c) {
/* short reference */
o(0x45 | op_reg);
g(c);
} else {
oad(0x85 | op_reg, c);
}
} else {
g(0x00 | op_reg | (r & VT_VALMASK));
}
}
/* load 'r' from value 'sv' */
ST_FUNC void load(int r, SValue *sv)
{
int v, t, ft, fc, fr;
SValue v1;
#ifdef TCC_TARGET_PE
SValue v2;
sv = pe_getimport(sv, &v2);
#endif
fr = sv->r;
ft = sv->type.t;
fc = sv->c.ul;
v = fr & VT_VALMASK;
if (fr & VT_LVAL) {
if (v == VT_LLOCAL) {
v1.type.t = VT_INT;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.ul = fc;
fr = r;
if (!(reg_classes[fr] & RC_INT))
src/i386-gen.c view on Meta::CPAN
#endif
ft = v->type.t;
fc = v->c.ul;
fr = v->r & VT_VALMASK;
bt = ft & VT_BTYPE;
/* XXX: incorrect if float reg to reg */
if (bt == VT_FLOAT) {
o(0xd9); /* fsts */
r = 2;
} else if (bt == VT_DOUBLE) {
o(0xdd); /* fstpl */
r = 2;
} else if (bt == VT_LDOUBLE) {
o(0xc0d9); /* fld %st(0) */
o(0xdb); /* fstpt */
r = 7;
} else {
if (bt == VT_SHORT)
o(0x66);
if (bt == VT_BYTE || bt == VT_BOOL)
o(0x88);
else
o(0x89);
}
if (fr == VT_CONST ||
fr == VT_LOCAL ||
(v->r & VT_LVAL)) {
gen_modrm(r, v->r, v->sym, fc);
} else if (fr != r) {
o(0xc0 + fr + r * 8); /* mov r, fr */
}
}
static void gadd_sp(int val)
{
if (val == (char)val) {
o(0xc483);
g(val);
} else {
oad(0xc481, val); /* add $xxx, %esp */
}
}
static void gen_static_call(int v)
{
Sym *sym;
sym = external_global_sym(v, &func_old_type, 0);
oad(0xe8, -4);
greloc(cur_text_section, sym, ind-4, R_386_PC32);
}
/* 'is_jmp' is '1' if it is a jump */
static void gcall_or_jmp(int is_jmp)
{
int r;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* constant case */
if (vtop->r & VT_SYM) {
/* relocation case */
greloc(cur_text_section, vtop->sym,
ind + 1, R_386_PC32);
} else {
/* put an empty PC32 relocation */
put_elf_reloc(symtab_section, cur_text_section,
ind + 1, R_386_PC32, 0);
}
oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
} else {
/* otherwise, indirect call */
r = gv(RC_INT);
o(0xff); /* call/jmp *r */
o(0xd0 + r + (is_jmp << 4));
}
}
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
/* Return 1 if this function returns via an sret pointer, 0 otherwise */
ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align)
{
#ifdef TCC_TARGET_PE
int size, align;
*ret_align = 1; // Never have to re-align return values for x86
size = type_size(vt, &align);
if (size > 8) {
return 1;
} else if (size > 4) {
ret->ref = NULL;
ret->t = VT_LLONG;
return 0;
} else {
ret->ref = NULL;
ret->t = VT_INT;
return 0;
}
#else
*ret_align = 1; // Never have to re-align return values for x86
return 1;
#endif
}
/* Generate function call. The function address is pushed first, then
all the parameters in call order. This functions pops all the
parameters and the function address. */
ST_FUNC void gfunc_call(int nb_args)
{
int size, align, r, args_size, i, func_call;
Sym *func_sym;
args_size = 0;
for(i = 0;i < nb_args; i++) {
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
size = type_size(&vtop->type, &align);
/* align to stack align size */
size = (size + 3) & ~3;
/* allocate the necessary size on stack */
oad(0xec81, size); /* sub $xxx, %esp */
/* generate structure store */
r = get_reg(RC_INT);
o(0x89); /* mov %esp, r */
o(0xe0 + r);
src/i386-gen.c view on Meta::CPAN
/* computed goto support */
ST_FUNC void ggoto(void)
{
gcall_or_jmp(1);
vtop--;
}
/* bound check support functions */
#ifdef CONFIG_TCC_BCHECK
/* generate a bounded pointer addition */
ST_FUNC void gen_bounded_ptr_add(void)
{
/* prepare fast i386 function call (args in eax and edx) */
gv2(RC_EAX, RC_EDX);
/* save all temporary registers */
vtop -= 2;
save_regs(0);
/* do a fast function call */
gen_static_call(TOK___bound_ptr_add);
/* returned pointer is in eax */
vtop++;
vtop->r = TREG_EAX | VT_BOUNDED;
/* address of bounding function call point */
vtop->c.ul = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
}
/* patch pointer addition in vtop so that pointer dereferencing is
also tested */
ST_FUNC void gen_bounded_ptr_deref(void)
{
int func;
int size, align;
Elf32_Rel *rel;
Sym *sym;
size = 0;
/* XXX: put that code in generic part of tcc */
if (!is_float(vtop->type.t)) {
if (vtop->r & VT_LVAL_BYTE)
size = 1;
else if (vtop->r & VT_LVAL_SHORT)
size = 2;
}
if (!size)
size = type_size(&vtop->type, &align);
switch(size) {
case 1: func = TOK___bound_ptr_indir1; break;
case 2: func = TOK___bound_ptr_indir2; break;
case 4: func = TOK___bound_ptr_indir4; break;
case 8: func = TOK___bound_ptr_indir8; break;
case 12: func = TOK___bound_ptr_indir12; break;
case 16: func = TOK___bound_ptr_indir16; break;
default:
tcc_error("unhandled size when dereferencing bounded pointer");
func = 0;
break;
}
/* patch relocation */
/* XXX: find a better solution ? */
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul);
sym = external_global_sym(func, &func_old_type, 0);
if (!sym->c)
put_extern_sym(sym, NULL, 0, 0);
rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
}
#endif
/* Save the stack pointer onto the stack */
ST_FUNC void gen_vla_sp_save(int addr) {
/* mov %esp,addr(%ebp)*/
o(0x89);
gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
}
/* Restore the SP from a location on the stack */
ST_FUNC void gen_vla_sp_restore(int addr) {
o(0x8b);
gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
}
/* Subtract from the stack pointer, and push the resulting value onto the stack */
ST_FUNC void gen_vla_alloc(CType *type, int align) {
#ifdef TCC_TARGET_PE
/* alloca does more than just adjust %rsp on Windows */
vpush_global_sym(&func_old_type, TOK_alloca);
vswap(); /* Move alloca ref past allocation size */
gfunc_call(1);
vset(type, REG_IRET, 0);
#else
int r;
r = gv(RC_INT); /* allocation size */
/* sub r,%rsp */
o(0x2b);
o(0xe0 | r);
/* We align to 16 bytes rather than align */
/* and ~15, %esp */
o(0xf0e483);
/* mov %esp, r */
o(0x89);
o(0xe0 | r);
vpop();
vset(type, r, 0);
#endif
}
/* end of X86 code generator */
/*************************************************************/
#endif
/*************************************************************/
( run in 0.476 second using v1.01-cache-2.11-cpan-71847e10f99 )