⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i386-gen.c

📁 tcc
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  X86 code generator for TCC *  *  Copyright (c) 2001, 2002, 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *//* number of available registers */#define NB_REGS             4/* 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,};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,};/* 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/* relocation type for 32 bit data relocation */#define R_DATA_32 R_386_32/******************************************************/static unsigned long func_sub_sp_offset;static unsigned long func_bound_offset;static int func_ret_sub;/* XXX: make it faster ? */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;}void o(int c){    while (c) {        g(c);        c = c / 256;    }}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 */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;    }}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 */static 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 */static 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);}/* 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' */void load(int r, SValue *sv){    int v, t, ft, fc, fr;    SValue v1;    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;            load(r, &v1);            fr = r;        }        if ((ft & VT_BTYPE) == VT_FLOAT) {            o(0xd9); /* flds */            r = 0;        } else if ((ft & VT_BTYPE) == VT_DOUBLE) {            o(0xdd); /* fldl */            r = 0;        } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {            o(0xdb); /* fldt */            r = 5;        } else if ((ft & VT_TYPE) == VT_BYTE) {            o(0xbe0f);   /* movsbl */        } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {            o(0xb60f);   /* movzbl */        } else if ((ft & VT_TYPE) == VT_SHORT) {            o(0xbf0f);   /* movswl */        } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {            o(0xb70f);   /* movzwl */        } else {            o(0x8b);     /* movl */        }        gen_modrm(r, fr, sv->sym, fc);    } else {        if (v == VT_CONST) {            o(0xb8 + r); /* mov $xx, r */            gen_addr32(fr, sv->sym, fc);        } else if (v == VT_LOCAL) {            o(0x8d); /* lea xxx(%ebp), r */            gen_modrm(r, VT_LOCAL, sv->sym, fc);        } else if (v == VT_CMP) {            oad(0xb8 + r, 0); /* mov $0, r */            o(0x0f); /* setxx %br */            o(fc);            o(0xc0 + r);        } else if (v == VT_JMP || v == VT_JMPI) {            t = v & 1;            oad(0xb8 + r, t); /* mov $1, r */            o(0x05eb); /* jmp after */            gsym(fc);            oad(0xb8 + r, t ^ 1); /* mov $0, r */        } else if (v != r) {            o(0x89);            o(0xc0 + r + v * 8); /* mov v, r */        }    }}/* store register 'r' in lvalue 'v' */void store(int r, SValue *v){    int fr, bt, ft, fc;    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)            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 */    }}/* '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));    }}/* 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. */void gfunc_call(int nb_args){    int size, align, r, args_size, i;    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);            vset(&vtop->type, r | VT_LVAL, 0);            vswap();            vstore();            args_size += size;        } else if (is_float(vtop->type.t)) {            gv(RC_FLOAT); /* only one float register */            if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)                size = 4;            else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)                size = 8;            else                size = 12;            oad(0xec81, size); /* sub $xxx, %esp */            if (size == 12)                o(0x7cdb);            else                o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */            g(0x24);            g(0x00);            args_size += size;        } else {            /* simple type (currently always same size) */            /* XXX: implicit cast ? */            r = gv(RC_INT);            if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {                size = 8;                o(0x50 + vtop->r2); /* push r */            } else {                size = 4;            }            o(0x50 + r); /* push r */            args_size += size;        }        vtop--;    }    save_regs(0); /* save used temporary registers */    func_sym = vtop->type.ref;    gcall_or_jmp(0);    if (args_size && func_sym->r == FUNC_CDECL)        gadd_sp(args_size);    vtop--;}/* generate function prolog of type 't' */void gfunc_prolog(CType *func_type){    int addr, align, size, func_call;    Sym *sym;    CType *type;    sym = func_type->ref;    func_call = sym->r;    addr = 8;    /* if the function returns a structure, then add an       implicit pointer parameter */    func_vt = sym->type;    if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {        func_vc = addr;        addr += 4;    }    /* define parameters */    while ((sym = sym->next) != NULL) {        type = &sym->type;        sym_push(sym->v & ~SYM_FIELD, type,                 VT_LOCAL | VT_LVAL, addr);        size = type_size(type, &align);        size = (size + 3) & ~3;#ifdef FUNC_STRUCT_PARAM_AS_PTR        /* structs are passed as pointer */        if ((type->t & VT_BTYPE) == VT_STRUCT) {            size = 4;        }#endif        addr += size;    }    func_ret_sub = 0;    /* pascal type call ? */    if (func_call == FUNC_STDCALL)        func_ret_sub = addr - 8;    o(0xe58955); /* push   %ebp, mov    %esp, %ebp */    func_sub_sp_offset = oad(0xec81, 0); /* sub $xxx, %esp */    /* leave some room for bound checking code */    if (do_bounds_check) {        oad(0xb8, 0); /* lbound section pointer */        oad(0xb8, 0); /* call to function */        func_bound_offset = lbounds_section->data_offset;    }}/* generate function epilog */void gfunc_epilog(void){#ifdef CONFIG_TCC_BCHECK    if (do_bounds_check && func_bound_offset != lbounds_section->data_offset) {        int saved_ind;        int *bounds_ptr;        Sym *sym, *sym_data;        /* add end of table info */        bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));        *bounds_ptr = 0;        /* generate bound local allocation */        saved_ind = ind;        ind = func_sub_sp_offset + 4;        sym_data = get_sym_ref(&char_pointer_type, lbounds_section,                                func_bound_offset, lbounds_section->data_offset);        greloc(cur_text_section, sym_data,               ind + 1, R_386_32);        oad(0xb8, 0); /* mov %eax, xxx */        sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0);        greloc(cur_text_section, sym,                ind + 1, R_386_PC32);        oad(0xe8, -4);        ind = saved_ind;        /* generate bound check local freeing */        o(0x5250); /* save returned value, if any */        greloc(cur_text_section, sym_data,               ind + 1, R_386_32);        oad(0xb8, 0); /* mov %eax, xxx */        sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0);        greloc(cur_text_section, sym,                ind + 1, R_386_PC32);        oad(0xe8, -4);        o(0x585a); /* restore returned value, if any */    }#endif    o(0xc9); /* leave */    if (func_ret_sub == 0) {        o(0xc3); /* ret */    } else {        o(0xc2); /* ret n */        g(func_ret_sub);        g(func_ret_sub >> 8);    }    /* align local size to word & save local variables */    *(int *)(cur_text_section->data + func_sub_sp_offset) = (-loc + 3) & -4; }/* generate a jump to a label */int gjmp(int t){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -