tcg-target.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,300 行 · 第 1/3 页

C
1,300
字号
/* * Tiny Code Generator for QEMU * * Copyright (c) 2008 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */const char *tcg_target_reg_names[TCG_TARGET_NB_REGS] = {    "%rax",    "%rcx",    "%rdx",    "%rbx",    "%rsp",    "%rbp",    "%rsi",    "%rdi",    "%r8",    "%r9",    "%r10",    "%r11",    "%r12",    "%r13",    "%r14",    "%r15",};int tcg_target_reg_alloc_order[] = {    TCG_REG_RDI,    TCG_REG_RSI,    TCG_REG_RDX,    TCG_REG_RCX,    TCG_REG_R8,    TCG_REG_R9,    TCG_REG_RAX,    TCG_REG_R10,    TCG_REG_R11,    TCG_REG_RBP,    TCG_REG_RBX,    TCG_REG_R12,    TCG_REG_R13,    TCG_REG_R14,    TCG_REG_R15,};const int tcg_target_call_iarg_regs[6] = {     TCG_REG_RDI,    TCG_REG_RSI,    TCG_REG_RDX,    TCG_REG_RCX,    TCG_REG_R8,    TCG_REG_R9,};const int tcg_target_call_oarg_regs[2] = {     TCG_REG_RAX,     TCG_REG_RDX };static uint8_t *tb_ret_addr;static void patch_reloc(uint8_t *code_ptr, int type,                         tcg_target_long value, tcg_target_long addend){    value += addend;    switch(type) {    case R_X86_64_32:        if (value != (uint32_t)value)            tcg_abort();        *(uint32_t *)code_ptr = value;        break;    case R_X86_64_32S:        if (value != (int32_t)value)            tcg_abort();        *(uint32_t *)code_ptr = value;        break;    case R_386_PC32:        value -= (long)code_ptr;        if (value != (int32_t)value)            tcg_abort();        *(uint32_t *)code_ptr = value;        break;    default:        tcg_abort();    }}/* maximum number of register used for input function arguments */static inline int tcg_target_get_call_iarg_regs_count(int flags){    return 6;}/* parse target specific constraints */int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str){    const char *ct_str;    ct_str = *pct_str;    switch(ct_str[0]) {    case 'a':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_RAX);        break;    case 'b':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_RBX);        break;    case 'c':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_RCX);        break;    case 'd':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_RDX);        break;    case 'S':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_RSI);        break;    case 'D':        ct->ct |= TCG_CT_REG;        tcg_regset_set_reg(ct->u.regs, TCG_REG_RDI);        break;    case 'q':        ct->ct |= TCG_CT_REG;        tcg_regset_set32(ct->u.regs, 0, 0xf);        break;    case 'r':        ct->ct |= TCG_CT_REG;        tcg_regset_set32(ct->u.regs, 0, 0xffff);        break;    case 'L': /* qemu_ld/st constraint */        ct->ct |= TCG_CT_REG;        tcg_regset_set32(ct->u.regs, 0, 0xffff);        tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI);        tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI);        break;    case 'e':        ct->ct |= TCG_CT_CONST_S32;        break;    case 'Z':        ct->ct |= TCG_CT_CONST_U32;        break;    default:        return -1;    }    ct_str++;    *pct_str = ct_str;    return 0;}/* test if a constant matches the constraint */static inline int tcg_target_const_match(tcg_target_long val,                                         const TCGArgConstraint *arg_ct){    int ct;    ct = arg_ct->ct;    if (ct & TCG_CT_CONST)        return 1;    else if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val)        return 1;    else if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val)        return 1;    else        return 0;}#define ARITH_ADD 0#define ARITH_OR  1#define ARITH_ADC 2#define ARITH_SBB 3#define ARITH_AND 4#define ARITH_SUB 5#define ARITH_XOR 6#define ARITH_CMP 7#define SHIFT_SHL 4#define SHIFT_SHR 5#define SHIFT_SAR 7#define JCC_JMP (-1)#define JCC_JO  0x0#define JCC_JNO 0x1#define JCC_JB  0x2#define JCC_JAE 0x3#define JCC_JE  0x4#define JCC_JNE 0x5#define JCC_JBE 0x6#define JCC_JA  0x7#define JCC_JS  0x8#define JCC_JNS 0x9#define JCC_JP  0xa#define JCC_JNP 0xb#define JCC_JL  0xc#define JCC_JGE 0xd#define JCC_JLE 0xe#define JCC_JG  0xf#define P_EXT   0x100 /* 0x0f opcode prefix */#define P_REXW  0x200 /* set rex.w = 1 */#define P_REXB  0x400 /* force rex use for byte registers */                                  static const uint8_t tcg_cond_to_jcc[10] = {    [TCG_COND_EQ] = JCC_JE,    [TCG_COND_NE] = JCC_JNE,    [TCG_COND_LT] = JCC_JL,    [TCG_COND_GE] = JCC_JGE,    [TCG_COND_LE] = JCC_JLE,    [TCG_COND_GT] = JCC_JG,    [TCG_COND_LTU] = JCC_JB,    [TCG_COND_GEU] = JCC_JAE,    [TCG_COND_LEU] = JCC_JBE,    [TCG_COND_GTU] = JCC_JA,};static inline void tcg_out_opc(TCGContext *s, int opc, int r, int rm, int x){    int rex;    rex = ((opc >> 6) & 0x8) | ((r >> 1) & 0x4) |         ((x >> 2) & 2) | ((rm >> 3) & 1);    if (rex || (opc & P_REXB)) {        tcg_out8(s, rex | 0x40);    }    if (opc & P_EXT)        tcg_out8(s, 0x0f);    tcg_out8(s, opc);}static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm){    tcg_out_opc(s, opc, r, rm, 0);    tcg_out8(s, 0xc0 | ((r & 7) << 3) | (rm & 7));}/* rm < 0 means no register index plus (-rm - 1 immediate bytes) */static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm,                                         tcg_target_long offset){    if (rm < 0) {        tcg_target_long val;        tcg_out_opc(s, opc, r, 0, 0);        val = offset - ((tcg_target_long)s->code_ptr + 5 + (-rm - 1));        if (val == (int32_t)val) {            /* eip relative */            tcg_out8(s, 0x05 | ((r & 7) << 3));            tcg_out32(s, val);        } else if (offset == (int32_t)offset) {            tcg_out8(s, 0x04 | ((r & 7) << 3));            tcg_out8(s, 0x25); /* sib */            tcg_out32(s, offset);        } else {            tcg_abort();        }    } else if (offset == 0 && (rm & 7) != TCG_REG_RBP) {        tcg_out_opc(s, opc, r, rm, 0);        if ((rm & 7) == TCG_REG_RSP) {            tcg_out8(s, 0x04 | ((r & 7) << 3));            tcg_out8(s, 0x24);        } else {            tcg_out8(s, 0x00 | ((r & 7) << 3) | (rm & 7));        }    } else if ((int8_t)offset == offset) {        tcg_out_opc(s, opc, r, rm, 0);        if ((rm & 7) == TCG_REG_RSP) {            tcg_out8(s, 0x44 | ((r & 7) << 3));            tcg_out8(s, 0x24);        } else {            tcg_out8(s, 0x40 | ((r & 7) << 3) | (rm & 7));        }        tcg_out8(s, offset);    } else {        tcg_out_opc(s, opc, r, rm, 0);        if ((rm & 7) == TCG_REG_RSP) {            tcg_out8(s, 0x84 | ((r & 7) << 3));            tcg_out8(s, 0x24);        } else {            tcg_out8(s, 0x80 | ((r & 7) << 3) | (rm & 7));        }        tcg_out32(s, offset);    }}#if defined(CONFIG_SOFTMMU)/* XXX: incomplete. index must be different from ESP */static void tcg_out_modrm_offset2(TCGContext *s, int opc, int r, int rm,                                   int index, int shift,                                  tcg_target_long offset){    int mod;    if (rm == -1)        tcg_abort();    if (offset == 0 && (rm & 7) != TCG_REG_RBP) {        mod = 0;    } else if (offset == (int8_t)offset) {        mod = 0x40;    } else if (offset == (int32_t)offset) {        mod = 0x80;    } else {        tcg_abort();    }    if (index == -1) {        tcg_out_opc(s, opc, r, rm, 0);        if ((rm & 7) == TCG_REG_RSP) {            tcg_out8(s, mod | ((r & 7) << 3) | 0x04);            tcg_out8(s, 0x04 | (rm & 7));        } else {            tcg_out8(s, mod | ((r & 7) << 3) | (rm & 7));        }    } else {        tcg_out_opc(s, opc, r, rm, index);        tcg_out8(s, mod | ((r & 7) << 3) | 0x04);        tcg_out8(s, (shift << 6) | ((index & 7) << 3) | (rm & 7));    }    if (mod == 0x40) {        tcg_out8(s, offset);    } else if (mod == 0x80) {        tcg_out32(s, offset);    }}#endifstatic inline void tcg_out_mov(TCGContext *s, int ret, int arg){    tcg_out_modrm(s, 0x8b | P_REXW, ret, arg);}static inline void tcg_out_movi(TCGContext *s, TCGType type,                                 int ret, tcg_target_long arg){    if (arg == 0) {        tcg_out_modrm(s, 0x01 | (ARITH_XOR << 3), ret, ret); /* xor r0,r0 */    } else if (arg == (uint32_t)arg || type == TCG_TYPE_I32) {        tcg_out_opc(s, 0xb8 + (ret & 7), 0, ret, 0);        tcg_out32(s, arg);    } else if (arg == (int32_t)arg) {        tcg_out_modrm(s, 0xc7 | P_REXW, 0, ret);        tcg_out32(s, arg);    } else {        tcg_out_opc(s, (0xb8 + (ret & 7)) | P_REXW, 0, ret, 0);        tcg_out32(s, arg);        tcg_out32(s, arg >> 32);    }}static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,                              int arg1, tcg_target_long arg2){    if (type == TCG_TYPE_I32)        tcg_out_modrm_offset(s, 0x8b, ret, arg1, arg2); /* movl */    else        tcg_out_modrm_offset(s, 0x8b | P_REXW, ret, arg1, arg2); /* movq */}static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,                              int arg1, tcg_target_long arg2){    if (type == TCG_TYPE_I32)        tcg_out_modrm_offset(s, 0x89, arg, arg1, arg2); /* movl */    else        tcg_out_modrm_offset(s, 0x89 | P_REXW, arg, arg1, arg2); /* movq */}static inline void tgen_arithi32(TCGContext *s, int c, int r0, int32_t val){    if (val == (int8_t)val) {        tcg_out_modrm(s, 0x83, c, r0);        tcg_out8(s, val);    } else {        tcg_out_modrm(s, 0x81, c, r0);        tcg_out32(s, val);    }}static inline void tgen_arithi64(TCGContext *s, int c, int r0, int64_t val){    if (val == (int8_t)val) {        tcg_out_modrm(s, 0x83 | P_REXW, c, r0);        tcg_out8(s, val);    } else if (val == (int32_t)val) {        tcg_out_modrm(s, 0x81 | P_REXW, c, r0);        tcg_out32(s, val);    } else if (c == ARITH_AND && val == (uint32_t)val) {        tcg_out_modrm(s, 0x81, c, r0);        tcg_out32(s, val);    } else {        tcg_abort();    }}void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val){    if (val != 0)        tgen_arithi64(s, ARITH_ADD, reg, val);}static void tcg_out_jxx(TCGContext *s, int opc, int label_index){    int32_t val, val1;    TCGLabel *l = &s->labels[label_index];        if (l->has_value) {        val = l->u.value - (tcg_target_long)s->code_ptr;        val1 = val - 2;        if ((int8_t)val1 == val1) {            if (opc == -1)                tcg_out8(s, 0xeb);            else                tcg_out8(s, 0x70 + opc);            tcg_out8(s, val1);        } else {            if (opc == -1) {                tcg_out8(s, 0xe9);                tcg_out32(s, val - 5);            } else {                tcg_out8(s, 0x0f);                tcg_out8(s, 0x80 + opc);                tcg_out32(s, val - 6);

⌨️ 快捷键说明

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