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 + -
显示快捷键?