📄 x86asm.cc
字号:
/* * HT Editor * x86asm.cc * * Copyright (C) 1999-2002 Stefan Weyergraf * Copyright (C) 2005-2007 Sebastian Biallas (sb@biallas.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * 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. */#include <stdlib.h>#include <string.h>#include "x86asm.h"#include "snprintf.h"#include "strtools.h"enum { X86ASM_PREFIX_NO, X86ASM_PREFIX_0F, X86ASM_PREFIX_F20F, X86ASM_PREFIX_F30F, X86ASM_PREFIX_0F0F, X86ASM_PREFIX_0F38, X86ASM_PREFIX_660F38, X86ASM_PREFIX_F20F38, X86ASM_PREFIX_0F3A, X86ASM_PREFIX_660F3A, X86ASM_PREFIX_0F7A, X86ASM_PREFIX_0F7B, X86ASM_PREFIX_0F24, X86ASM_PREFIX_0F25, X86ASM_PREFIX_D8, X86ASM_PREFIX_D9, X86ASM_PREFIX_DA, X86ASM_PREFIX_DB, X86ASM_PREFIX_DC, X86ASM_PREFIX_DD, X86ASM_PREFIX_DE, X86ASM_PREFIX_DF,};#define X86ASM_ERRMSG_AMBIGUOUS "ambiguous command"#define X86ASM_ERRMSG_UNKNOWN_COMMAND "unknown command '%s'"#define X86ASM_ERRMSG_INVALID_PREFIX "invalid prefix"#define X86ASM_ERRMSG_UNKNOWN_SYMBOL "unknown symbol '%s'"#define X86ASM_ERRMSG_INVALID_OPERANDS "invalid operand(s)"#define X86ASM_ERRMSG_INTERNAL "internal error: "#define rexw 0x48#define rexr 0x44#define rexx 0x42#define rexb 0x41static const x86addrcoding modrm16[3][8] = {/* mod = 0 */{{X86_REG_BX, X86_REG_SI, 0},{X86_REG_BX, X86_REG_DI, 0},{X86_REG_BP, X86_REG_SI, 0},{X86_REG_BP, X86_REG_DI, 0},{X86_REG_SI, X86_REG_NO, 0},{X86_REG_DI, X86_REG_NO, 0},{X86_REG_NO, X86_REG_NO, 2},{X86_REG_BX, X86_REG_NO, 0}},/* mod = 1 */{{X86_REG_BX, X86_REG_SI, 1},{X86_REG_BX, X86_REG_DI, 1},{X86_REG_BP, X86_REG_SI, 1},{X86_REG_BP, X86_REG_DI, 1},{X86_REG_SI, X86_REG_NO, 1},{X86_REG_DI, X86_REG_NO, 1},{X86_REG_BP, X86_REG_NO, 1},{X86_REG_BX, X86_REG_NO, 1}},/* mod = 2 */{{X86_REG_BX, X86_REG_SI, 2},{X86_REG_BX, X86_REG_DI, 2},{X86_REG_BP, X86_REG_SI, 2},{X86_REG_BP, X86_REG_DI, 2},{X86_REG_SI, X86_REG_NO, 2},{X86_REG_DI, X86_REG_NO, 2},{X86_REG_BP, X86_REG_NO, 2},{X86_REG_BX, X86_REG_NO, 2}}};static const x86addrcoding modrm32[3][8] = {/* mod = 0 */{{X86_REG_AX, X86_REG_NO, 0},{X86_REG_CX, X86_REG_NO, 0},{X86_REG_DX, X86_REG_NO, 0},{X86_REG_BX, X86_REG_NO, 0},{X86_REG_INVALID, X86_REG_INVALID, -1}, /* special: SIB */{X86_REG_NO, X86_REG_NO, 4},{X86_REG_SI, X86_REG_NO, 0},{X86_REG_DI, X86_REG_NO, 0}},/* mod = 1 */{{X86_REG_AX, X86_REG_NO, 1},{X86_REG_CX, X86_REG_NO, 1},{X86_REG_DX, X86_REG_NO, 1},{X86_REG_BX, X86_REG_NO, 1},{X86_REG_INVALID, X86_REG_INVALID, -1}, /* special: SIB + disp8 */{X86_REG_BP, X86_REG_NO, 1},{X86_REG_SI, X86_REG_NO, 1},{X86_REG_DI, X86_REG_NO, 1}},/* mod = 2 */{{X86_REG_AX, X86_REG_NO, 4},{X86_REG_CX, X86_REG_NO, 4},{X86_REG_DX, X86_REG_NO, 4},{X86_REG_BX, X86_REG_NO, 4},{X86_REG_INVALID, X86_REG_INVALID, -1}, /* special: SIB + disp32 */{X86_REG_BP, X86_REG_NO, 4},{X86_REG_SI, X86_REG_NO, 4},{X86_REG_DI, X86_REG_NO, 4}}};/* convert logical operand types to hardware operand types */static const byte lop2hop[12][9] = { /* X86_OPTYPE_EMPTY */ {}, /* X86_OPTYPE_IMM */ {TYPE_I, TYPE_Is, TYPE_J, TYPE_A, TYPE_Ix, TYPE_I4}, /* X86_OPTYPE_REG */ {TYPE_R, TYPE_Rx, TYPE_RXx, TYPE_G, TYPE_E, TYPE_MR}, /* X86_OPTYPE_SEG */ {TYPE_S, TYPE_Sx}, /* X86_OPTYPE_MEM */ {TYPE_E, TYPE_M, TYPE_MR, TYPE_O, TYPE_Q, TYPE_W, TYPE_VS, TYPE_X}, /* X86_OPTYPE_CRX */ {TYPE_C}, /* X86_OPTYPE_DRX */ {TYPE_D}, /* X86_OPTYPE_STX */ {TYPE_F, TYPE_Fx}, /* X86_OPTYPE_MMX */ {TYPE_P, TYPE_Q, TYPE_PR}, /* X86_OPTYPE_XMM */ {TYPE_V, TYPE_W, TYPE_VR, TYPE_Vx, TYPE_VV, TYPE_VI, TYPE_VS, TYPE_VD}, /* X86_OPTYPE_YMM */ {TYPE_Y, TYPE_X, TYPE_YR, TYPE_YV, TYPE_YI}, /* X86_OPTYPE_FARPTR */ {},};static const char immhsz8_16[] = { SIZE_B, SIZE_BV, SIZE_W, SIZE_V, SIZE_VV, 0 };static const char immhsz16_16[] = { SIZE_W, SIZE_V, SIZE_VV, 0 };static const char immhsz32_16[] = { 0 };static const char immhsz64_16[] = { 0 };static const char immhsz8_32[] = { SIZE_B, SIZE_BV, SIZE_W, SIZE_V, SIZE_VV, 0 };static const char immhsz16_32[] = { SIZE_W, SIZE_V, SIZE_VV, 0 };static const char immhsz32_32[] = { SIZE_V, SIZE_VV, 0 };static const char immhsz64_32[] = { 0 };static const char immhsz8_64[] = { SIZE_B, SIZE_BV, SIZE_W, SIZE_V, SIZE_VV, 0 };static const char immhsz16_64[] = { SIZE_W, SIZE_V, SIZE_VV, 0 };static const char immhsz32_64[] = { SIZE_V, SIZE_VV, 0 };static const char immhsz64_64[] = { SIZE_V, 0 };static const char hsz8_16[] = { SIZE_B, 0 };static const char hsz16_16[] = { SIZE_W, SIZE_V, SIZE_VV, 0 };static const char hsz32_16[] = { SIZE_D, SIZE_P, SIZE_Z, SIZE_R, 0 };static const char hsz48_16[] = { 0 };static const char hsz64_16[] = { SIZE_Q, SIZE_U, SIZE_Z, 0};static const char hsz128_16[] = { SIZE_O, SIZE_U, 0};static const char hsz256_16[] = { SIZE_Y, 0};static const char hsz8_32[] = { SIZE_B, 0 };static const char hsz16_32[] = { SIZE_W, 0 };static const char hsz32_32[] = { SIZE_D, SIZE_V, SIZE_VV, SIZE_R, SIZE_Z, 0 };static const char hsz48_32[] = { SIZE_P, 0 };static const char hsz64_32[] = { SIZE_Q, SIZE_U, SIZE_Z, 0};static const char hsz128_32[] = { SIZE_O, SIZE_U, 0};static const char hsz256_32[] = { SIZE_Y, 0};static const char hsz8_64[] = { SIZE_B, 0 };static const char hsz16_64[] = { SIZE_W, 0 };static const char hsz32_64[] = { SIZE_D, SIZE_Z, 0 };static const char hsz48_64[] = { 0 };static const char hsz64_64[] = { SIZE_Q, SIZE_U, SIZE_V, SIZE_VV, SIZE_R, SIZE_Z, 0};static const char hsz128_64[] = { SIZE_O, SIZE_U, 0};static const char hsz256_64[] = { SIZE_Y, 0};static const int reg2size[4] = {1, 2, 4, 8};static const int addr2size[4] = {-1, 2, 4, 8};/* * CLASS x86asm */x86asm::x86asm(X86OpSize o, X86AddrSize a): Assembler(false){ opsize = o; addrsize = a; if (a != X86_ADDRSIZE64) { prepInsns(); }}x86opc_insn (*x86asm::x86_32a_insns)[256];void x86asm::prepInsns(){ if (!x86_32a_insns) { x86_32a_insns = ht_malloc(sizeof *x86_32a_insns); memcpy(x86_32a_insns, x86_32_insns, sizeof x86_32_insns); (*x86_32a_insns)[0xc4] = x86_les; (*x86_32a_insns)[0xc5] = x86_lds; } x86_insns = x86_32a_insns;}asm_insn *x86asm::alloc_insn(){ return ht_malloc(sizeof (x86asm_insn));}x86dis *x86asm::createCompatibleDisassembler(){ return new x86dis(opsize, addrsize);}void x86asm::delete_nonsense(CPU_ADDR addr){ x86dis *dis = createCompatibleDisassembler();restart: asm_code *c=codes; while (c) { if (delete_nonsense_insn(c, dis, addr)) goto restart; c = c->next; } delete dis;}static void skip_prefixes(byte **p, int &sizep, int addrsize){ while (sizep > 0) { if (**p == 0x66 || **p == 0x67 || **p == 0xf2 || **p == 0xf3 || (addrsize == X86_ADDRSIZE64 && (**p & 0xf0) == 0x40)) { sizep--; (*p)++; } else { break; } }}static bool cmp_insn_normal(byte *p, int sizep, byte *q, int sizeq, int addrsize, x86dis *dis, CPU_ADDR addr){ // UGLY: compare disassembly char s[200]; dis_insn *d = dis->decode(p, sizep, addr); ht_strlcpy(s, dis->str(d, X86DIS_STYLE_EXPLICIT_MEMSIZE), sizeof s); d = dis->decode(q, sizeq, addr); if (strcmp(s, dis->str(d, X86DIS_STYLE_EXPLICIT_MEMSIZE))) return false; // different disassembly --> not the same // compare opcodes (w/o prefixes) skip_prefixes(&p, sizep, addrsize); skip_prefixes(&q, sizeq, addrsize); if (sizep != sizeq) return false; // -> different raw opcodes --> not the same return memcmp(p, q, sizep) == 0;}bool x86asm::delete_nonsense_insn(asm_code *code, x86dis *dis, CPU_ADDR addr){ asm_code *c = codes; while (c) { if (c != code && code->size <= c->size) { if (cmp_insn_normal(c->data, c->size, code->data, code->size, addrsize, dis, addr)) { deletecode(c); return true; } } c = c->next; } return false;}void x86asm::emitdisp(uint64 d, int size){ dispsize = size; disp = d;}void x86asm::emitimm(uint64 i, int size){ immsize = size; imm = i;}void x86asm::emitfarptr(uint32 s, uint32 o, bool big){ if (big) { immsize = 6; imm = o; imm2 = s; } else { immsize = 4; imm = (s<<16) | (o & 0xffff); }}void x86asm::emitmodrm(int modrm){ modrmv = modrm;}void x86asm::emitmodrm_mod(int mod){ if (modrmv == -1) modrmv = 0; modrmv = (modrmv & ~(3<<6)) | ((mod & 3)<<6);}void x86asm::emitmodrm_reg(int reg){ if (modrmv == -1) modrmv = 0; modrmv = (modrmv & ~(7<<3)) | ((reg & 7)<<3);}void x86asm::emitmodrm_rm(int rm){ if (modrmv == -1) modrmv = 0; modrmv = (modrmv & ~7) | (rm & 7);}void x86asm::emitsib_base(int base){ if (sibv == -1) sibv = 0; sibv = (sibv & ~7) | (base & 7);}void x86asm::emitsib_index(int index){ if (sibv == -1) sibv = 0; sibv = (sibv & ~(7<<3)) | ((index & 7)<<3);}void x86asm::emitsib_scale(int scale){ if (sibv == -1) sibv = 0; sibv = (sibv & ~(3<<6)) | ((scale & 3)<<6);}#define MATCHOPNAME_NOMATCH 0#define MATCHOPNAME_MATCH 1#define MATCHOPNAME_MATCH_IF_OPSIZE16 2#define MATCHOPNAME_MATCH_IF_OPSIZE32 3#define MATCHOPNAME_MATCH_IF_OPSIZE64 4#define MATCHOPNAME_MATCH_IF_ADDRSIZE16 5#define MATCHOPNAME_MATCH_IF_ADDRSIZE32 6#define MATCHOPNAME_MATCH_IF_ADDRSIZE64 7#define MATCHOPNAME_MATCH_IF_OPPREFIX 8#define MATCHOPNAME_MATCH_IF_NOOPPREFIX 9asm_code *x86asm::encode(asm_insn *asm_insn, int options, CPU_ADDR cur_address){ Assembler::encode(asm_insn, options, cur_address); x86asm_insn *insn = (x86asm_insn*)asm_insn; newcode(); namefound = false; if (addrsize == X86_ADDRSIZE64) { address = cur_address.flat64.addr; } else { address = cur_address.addr32.offset; } esizes[0] = 0; esizes[1] = 0; esizes[2] = 0; esizes[3] = 0; esizes[4] = 0; ambiguous = false; match_opcodes(*x86_insns, insn, X86ASM_PREFIX_NO, MATCHOPNAME_MATCH); if (!namefound && insn->repprefix != X86_PREFIX_NO) { set_error_msg(X86ASM_ERRMSG_INVALID_PREFIX); } else { match_fopcodes(insn); match_opcodes(x86_insns_ext, insn, X86ASM_PREFIX_0F, MATCHOPNAME_MATCH_IF_NOOPPREFIX); match_opcodes(x86_insns_ext_66, insn, X86ASM_PREFIX_0F, MATCHOPNAME_MATCH_IF_OPPREFIX); match_opcodes(x86_insns_ext_f2, insn, X86ASM_PREFIX_F20F, MATCHOPNAME_MATCH_IF_NOOPPREFIX); match_opcodes(x86_insns_ext_f3, insn, X86ASM_PREFIX_F30F, MATCHOPNAME_MATCH_IF_NOOPPREFIX); match_opcodes(x86_opc_group_insns[0], insn, X86ASM_PREFIX_0F38, MATCHOPNAME_MATCH_IF_NOOPPREFIX); match_opcodes(x86_opc_group_insns[1], insn, X86ASM_PREFIX_660F38, MATCHOPNAME_MATCH_IF_OPPREFIX); match_opcodes(x86_opc_group_insns[2], insn, X86ASM_PREFIX_F20F38, MATCHOPNAME_MATCH_IF_NOOPPREFIX); match_opcodes(x86_opc_group_insns[3], insn, X86ASM_PREFIX_0F3A, MATCHOPNAME_MATCH_IF_NOOPPREFIX); match_opcodes(x86_opc_group_insns[4], insn, X86ASM_PREFIX_660F3A, MATCHOPNAME_MATCH_IF_OPPREFIX); match_opcodes(x86_opc_group_insns[5], insn, X86ASM_PREFIX_0F7A, MATCHOPNAME_MATCH_IF_NOOPPREFIX); match_opcodes(x86_opc_group_insns[6], insn, X86ASM_PREFIX_0F7B, MATCHOPNAME_MATCH_IF_NOOPPREFIX); match_opcodes(x86_opc_group_insns[7], insn, X86ASM_PREFIX_0F24, MATCHOPNAME_MATCH_IF_NOOPPREFIX); match_opcodes(x86_opc_group_insns[8], insn, X86ASM_PREFIX_0F25, MATCHOPNAME_MATCH_IF_NOOPPREFIX); match_vex_opcodes(insn); } if (error) { free_asm_codes(); } else if (!codes) { if (namefound) { set_error_msg(X86ASM_ERRMSG_INVALID_OPERANDS); } else { set_error_msg(X86ASM_ERRMSG_UNKNOWN_COMMAND, insn->name); } } else { delete_nonsense(cur_address); } return codes;}bool x86asm::encode_insn(x86asm_insn *insn, x86opc_insn *opcode, int opcodeb, int additional_opcode, int prefix, int eopsize, int eaddrsize){ rexprefix = 0; disppos = 0; bool opsize_depend = false; for (int i = 0; i < 4; i++) { switch (x86_op_type[opcode->op[i]].size) { case SIZE_BV: case SIZE_V: case SIZE_VV: case SIZE_P: opsize_depend = true; break; } } code.context = (void*)opsize_depend; /* test rex thingies */ for (int i=0; i < 4; i++) { if (insn->op[i].need_rex) { rexprefix |= 0x40; } if (insn->op[i].forbid_rex) { rexprefix |= 0x80; } } modrmv = -1; sibv = -1; drexdest = -1; drexoc0 = -1; dispsize = 0; immsize = 0; if (additional_opcode != -1) { if (additional_opcode & 0x800) { emitmodrm_mod(3); emitmodrm_reg(additional_opcode & 0x7); emitmodrm_rm((additional_opcode >> 3) & 0x7); } else { emitmodrm_reg(additional_opcode); } } if (addrsize == X86_ADDRSIZE64) { if (eopsize == X86_ADDRSIZE64) { if (insn->opsizeprefix == X86_PREFIX_OPSIZE) emitbyte(0x66); if (!(x86_op_type[opcode->op[0]].info & INFO_DEFAULT_64)) { // instruction doesn't default to 64 bit opsize rexprefix |= rexw; } } else if (eopsize == X86_ADDRSIZE32) { if (x86_op_type[opcode->op[0]].info & INFO_DEFAULT_64) { // instruction defaults to 64 bit opsize // it's not possible to switch to 32 bit return false; } if (insn->opsizeprefix == X86_PREFIX_OPSIZE) emitbyte(0x66); } else if (eopsize == X86_ADDRSIZE16) { if (insn->opsizeprefix == X86_PREFIX_NOOPSIZE) return false; emitbyte(0x66); } if (eaddrsize == X86_ADDRSIZE16) return false; if (eaddrsize == X86_ADDRSIZE32) emitbyte(0x67); } else { if (eopsize != opsize || insn->opsizeprefix == X86_PREFIX_OPSIZE) { if (insn->opsizeprefix == X86_PREFIX_NOOPSIZE) return false; emitbyte(0x66); } if (eaddrsize != addrsize) emitbyte(0x67); } if ((rexprefix & 0xc0) == 0xc0) { // can't combine insns which simultaneously need REX and forbid REX clearcode(); return false; } /* write lock, rep and/or seg prefixes if needed */ switch (insn->lockprefix) { case X86_PREFIX_LOCK: emitbyte(0xf0); break; } switch (insn->repprefix) { case X86_PREFIX_REPNZ: emitbyte(0xf2); break; case X86_PREFIX_REPZ: emitbyte(0xf3); break; } switch (insn->segprefix) { case X86_PREFIX_ES: emitbyte(0x26); break; case X86_PREFIX_CS: emitbyte(0x2e); break; case X86_PREFIX_SS: emitbyte(0x36); break; case X86_PREFIX_DS: emitbyte(0x3e); break; case X86_PREFIX_FS: emitbyte(0x64); break; case X86_PREFIX_GS: emitbyte(0x65); break; } switch (prefix) { case X86ASM_PREFIX_F20F: case X86ASM_PREFIX_F20F38: emitbyte(0xf2); break; case X86ASM_PREFIX_F30F: emitbyte(0xf3); break; } int rexpos = code.size; if ((rexprefix & 0x40) && prefix != X86ASM_PREFIX_0F24 && prefix != X86ASM_PREFIX_0F25) { emitbyte(0xff); // dummy value } /* write opcodeprefixes and opcode */ switch (prefix) { case X86ASM_PREFIX_0F0F: emitbyte(0x0f); case X86ASM_PREFIX_F20F: case X86ASM_PREFIX_F30F: case X86ASM_PREFIX_0F: emitbyte(0x0f); case X86ASM_PREFIX_NO: break; case X86ASM_PREFIX_0F38: case X86ASM_PREFIX_660F38: case X86ASM_PREFIX_F20F38: emitbyte(0x0f); emitbyte(0x38); break; case X86ASM_PREFIX_0F3A: case X86ASM_PREFIX_660F3A: emitbyte(0x0f); emitbyte(0x3a); break; case X86ASM_PREFIX_0F24: emitbyte(0x0f); emitbyte(0x24); break; case X86ASM_PREFIX_0F25: emitbyte(0x0f); emitbyte(0x25); break; case X86ASM_PREFIX_0F7A: emitbyte(0x0f); emitbyte(0x7a);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -