mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4201 lines
108 KiB
4201 lines
108 KiB
/***********************************************************************
|
|
* Microsoft Puma
|
|
*
|
|
* Microsoft Confidential. Copyright 1994-1996 Microsoft Corporation.
|
|
*
|
|
* Component:
|
|
*
|
|
* File: x86dis.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "pumap.h"
|
|
|
|
#include "x86.h"
|
|
|
|
#include <ctype.h>
|
|
#include <iomanip.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <strstrea.h>
|
|
|
|
|
|
const unsigned char iregAL = 0;
|
|
const unsigned char iregCL = 1;
|
|
const unsigned char iregDL = 2;
|
|
const unsigned char iregBL = 3;
|
|
const unsigned char iregAH = 4;
|
|
const unsigned char iregCH = 5;
|
|
const unsigned char iregDH = 6;
|
|
const unsigned char iregBH = 7;
|
|
|
|
const char rgszReg8[8][4] =
|
|
{
|
|
"al",
|
|
"cl",
|
|
"dl",
|
|
"bl",
|
|
"ah",
|
|
"ch",
|
|
"dh",
|
|
"bh"
|
|
};
|
|
|
|
const unsigned char iregAX = 0;
|
|
const unsigned char iregCX = 1;
|
|
const unsigned char iregDX = 2;
|
|
const unsigned char iregBX = 3;
|
|
const unsigned char iregSP = 4;
|
|
const unsigned char iregBP = 5;
|
|
const unsigned char iregSI = 6;
|
|
const unsigned char iregDI = 7;
|
|
|
|
const char rgszReg16[8][4] =
|
|
{
|
|
"ax",
|
|
"cx",
|
|
"dx",
|
|
"bx",
|
|
"sp",
|
|
"bp",
|
|
"si",
|
|
"di"
|
|
};
|
|
|
|
const char rgszReg32[8][4] =
|
|
{
|
|
"eax",
|
|
"ecx",
|
|
"edx",
|
|
"ebx",
|
|
"esp",
|
|
"ebp",
|
|
"esi",
|
|
"edi"
|
|
};
|
|
|
|
const unsigned char iregES = 0;
|
|
const unsigned char iregCS = 1;
|
|
const unsigned char iregSS = 2;
|
|
const unsigned char iregDS = 3;
|
|
const unsigned char iregFS = 4;
|
|
const unsigned char iregGS = 5;
|
|
|
|
const char rgszSReg[8][4] =
|
|
{
|
|
"es",
|
|
"cs",
|
|
"ss",
|
|
"ds",
|
|
"fs",
|
|
"gs",
|
|
"??",
|
|
"??"
|
|
};
|
|
|
|
const char rgszBase16[8][8] =
|
|
{
|
|
"bx+si",
|
|
"bx+di",
|
|
"bp+si",
|
|
"bp+di",
|
|
"si",
|
|
"di",
|
|
"bp",
|
|
"bx"
|
|
};
|
|
|
|
const TRMT mptrmtx86trmt[] =
|
|
{
|
|
trmtUnknown, // trmtx86Unknown
|
|
trmtFallThrough, // trmtx86FallThrough
|
|
trmtTrap, // trmtx86Trap
|
|
trmtTrapCc, // trmtx86TrapCc
|
|
trmtBra, // trmtx86JmpShort
|
|
trmtBra, // trmtx86JmpNear
|
|
trmtBra, // trmtx86JmpFar
|
|
trmtBraInd, // trmtx86JmpInd
|
|
trmtBraInd, // trmtx86Ret
|
|
trmtBraInd, // trmtx86Iret
|
|
trmtBraCc, // trmtx86JmpCcShort
|
|
trmtBraCc, // trmtx86JmpCcNear
|
|
trmtBraCc, // trmtx86Loop
|
|
trmtBraCc, // trmtx86Jcxz
|
|
trmtCall, // trmtx86CallNear16
|
|
trmtCall, // trmtx86CallNear32
|
|
trmtCall, // trmtx86CallFar
|
|
trmtCallInd, // trmtx86CallInd
|
|
};
|
|
|
|
|
|
enum MODRMT // MODRM type
|
|
{
|
|
modrmtNo, // Not present
|
|
modrmtYes, // Present
|
|
modrmtMem, // Memory only
|
|
modrmtReg, // Register only
|
|
};
|
|
|
|
enum ICB // Immediate byte count
|
|
{
|
|
icbNil, // No immediate value
|
|
icbAP, // Far pointer
|
|
icbIb, // Immediate byte
|
|
icbIv, // Immediate operand size value
|
|
icbIw, // Immediate word
|
|
icbIw_Ib, // Immediate word and immediate byte
|
|
icbJb, // Byte displacement
|
|
icbJv, // Address size displacement
|
|
icbO, // Address size value
|
|
};
|
|
|
|
enum OPRNDT // Operand type
|
|
{
|
|
oprndtNil, // No operand
|
|
oprndtAP, // Far address
|
|
oprndtCd, // CRx register from MODRM reg
|
|
oprndtConst, // Constant from bValue
|
|
oprndtDd, // DRx register from MODRM reg
|
|
oprndtGvOp, // General register (operand size) from opcode
|
|
oprndtIb, // Immediate byte
|
|
oprndtIb2, // Immediate byte following word
|
|
oprndtIv, // Immediate operand size value
|
|
oprndtIw, // Immediate word
|
|
oprndtJb, // Relative address byte
|
|
oprndtJv, // Relative address operand size value
|
|
oprndtMmModrm, // Memory/MM register references from MODRM (MMX)
|
|
oprndtMmModrmReg, // MM register from MODRM reg (MMX)
|
|
oprndtModrm, // Memory/register references from MODRM
|
|
oprndtModrmReg, // General register from MODRM reg
|
|
oprndtModrmSReg, // Segment register from MODRM reg
|
|
oprndtOffset, // Address size immediate offset
|
|
oprndtRb, // General register (byte) from bValue
|
|
oprndtRv, // General register (operand size) from bValue
|
|
oprndtRw, // General register (word) from bValue
|
|
oprndtST, // Floating point top of stack
|
|
oprndtSTi, // Floating point register from MODRM reg
|
|
oprndtSw, // Segment register (word) from bValue
|
|
oprndtTd, // TRx register from MODRM reg
|
|
oprndtX, // DS:[eSI] for string instruction
|
|
oprndtY, // ES:[eDI] for string instruction
|
|
oprndtZ, // DS:[eBX] for XLAT
|
|
};
|
|
|
|
enum OPREFT // Operand reference type
|
|
{
|
|
opreftNil, // Operand not referenced (e.g. INVLPG)
|
|
opreftRd, // Operand is read
|
|
opreftRw, // Operand is read and written
|
|
opreftWr // Operand is written
|
|
};
|
|
|
|
struct OPRND // Operand
|
|
{
|
|
unsigned char opreft : 2;
|
|
unsigned char oprndt : 6;
|
|
unsigned char bValue;
|
|
};
|
|
|
|
struct OPS // Instruction operands
|
|
{
|
|
MODRMT modrmt;
|
|
ICB icb;
|
|
OPRND rgoprnd[3];
|
|
};
|
|
|
|
struct OPCD
|
|
{
|
|
const void *pvMnemonic;
|
|
const OPS *pops;
|
|
unsigned char trmtx86;
|
|
};
|
|
|
|
#if 1
|
|
|
|
// UNDONE: Work around problem initializing with const structs
|
|
|
|
#define DEFOPRND(name, opreft_, oprndt_, b) \
|
|
const unsigned char oprnd ## name ## _opreft = opreft ## opreft_; \
|
|
const unsigned char oprnd ## name ## _oprndt = oprndt ## oprndt_; \
|
|
const unsigned char oprnd ## name ## _b = b;
|
|
|
|
#else
|
|
|
|
#define DEFOPRND(name, opreft_, oprndt_, b) \
|
|
const OPRND oprnd ## name = \
|
|
{ \
|
|
opreft ## opreft_, \
|
|
oprndt ## oprndt_, \
|
|
b \
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
DEFOPRND(1, Nil, Const, 1 )
|
|
DEFOPRND(3, Nil, Const, 3 )
|
|
DEFOPRND(AP, Nil, AP, 0 )
|
|
DEFOPRND(Ib, Nil, Ib, 1 )
|
|
DEFOPRND(Ib2, Nil, Ib2, 1 )
|
|
DEFOPRND(Iv, Nil, Iv, 0 )
|
|
DEFOPRND(Iw, Nil, Iw, 2 )
|
|
DEFOPRND(Jb, Nil, Jb, 1 )
|
|
DEFOPRND(Jv, Nil, Jv, 0 )
|
|
DEFOPRND(M, Nil, Modrm, 0 )
|
|
DEFOPRND(Nil, Nil, Nil, 0 )
|
|
DEFOPRND(RdCd, Rd, Cd, 4 )
|
|
DEFOPRND(RdDd, Rd, Dd, 4 )
|
|
DEFOPRND(RdEb, Rd, Modrm, 1 )
|
|
DEFOPRND(RdEv, Rd, Modrm, 0 )
|
|
DEFOPRND(RdEw, Rd, Modrm, 2 )
|
|
DEFOPRND(RdGb, Rd, ModrmReg, 1 )
|
|
DEFOPRND(RdGv, Rd, ModrmReg, 0 )
|
|
DEFOPRND(RdGvOp, Rd, GvOp, 0 )
|
|
DEFOPRND(RdGw, Rd, ModrmReg, 2 )
|
|
DEFOPRND(RdMa, Rd, Modrm, 0 )
|
|
DEFOPRND(RdMd, Rd, Modrm, 4 )
|
|
DEFOPRND(RdMenv, Rd, Modrm, 0 )
|
|
DEFOPRND(RdMmd, Rd, MmModrm, 4 )
|
|
DEFOPRND(RdMmq, Rd, MmModrm, 8 )
|
|
DEFOPRND(RdMp, Rd, Modrm, 0 )
|
|
DEFOPRND(RdMq, Rd, Modrm, 8 )
|
|
DEFOPRND(RdMs, Rd, Modrm, 6 )
|
|
DEFOPRND(RdMsta, Rd, Modrm, 0 )
|
|
DEFOPRND(RdMt, Rd, Modrm, 10 )
|
|
DEFOPRND(RdMv, Rd, MmModrmReg, 0 )
|
|
DEFOPRND(RdMw, Rd, Modrm, 2 )
|
|
DEFOPRND(RdOb, Rd, Offset, 1 )
|
|
DEFOPRND(RdOv, Rd, Offset, 0 )
|
|
DEFOPRND(RdRbAL, Rd, Rb, iregAL )
|
|
DEFOPRND(RdRbCL, Rd, Rb, iregCL )
|
|
DEFOPRND(RdRd, Rd, Modrm, 4 )
|
|
DEFOPRND(RdRvAX, Rd, Rv, iregAX )
|
|
DEFOPRND(RdRwDX, Rd, Rw, iregDX )
|
|
DEFOPRND(RdSw, Rd, ModrmSReg, 2 )
|
|
DEFOPRND(RdSwCS, Rd, Sw, iregCS )
|
|
DEFOPRND(RdSwDS, Rd, Sw, iregDS )
|
|
DEFOPRND(RdSwES, Rd, Sw, iregES )
|
|
DEFOPRND(RdSwFS, Rd, Sw, iregFS )
|
|
DEFOPRND(RdSwGS, Rd, Sw, iregGS )
|
|
DEFOPRND(RdSwSS, Rd, Sw, iregSS )
|
|
DEFOPRND(RdTd, Rd, Td, 4 )
|
|
DEFOPRND(RdXb, Rd, X, 1 )
|
|
DEFOPRND(RdXv, Rd, X, 0 )
|
|
DEFOPRND(RdYb, Rd, Y, 1 )
|
|
DEFOPRND(RdYv, Rd, Y, 0 )
|
|
DEFOPRND(RdZb, Rd, Z, 1 )
|
|
DEFOPRND(RwEb, Rw, Modrm, 1 )
|
|
DEFOPRND(RwEv, Rw, Modrm, 0 )
|
|
DEFOPRND(RwEw, Rw, Modrm, 2 )
|
|
DEFOPRND(RwGb, Rw, ModrmReg, 1 )
|
|
DEFOPRND(RwGdOp, Rw, GvOp, 4 )
|
|
DEFOPRND(RwGv, Rw, ModrmReg, 0 )
|
|
DEFOPRND(RwGvOp, Rw, GvOp, 0 )
|
|
DEFOPRND(RwMq, Rw, Modrm, 8 )
|
|
DEFOPRND(RwMv, Wr, MmModrmReg, 0 )
|
|
DEFOPRND(RwRbAL, Rw, Rb, iregAL )
|
|
DEFOPRND(RwRvAX, Rw, Rv, iregAX )
|
|
DEFOPRND(ST, Nil, ST, 0 )
|
|
DEFOPRND(STi, Nil, STi, 0 )
|
|
DEFOPRND(WrCd, Wr, Cd, 4 )
|
|
DEFOPRND(WrDd, Wr, Dd, 4 )
|
|
DEFOPRND(WrEb, Wr, Modrm, 1 )
|
|
DEFOPRND(WrEv, Wr, Modrm, 0 )
|
|
DEFOPRND(WrEw, Wr, Modrm, 2 )
|
|
DEFOPRND(WrGb, Wr, ModrmReg, 1 )
|
|
DEFOPRND(WrGbOp, Wr, GvOp, 1 )
|
|
DEFOPRND(WrGd, Wr, ModrmReg, 4 )
|
|
DEFOPRND(WrGv, Wr, ModrmReg, 0 )
|
|
DEFOPRND(WrGvOp, Wr, GvOp, 0 )
|
|
DEFOPRND(WrMcache, Wr, Modrm, 32 ) // UNDONE: Really cache line
|
|
DEFOPRND(WrMd, Wr, Modrm, 4 )
|
|
DEFOPRND(WrMenv, Wr, Modrm, 0 )
|
|
DEFOPRND(WrMmd, Wr, MmModrm, 4 )
|
|
DEFOPRND(WrMmq, Wr, MmModrm, 8 )
|
|
DEFOPRND(WrMq, Wr, Modrm, 8 )
|
|
DEFOPRND(WrMs, Wr, Modrm, 6 )
|
|
DEFOPRND(WrMsta, Wr, Modrm, 0 )
|
|
DEFOPRND(WrMt, Wr, Modrm, 10 )
|
|
DEFOPRND(WrMv, Wr, MmModrmReg, 0 )
|
|
DEFOPRND(WrMw, Wr, Modrm, 2 )
|
|
DEFOPRND(WrOb, Wr, Offset, 1 )
|
|
DEFOPRND(WrOv, Wr, Offset, 0 )
|
|
DEFOPRND(WrRbAL, Wr, Rb, iregAL )
|
|
DEFOPRND(WrRd, Wr, Modrm, 4 )
|
|
DEFOPRND(WrRwAX, Wr, Rw, iregAX )
|
|
DEFOPRND(WrRvAX, Wr, Rv, iregAX )
|
|
DEFOPRND(WrSw, Wr, ModrmSReg, 0 )
|
|
DEFOPRND(WrSwDS, Wr, Sw, iregDS )
|
|
DEFOPRND(WrSwES, Wr, Sw, iregES )
|
|
DEFOPRND(WrSwFS, Wr, Sw, iregFS )
|
|
DEFOPRND(WrSwGS, Wr, Sw, iregGS )
|
|
DEFOPRND(WrSwSS, Wr, Sw, iregSS )
|
|
DEFOPRND(WrTd, Wr, Td, 4 )
|
|
DEFOPRND(WrYb, Wr, Y, 1 )
|
|
DEFOPRND(WrYv, Wr, Y, 0 )
|
|
|
|
|
|
// The following are default operand sets. These are sets of three
|
|
// operands that form the base for all possible instructions. The
|
|
// operand definitions may be incomplete and require information
|
|
// to be filled in by the instruction decoding process.
|
|
|
|
|
|
#if 1
|
|
|
|
// UNDONE: Work around problem initializing with const structs
|
|
|
|
#define REFOPRND(oprnd_) \
|
|
{ \
|
|
oprnd ## oprnd_ ## _opreft, \
|
|
oprnd ## oprnd_ ## _oprndt, \
|
|
oprnd ## oprnd_ ## _b \
|
|
}
|
|
|
|
#else
|
|
|
|
#define REFOPRND(oprnd_) \
|
|
oprnd ## oprnd_
|
|
|
|
#endif
|
|
|
|
#define DEFOPS(name, modrmt_, icb_, oprnd1, oprnd2, oprnd3) \
|
|
const OPS ops ## name = \
|
|
{ \
|
|
modrmt ## modrmt_, \
|
|
icb ## icb_, \
|
|
{ \
|
|
REFOPRND(oprnd1), \
|
|
REFOPRND(oprnd2), \
|
|
REFOPRND(oprnd3) \
|
|
} \
|
|
};
|
|
|
|
// name, modrmt, icb, oprnd1, oprnd2, oprnd3
|
|
|
|
DEFOPS(Nil, No, Nil, Nil, Nil, Nil ) // AAA
|
|
|
|
DEFOPS(3, No, Nil, 3, Nil, Nil ) // INT 3
|
|
DEFOPS(AP, No, AP, AP, Nil, Nil ) // CALL ptr16:16/32
|
|
DEFOPS(Ib, No, Ib, Ib, Nil, Nil ) // INT imm8
|
|
DEFOPS(Ib_RdRbAL, No, Ib, Ib, RdRbAL, Nil ) // OUT imm8,AL
|
|
DEFOPS(Ib_RdRvAX, No, Ib, Ib, RdRvAX, Nil ) // OUT imm8,eAX
|
|
DEFOPS(Iv, No, Iv, Iv, Nil, Nil ) // PUSH imm
|
|
DEFOPS(Iw, No, Iw, Iw, Nil, Nil ) // RET imm16
|
|
DEFOPS(Iw_Ib, No, Iw_Ib, Iw, Ib2, Nil ) // ENTER imm16,imm8
|
|
DEFOPS(Jb, No, Jb, Jb, Nil, Nil ) // JA rel8
|
|
DEFOPS(Jv, No, Jv, Jv, Nil, Nil ) // CALL rel
|
|
DEFOPS(M, No, Nil, M, Nil, Nil ) // INVLPG m
|
|
DEFOPS(RdEb, Yes, Nil, RdEb, Nil, Nil ) // IDIV r/m8
|
|
DEFOPS(RdEb_Ib, Yes, Ib, RdEb, Ib, Nil ) // CMP r/m8,imm8
|
|
DEFOPS(RdEb_RdGb, Yes, Nil, RdEb, RdGb, Nil ) // CMP r/m8,r8
|
|
DEFOPS(RdEv, Yes, Nil, RdEv, Nil, Nil ) // CALL r/m
|
|
DEFOPS(RdEv_Ib, Yes, Ib, RdEv, Ib, Nil ) // BT r/m,imm8
|
|
DEFOPS(RdEv_Iv, Yes, Iv, RdEv, Iv, Nil ) // CMP r/m,imm
|
|
DEFOPS(RdEv_RdGv, Yes, Nil, RdEv, RdGv, Nil ) // BT r/m,r
|
|
DEFOPS(RdEw, Yes, Nil, RdEw, Nil, Nil ) // LLDT r/m16
|
|
DEFOPS(RdGb_RdEb, Yes, Nil, RdGb, RdEb, Nil ) // CMP r8,r/m8
|
|
DEFOPS(RdGv_RdEv, Yes, Nil, RdGv, RdEv, Nil ) // CMP r,r/m
|
|
DEFOPS(RdGv_RdMa, Mem, Nil, RdGv, RdMa, Nil ) // BOUND r,m
|
|
DEFOPS(RdGvOp, No, Nil, RdGvOp, Nil, Nil ) // PUSH r
|
|
DEFOPS(RdMd, Mem, Nil, RdMd, Nil, Nil ) // FADD m32
|
|
DEFOPS(RdMenv, Mem, Nil, RdMenv, Nil, Nil ) // FLDENV m14/28
|
|
DEFOPS(RdMp, Mem, Nil, RdMp, Nil, Nil ) // CALL m16:16/32
|
|
DEFOPS(RdMq, Mem, Nil, RdMq, Nil, Nil ) // FADD m64
|
|
DEFOPS(RdMs, Mem, Nil, RdMs, Nil, Nil ) // LGDT m48
|
|
DEFOPS(RdMsta, Mem, Nil, RdMsta, Nil, Nil ) // FRSTOR m94/108
|
|
DEFOPS(RdMt, Mem, Nil, RdMt, Nil, Nil ) // FBLD m80
|
|
DEFOPS(RdMw, Mem, Nil, RdMw, Nil, Nil ) // FIADD m16
|
|
DEFOPS(RdRbAL_Ib, No, Ib, RdRbAL, Ib, Nil ) // CMP AL,imm8
|
|
DEFOPS(RdRvAX_Iv, No, Iv, RdRvAX, Iv, Nil ) // CMP eAX,imm
|
|
DEFOPS(RdRwDX_RdRbAL, No, Nil, RdRwDX, RdRbAL, Nil ) // OUT DX,AL
|
|
DEFOPS(RdRwDX_RdRvAX, No, Nil, RdRwDX, RdRvAX, Nil ) // OUT DX,eAX
|
|
DEFOPS(RdRwDX_RdXb, No, Nil, RdRwDX, RdXb, Nil ) // OUTS m8
|
|
DEFOPS(RdRwDX_RdXv, No, Nil, RdRwDX, RdXv, Nil ) // OUTS m
|
|
DEFOPS(RdSwCS, No, Nil, RdSwCS, Nil, Nil ) // PUSH CS
|
|
DEFOPS(RdSwDS, No, Nil, RdSwDS, Nil, Nil ) // PUSH DS
|
|
DEFOPS(RdSwES, No, Nil, RdSwES, Nil, Nil ) // PUSH ES
|
|
DEFOPS(RdSwFS, No, Nil, RdSwFS, Nil, Nil ) // PUSH FS
|
|
DEFOPS(RdSwGS, No, Nil, RdSwGS, Nil, Nil ) // PUSH GS
|
|
DEFOPS(RdSwSS, No, Nil, RdSwSS, Nil, Nil ) // PUSH SS
|
|
DEFOPS(RdXb, No, Nil, RdXb, Nil, Nil ) // LODS m8
|
|
DEFOPS(RdXb_RdYb, No, Nil, RdXb, RdYb, Nil ) // CMPS m8,m8
|
|
DEFOPS(RdXv, No, Nil, RdXv, Nil, Nil ) // LODS m
|
|
DEFOPS(RdXv_RdYv, No, Nil, RdXv, RdYv, Nil ) // CMPS m,m
|
|
DEFOPS(RdYb, No, Nil, RdYb, Nil, Nil ) // SCAS m8
|
|
DEFOPS(RdYv, No, Nil, RdYv, Nil, Nil ) // SCAS m
|
|
DEFOPS(RdZb, No, Nil, RdZb, Nil, Nil ) // XLAT m
|
|
DEFOPS(RwEb, Yes, Nil, RwEb, Nil, Nil ) // DEC r/m8
|
|
DEFOPS(RwEb_1, Yes, Nil, RwEb, 1, Nil ) // RCL r/m8,1
|
|
DEFOPS(RwEb_Ib, Yes, Ib, RwEb, Ib, Nil ) // RCL r/m8,imm8
|
|
DEFOPS(RwEb_RdGb, Yes, Nil, RwEb, RdGb, Nil ) // ADC r/m8,r8
|
|
DEFOPS(RwEb_RdRbCL, Yes, Nil, RwEb, RdRbCL, Nil ) // RCL r/m8,CL
|
|
DEFOPS(RwEb_RwGb, Yes, Nil, RwEb, RwGb, Nil ) // CMPXCHG r/m8,r8
|
|
DEFOPS(RwEv, Yes, Nil, RwEv, Nil, Nil ) // DEC r/m
|
|
DEFOPS(RwEv_1, Yes, Nil, RwEv, 1, Nil ) // RCL r/m,1
|
|
DEFOPS(RwEv_Ib, Yes, Ib, RwEv, Ib, Nil ) // ADC r/m,imm8
|
|
DEFOPS(RwEv_Iv, Yes, Iv, RwEv, Iv, Nil ) // ADC r/m,imm
|
|
DEFOPS(RwEv_RdGv, Yes, Nil, RwEv, RdGv, Nil ) // ADC r/m,r
|
|
DEFOPS(RwEv_RdGv_Ib, Yes, Ib, RwEv, RdGv, Ib, ) // SHLD r/m,r,imm8
|
|
DEFOPS(RwEv_RdGv_RdRbCL, Yes, Nil, RwEv, RdGv, RdRbCL ) // SHLD r/m,r,CL
|
|
DEFOPS(RwEv_RdRbCL, Yes, Nil, RwEv, RdRbCL, Nil ) // RCL r/m,CL
|
|
DEFOPS(RwEv_RwGv, Yes, Nil, RwEv, RwGv, Nil ) // CMPXCHG r/m,r
|
|
DEFOPS(RwEw_RdGw, Yes, Nil, RwEw, RdGw, Nil ) // ARPL r/m16,r16
|
|
DEFOPS(RwGb_RdEb, Yes, Nil, RwGb, RdEb, Nil ) // ADC r8,r/m8
|
|
DEFOPS(RwGb_RwEb, Yes, Nil, RwGb, RwEb, Nil ) // XCHG r8,r/m8
|
|
DEFOPS(RwGdOp, No, Nil, RwGdOp, Nil, Nil ) // BSWAP r32
|
|
DEFOPS(RwGv_RdEv, Yes, Nil, RwGv, RdEv, Nil ) // ADC r,r/m
|
|
DEFOPS(RwGv_RwEv, Yes, Nil, RwGv, RwEv, Nil ) // XCHG r,r/m
|
|
DEFOPS(RwGvOp, No, Nil, RwGvOp, Nil, Nil ) // DEC r
|
|
DEFOPS(RwMq, Mem, Nil, RwMq, Nil, Nil ) // CMPXCHG8B m64
|
|
DEFOPS(RwMv_Ib, Yes, Nil, RwMv, Ib, Nil ) // PSLLW mm,imm8
|
|
DEFOPS(RwMv_RdMmq, Yes, Nil, RwMv, RdMmq, Nil ) // PACKSSWB mm,mm/m64
|
|
DEFOPS(RwRbAL_Ib, No, Ib, RwRbAL, Ib, Nil ) // ADC AL,imm8
|
|
DEFOPS(RwRbAL_RdEb, Yes, Nil, RwRbAL, RdEb, Nil ) // DIV AL,r/m8
|
|
DEFOPS(RwRvAX_Iv, No, Iv, RwRvAX, Iv, Nil ) // ADC eAX,imm
|
|
DEFOPS(RwRvAX_RdEv, Yes, Nil, RwRvAX, RdEv, Nil ) // DIV eAX,r/m
|
|
DEFOPS(RwRvAX_RwGvOp, No, Nil, RwRvAX, RwGvOp, Nil ) // XCHG eAX,r
|
|
DEFOPS(ST_STi, Yes, Nil, ST, STi, Nil ) // FADD ST,ST(i)
|
|
DEFOPS(STi, Yes, Nil, STi, Nil, Nil ) // FCOM ST(i)
|
|
DEFOPS(STi_ST, Yes, Nil, STi, ST, Nil ) // FADD ST(i),ST
|
|
DEFOPS(WrCd_RdRd, Reg, Nil, WrCd, RdRd, Nil ) // MOV CRn,r
|
|
DEFOPS(WrDd_RdRd, Reg, Nil, WrDd, RdRd, Nil ) // MOV DRn,r
|
|
DEFOPS(WrEb, Yes, Nil, WrEb, Nil, Nil ) // SETA r/m8
|
|
DEFOPS(WrEb_Ib, Yes, Ib, WrEb, Ib, Nil ) // MOV r/m8,imm8
|
|
DEFOPS(WrEb_RdGb, Yes, Nil, WrEb, RdGb, Nil ) // MOV r/m8,r8
|
|
DEFOPS(WrEv, Yes, Nil, WrEv, Nil, Nil ) // POP r/m
|
|
DEFOPS(WrEv_Iv, Yes, Iv, WrEv, Iv, Nil ) // MOV r/m,imm
|
|
DEFOPS(WrEv_RdGv, Yes, Nil, WrEv, RdGv, Nil ) // MOV r/m,r
|
|
DEFOPS(WrEvReg_RdGv, Reg, Nil, WrEv, RdGv, Nil ) // CMOV r,r
|
|
DEFOPS(WrEw, Yes, Nil, WrEw, Nil, Nil ) // SLDT r/m16
|
|
DEFOPS(WrEw_RdSw, Yes, Nil, WrEw, RdSw, Nil ) // MOV r/m16,sreg
|
|
DEFOPS(WrGb_RdEb, Yes, Nil, WrGb, RdEb, Nil ) // MOV r8,r/m8
|
|
DEFOPS(WrGbOp_Ib, No, Ib, WrGbOp, Ib, Nil ) // MOV r8,imm8
|
|
DEFOPS(WrGd_RdEw, Yes, Nil, WrGd, RdEw, Nil ) // MOVSZ r32,r/m16
|
|
DEFOPS(WrGv_M, Mem, Nil, WrGv, M, Nil ) // LEA r,m
|
|
DEFOPS(WrGv_RdEb, Yes, Nil, WrGv, RdEb, Nil ) // MOVSX r,r/m8
|
|
DEFOPS(WrGv_RdEv, Yes, Nil, WrGv, RdEv, Nil ) // BSF r,r/m
|
|
DEFOPS(WrGv_RdEv_Ib, Yes, Ib, WrGv, RdEv, Ib ) // IMUL r,r/m,imm8
|
|
DEFOPS(WrGv_RdEv_Iv, Yes, Iv, WrGv, RdEv, Ib ) // IMUL r,r/m,imm
|
|
DEFOPS(WrGv_RdEw, Yes, Nil, WrGv, RdEw, Nil ) // MOVSX r,r/m16
|
|
DEFOPS(WrGv_RdMp, Mem, Nil, WrGv, RdMp, Nil ) // LDS r,m16:16/32
|
|
DEFOPS(WrGvOp, No, Nil, WrGvOp, Nil, Nil ) // POP r
|
|
DEFOPS(WrGvOp_Iv, No, Iv, WrGvOp, Iv, Nil ) // MOV r,imm
|
|
DEFOPS(WrMcache, Mem, Nil, WrMcache, Nil, Nil ) // ZALLOC m
|
|
DEFOPS(WrMd, Mem, Nil, WrMd, Nil, Nil ) // FST m32
|
|
DEFOPS(WrMenv, Mem, Nil, WrMenv, Nil, Nil ) // FSTENV m14/28
|
|
DEFOPS(WrMmd_RdMv, Yes, Nil, WrMmd, RdMv, Nil ) // MOVD mm,r/m32
|
|
DEFOPS(WrMmq_RdMv, Yes, Nil, WrMmq, RdMv, Nil ) // MOVQ mm,r/m64
|
|
DEFOPS(WrMq, Mem, Nil, WrMq, Nil, Nil ) // FST m64
|
|
DEFOPS(WrMs, Mem, Nil, WrMs, Nil, Nil ) // SGDT m48
|
|
DEFOPS(WrMsta, Mem, Nil, WrMsta, Nil, Nil ) // FNSAVE m94/108
|
|
DEFOPS(WrMt, Mem, Nil, WrMt, Nil, Nil ) // FBSTP m80
|
|
DEFOPS(WrMt_RdSw, Mem, Nil, WrMt, RdSw, Nil ) // SVDC m80,sreg
|
|
DEFOPS(WrMv_RdMmd, Yes, Nil, WrMv, RdMmd, Nil ) // MOVD r/m32,mm
|
|
DEFOPS(WrMv_RdMmq, Yes, Nil, WrMv, RdMmq, Nil ) // MOVQ r/m64,mm
|
|
DEFOPS(WrMw, Mem, Nil, WrMw, Nil, Nil ) // FNSTCW m16
|
|
DEFOPS(WrOb_RdRbAL, No, O, WrOb, RdRbAL, Nil ) // MOV moffs8,AL
|
|
DEFOPS(WrOv_RdRvAX, No, O, WrOv, RdRvAX, Nil ) // MOV moffs,eAX
|
|
DEFOPS(WrRbAL_Ib, No, Ib, WrRbAL, Ib, Nil ) // IN AL,imm8
|
|
DEFOPS(WrRbAL_RdOb, No, O, WrRbAL, RdOb, Nil ) // MOV AL,moffs8
|
|
DEFOPS(WrRbAL_RdRwDX, No, Nil, WrRbAL, RdRwDX, Nil ) // IN AL,DX
|
|
DEFOPS(WrRd_RdCd, Reg, Nil, WrRd, RdCd, Nil ) // MOV r,CRn
|
|
DEFOPS(WrRd_RdDd, Reg, Nil, WrRd, RdDd, Nil ) // MOV r,DRn
|
|
DEFOPS(WrRd_RdTd, Reg, Nil, WrRd, RdTd, Nil ) // MOV r,TRn
|
|
DEFOPS(WrRwAX, Yes, Nil, WrRwAX, Nil, Nil ) // FNSTSW AX
|
|
DEFOPS(WrRvAX_Ib, No, Ib, WrRvAX, Ib, Nil ) // IN eAX,imm8
|
|
DEFOPS(WrRvAX_RdOv, No, O, WrRvAX, RdOv, Nil ) // MOV eAX,moffs
|
|
DEFOPS(WrRvAX_RdRwDX, No, Nil, WrRvAX, RdRwDX, Nil ) // IN eAX,DX
|
|
DEFOPS(WrSw_RdEw, Yes, Nil, WrSw, RdEw, Nil ) // MOV sreg,r/m16,r16
|
|
DEFOPS(WrSw_RdMt, Mem, Nil, WrSw, RdMt, Nil ) // RSDC sreg,m80
|
|
DEFOPS(WrSwDS, No, Nil, WrSwDS, Nil, Nil ) // POP DS
|
|
DEFOPS(WrSwES, No, Nil, WrSwES, Nil, Nil ) // POP ES
|
|
DEFOPS(WrSwFS, No, Nil, WrSwFS, Nil, Nil ) // POP FS
|
|
DEFOPS(WrSwGS, No, Nil, WrSwGS, Nil, Nil ) // POP GS
|
|
DEFOPS(WrSwSS, No, Nil, WrSwSS, Nil, Nil ) // POP SS
|
|
DEFOPS(WrTd_RdRd, Reg, Nil, WrTd, RdRd, Nil ) // MOV TRn,r
|
|
DEFOPS(WrYb, No, Nil, WrYb, Nil, Nil ) // STOS m8
|
|
DEFOPS(WrYb_RdRwDX, No, Nil, WrYb, RdRwDX, Nil ) // INS m8,DX
|
|
DEFOPS(WrYb_RdXb, No, Nil, WrYb, RdXb, Nil ) // MOVS m8,m8
|
|
DEFOPS(WrYv, No, Nil, WrYv, Nil, Nil ) // STOS m
|
|
DEFOPS(WrYv_RdRwDX, No, Nil, WrYv, RdRwDX, Nil ) // INS m,DX
|
|
DEFOPS(WrYv_RdXv, No, Nil, WrYv, RdXv, Nil ) // MOVS m,m
|
|
|
|
|
|
#define DEFOPCD(pvMnemonic, ops_, trmtx86_) \
|
|
{ \
|
|
pvMnemonic, \
|
|
&ops ## ops_, \
|
|
trmtx86 ## trmtx86_ \
|
|
}
|
|
|
|
|
|
#define DEFOGRP(name) \
|
|
{ \
|
|
&rgopcd ## name, \
|
|
NULL, \
|
|
trmtx86Unknown \
|
|
}
|
|
|
|
|
|
const OPCD rgopcd80[8] = // Grp 1
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("add", RwEb_Ib, FallThrough ), // 00
|
|
DEFOPCD("or", RwEb_Ib, FallThrough ), // 01
|
|
DEFOPCD("adc", RwEb_Ib, FallThrough ), // 02
|
|
DEFOPCD("sbb", RwEb_Ib, FallThrough ), // 03
|
|
DEFOPCD("and", RwEb_Ib, FallThrough ), // 04
|
|
DEFOPCD("sub", RwEb_Ib, FallThrough ), // 05
|
|
DEFOPCD("xor", RwEb_Ib, FallThrough ), // 06
|
|
DEFOPCD("cmp", RdEb_Ib, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcd81[8] = // Grp 1
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("add", RwEv_Iv, FallThrough ), // 00
|
|
DEFOPCD("or", RwEv_Iv, FallThrough ), // 01
|
|
DEFOPCD("adc", RwEv_Iv, FallThrough ), // 02
|
|
DEFOPCD("sbb", RwEv_Iv, FallThrough ), // 03
|
|
DEFOPCD("and", RwEv_Iv, FallThrough ), // 04
|
|
DEFOPCD("sub", RwEv_Iv, FallThrough ), // 05
|
|
DEFOPCD("xor", RwEv_Iv, FallThrough ), // 06
|
|
DEFOPCD("cmp", RdEv_Iv, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcd83[8] = // Grp 1
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("add", RwEv_Ib, FallThrough ), // 00
|
|
DEFOPCD("or", RwEv_Ib, FallThrough ), // 01
|
|
DEFOPCD("adc", RwEv_Ib, FallThrough ), // 02
|
|
DEFOPCD("sbb", RwEv_Ib, FallThrough ), // 03
|
|
DEFOPCD("and", RwEv_Ib, FallThrough ), // 04
|
|
DEFOPCD("sub", RwEv_Ib, FallThrough ), // 05
|
|
DEFOPCD("xor", RwEv_Ib, FallThrough ), // 06
|
|
DEFOPCD("cmp", RdEv_Ib, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdC0[8] = // Grp 2
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("rol", RwEb_Ib, FallThrough ), // 00
|
|
DEFOPCD("ror", RwEb_Ib, FallThrough ), // 01
|
|
DEFOPCD("rcl", RwEb_Ib, FallThrough ), // 02
|
|
DEFOPCD("rcr", RwEb_Ib, FallThrough ), // 03
|
|
DEFOPCD("shl", RwEb_Ib, FallThrough ), // 04
|
|
DEFOPCD("shr", RwEb_Ib, FallThrough ), // 05
|
|
DEFOPCD("sal", RwEb_Ib, FallThrough ), // 06
|
|
DEFOPCD("sar", RwEb_Ib, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdC1[8] = // Grp 2
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("rol", RwEv_Ib, FallThrough ), // 00
|
|
DEFOPCD("ror", RwEv_Ib, FallThrough ), // 01
|
|
DEFOPCD("rcl", RwEv_Ib, FallThrough ), // 02
|
|
DEFOPCD("rcr", RwEv_Ib, FallThrough ), // 03
|
|
DEFOPCD("shl", RwEv_Ib, FallThrough ), // 04
|
|
DEFOPCD("shr", RwEv_Ib, FallThrough ), // 05
|
|
DEFOPCD("sal", RwEv_Ib, FallThrough ), // 06
|
|
DEFOPCD("sar", RwEv_Ib, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdD0[8] = // Grp 2
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("rol", RwEb_1, FallThrough ), // 00
|
|
DEFOPCD("ror", RwEb_1, FallThrough ), // 01
|
|
DEFOPCD("rcl", RwEb_1, FallThrough ), // 02
|
|
DEFOPCD("rcr", RwEb_1, FallThrough ), // 03
|
|
DEFOPCD("shl", RwEb_1, FallThrough ), // 04
|
|
DEFOPCD("shr", RwEb_1, FallThrough ), // 05
|
|
DEFOPCD("sal", RwEb_1, FallThrough ), // 06
|
|
DEFOPCD("sar", RwEb_1, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdD1[8] = // Grp 2
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("rol", RwEv_1, FallThrough ), // 00
|
|
DEFOPCD("ror", RwEv_1, FallThrough ), // 01
|
|
DEFOPCD("rcl", RwEv_1, FallThrough ), // 02
|
|
DEFOPCD("rcr", RwEv_1, FallThrough ), // 03
|
|
DEFOPCD("shl", RwEv_1, FallThrough ), // 04
|
|
DEFOPCD("shr", RwEv_1, FallThrough ), // 05
|
|
DEFOPCD("sal", RwEv_1, FallThrough ), // 06
|
|
DEFOPCD("sar", RwEv_1, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdD2[8] = // Grp 2
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("rol", RwEb_RdRbCL, FallThrough ), // 00
|
|
DEFOPCD("ror", RwEb_RdRbCL, FallThrough ), // 01
|
|
DEFOPCD("rcl", RwEb_RdRbCL, FallThrough ), // 02
|
|
DEFOPCD("rcr", RwEb_RdRbCL, FallThrough ), // 03
|
|
DEFOPCD("shl", RwEb_RdRbCL, FallThrough ), // 04
|
|
DEFOPCD("shr", RwEb_RdRbCL, FallThrough ), // 05
|
|
DEFOPCD("sal", RwEb_RdRbCL, FallThrough ), // 06
|
|
DEFOPCD("sar", RwEb_RdRbCL, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdD3[8] = // Grp 2
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("rol", RwEv_RdRbCL, FallThrough ), // 00
|
|
DEFOPCD("ror", RwEv_RdRbCL, FallThrough ), // 01
|
|
DEFOPCD("rcl", RwEv_RdRbCL, FallThrough ), // 02
|
|
DEFOPCD("rcr", RwEv_RdRbCL, FallThrough ), // 03
|
|
DEFOPCD("shl", RwEv_RdRbCL, FallThrough ), // 04
|
|
DEFOPCD("shr", RwEv_RdRbCL, FallThrough ), // 05
|
|
DEFOPCD("sal", RwEv_RdRbCL, FallThrough ), // 06
|
|
DEFOPCD("sar", RwEv_RdRbCL, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdF6[8] = // Grp 3
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("test", RdEb_Ib, FallThrough ), // 00
|
|
DEFOPCD("test", RdEb_Ib, FallThrough ), // 01
|
|
DEFOPCD("not", RwEb, FallThrough ), // 02
|
|
DEFOPCD("neg", RwEb, FallThrough ), // 03
|
|
DEFOPCD("mul", RwRbAL_RdEb, FallThrough ), // 04
|
|
DEFOPCD("imul", RdEb, FallThrough ), // 05
|
|
DEFOPCD("div", RwRbAL_RdEb, TrapCc ), // 06
|
|
DEFOPCD("idiv", RdEb, TrapCc ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdF7[8] = // Grp 3
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("test", RdEv_Iv, FallThrough ), // 00
|
|
DEFOPCD("test", RdEv_Iv, FallThrough ), // 01
|
|
DEFOPCD("not", RwEv, FallThrough ), // 02
|
|
DEFOPCD("neg", RwEv, FallThrough ), // 03
|
|
DEFOPCD("mul", RwRvAX_RdEv, FallThrough ), // 04
|
|
DEFOPCD("imul", RdEv, FallThrough ), // 05
|
|
DEFOPCD("div", RwRvAX_RdEv, TrapCc ), // 06
|
|
DEFOPCD("idiv", RwRvAX_RdEv, TrapCc ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdFE[8] = // Grp 4
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("inc", RwEb, FallThrough ), // 00
|
|
DEFOPCD("dec", RwEb, FallThrough ), // 01
|
|
DEFOPCD(NULL, Nil, Unknown ), // 02
|
|
DEFOPCD(NULL, Nil, Unknown ), // 03
|
|
DEFOPCD(NULL, Nil, Unknown ), // 04
|
|
DEFOPCD(NULL, Nil, Unknown ), // 05
|
|
DEFOPCD(NULL, Nil, Unknown ), // 06
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdFF[8] = // Grp 5
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("inc", RwEv, FallThrough ), // 00
|
|
DEFOPCD("dec", RwEv, FallThrough ), // 01
|
|
DEFOPCD("call", RdEv, CallInd ), // 02
|
|
DEFOPCD("call", RdMp, CallInd ), // 03
|
|
DEFOPCD("jmp", RdEv, JmpInd ), // 04
|
|
DEFOPCD("jmp", RdMp, JmpInd ), // 05
|
|
DEFOPCD("push", RdEv, FallThrough ), // 06
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
};
|
|
|
|
const OPCD rgopcd0F00[8] = // Grp 6
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("sldt", WrEw, FallThrough ), // 00
|
|
DEFOPCD("str", WrEw, FallThrough ), // 01
|
|
DEFOPCD("lldt", RdEw, FallThrough ), // 02
|
|
DEFOPCD("ltr", RdEw, FallThrough ), // 03
|
|
DEFOPCD("verr", RdEw, FallThrough ), // 04
|
|
DEFOPCD("verw", RdEw, FallThrough ), // 05
|
|
DEFOPCD(NULL, Nil, Unknown ), // 06
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
};
|
|
|
|
const OPCD rgopcd0F01[8] = // Grp 7
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("sgdt", WrMs, FallThrough ), // 00
|
|
DEFOPCD("sidt", WrMs, FallThrough ), // 01
|
|
DEFOPCD("lgdt", RdMs, FallThrough ), // 02
|
|
DEFOPCD("lidt", RdMs, FallThrough ), // 03
|
|
DEFOPCD("smsw", WrEw, FallThrough ), // 04
|
|
DEFOPCD(NULL, Nil, Unknown ), // 05
|
|
DEFOPCD("lmsw", RdEw, FallThrough ), // 06
|
|
DEFOPCD("invlpg", M, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcd0F71[8] =
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD(NULL, Nil, Unknown ), // 00
|
|
DEFOPCD(NULL, Nil, Unknown ), // 01
|
|
DEFOPCD("psrlw", RwMv_Ib, FallThrough ), // 02 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // 03
|
|
DEFOPCD("psraw", RwMv_Ib, FallThrough ), // 04 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // 05
|
|
DEFOPCD("psllw", RwMv_Ib, FallThrough ), // 06 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
};
|
|
|
|
const OPCD rgopcd0F72[8] =
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD(NULL, Nil, Unknown ), // 00
|
|
DEFOPCD(NULL, Nil, Unknown ), // 01
|
|
DEFOPCD("psrld", RwMv_Ib, FallThrough ), // 02 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // 03
|
|
DEFOPCD("psrad", RwMv_Ib, FallThrough ), // 04 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // 05
|
|
DEFOPCD("pslld", RwMv_Ib, FallThrough ), // 06 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
};
|
|
|
|
const OPCD rgopcd0F73[8] =
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD(NULL, Nil, Unknown ), // 00
|
|
DEFOPCD(NULL, Nil, Unknown ), // 01
|
|
DEFOPCD("psrlq", RwMv_Ib, FallThrough ), // 02 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // 03
|
|
DEFOPCD(NULL, Nil, Unknown ), // 04
|
|
DEFOPCD(NULL, Nil, Unknown ), // 05
|
|
DEFOPCD("psllq", RwMv_Ib, FallThrough ), // 06 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
};
|
|
|
|
const OPCD rgopcd0FBA[8] = // Grp 8
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD(NULL, Nil, Unknown ), // 00
|
|
DEFOPCD(NULL, Nil, Unknown ), // 01
|
|
DEFOPCD(NULL, Nil, Unknown ), // 02
|
|
DEFOPCD(NULL, Nil, Unknown ), // 03
|
|
DEFOPCD("bt", RdEv_Ib, FallThrough ), // 04
|
|
DEFOPCD("bts", RwEv_Ib, FallThrough ), // 05
|
|
DEFOPCD("btr", RwEv_Ib, FallThrough ), // 06
|
|
DEFOPCD("btc", RwEv_Ib, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcd0FC7[8] =
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD(NULL, Nil, Unknown ), // 00
|
|
DEFOPCD("cmpxchg8b", RwMq, FallThrough ), // 01
|
|
DEFOPCD(NULL, Nil, Unknown ), // 02
|
|
DEFOPCD(NULL, Nil, Unknown ), // 03
|
|
DEFOPCD(NULL, Nil, Unknown ), // 04
|
|
DEFOPCD(NULL, Nil, Unknown ), // 05
|
|
DEFOPCD(NULL, Nil, Unknown ), // 06
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdD8[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fadd", RdMd, FallThrough ), // 00
|
|
DEFOPCD("fmul", RdMd, FallThrough ), // 01
|
|
DEFOPCD("fcom", RdMd, FallThrough ), // 02
|
|
DEFOPCD("fcomp", RdMd, FallThrough ), // 03
|
|
DEFOPCD("fsub", RdMd, FallThrough ), // 04
|
|
DEFOPCD("fsubr", RdMd, FallThrough ), // 05
|
|
DEFOPCD("fdiv", RdMd, FallThrough ), // 06
|
|
DEFOPCD("fdivr", RdMd, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdD9[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fld", RdMd, FallThrough ), // 00
|
|
DEFOPCD(NULL, Nil, Unknown ), // 01
|
|
DEFOPCD("fst", WrMd, FallThrough ), // 02
|
|
DEFOPCD("fstp", WrMd, FallThrough ), // 03
|
|
DEFOPCD("fldenv", RdMenv, FallThrough ), // 04
|
|
DEFOPCD("fldcw", RdMw, FallThrough ), // 05
|
|
DEFOPCD("fnstenv", WrMenv, FallThrough ), // 06
|
|
DEFOPCD("fnstcw", WrMw, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdDA[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fiadd", RdMd, FallThrough ), // 00
|
|
DEFOPCD("fimul", RdMd, FallThrough ), // 01
|
|
DEFOPCD("ficom", RdMd, FallThrough ), // 02
|
|
DEFOPCD("ficomp", RdMd, FallThrough ), // 03
|
|
DEFOPCD("fisub", RdMd, FallThrough ), // 04
|
|
DEFOPCD("fisubr", RdMd, FallThrough ), // 05
|
|
DEFOPCD("fidiv", RdMd, FallThrough ), // 06
|
|
DEFOPCD("fidivr", RdMd, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdDB[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fild", RdMd, FallThrough ), // 00
|
|
DEFOPCD(NULL, Nil, Unknown ), // 01
|
|
DEFOPCD("fist", WrMd, FallThrough ), // 02
|
|
DEFOPCD("fistp", WrMd, FallThrough ), // 03
|
|
DEFOPCD(NULL, Nil, Unknown ), // 04
|
|
DEFOPCD("fld", RdMt, FallThrough ), // 05
|
|
DEFOPCD(NULL, Nil, Unknown ), // 06
|
|
DEFOPCD("fstp", WrMt, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdDC[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fadd", RdMq, FallThrough ), // 00
|
|
DEFOPCD("fmul", RdMq, FallThrough ), // 01
|
|
DEFOPCD("fcom", RdMq, FallThrough ), // 02
|
|
DEFOPCD("fcomp", RdMq, FallThrough ), // 03
|
|
DEFOPCD("fsub", RdMq, FallThrough ), // 04
|
|
DEFOPCD("fsubr", RdMq, FallThrough ), // 05
|
|
DEFOPCD("fdiv", RdMq, FallThrough ), // 06
|
|
DEFOPCD("fdivr", RdMq, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdDD[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fld", RdMq, FallThrough ), // 00
|
|
DEFOPCD(NULL, Nil, Unknown ), // 01
|
|
DEFOPCD("fst", WrMq, FallThrough ), // 02
|
|
DEFOPCD("fstp", WrMq, FallThrough ), // 03
|
|
DEFOPCD("frstor", RdMsta, FallThrough ), // 04
|
|
DEFOPCD(NULL, Nil, Unknown ), // 05
|
|
DEFOPCD("fnsave", WrMsta, FallThrough ), // 06
|
|
DEFOPCD("fnstsw", WrMw, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdDE[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fiadd", RdMw, FallThrough ), // 00
|
|
DEFOPCD("fimul", RdMw, FallThrough ), // 01
|
|
DEFOPCD("ficom", RdMw, FallThrough ), // 02
|
|
DEFOPCD("ficomp", RdMw, FallThrough ), // 03
|
|
DEFOPCD("fisub", RdMw, FallThrough ), // 04
|
|
DEFOPCD("fisubr", RdMw, FallThrough ), // 05
|
|
DEFOPCD("fidiv", RdMw, FallThrough ), // 06
|
|
DEFOPCD("fidivr", RdMw, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdDF[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fild", RdMq, FallThrough ), // 00
|
|
DEFOPCD(NULL, Nil, Unknown ), // 01
|
|
DEFOPCD("fist", WrMq, FallThrough ), // 02
|
|
DEFOPCD("fistp", WrMq, FallThrough ), // 03
|
|
DEFOPCD("fbld", RdMt, FallThrough ), // 04
|
|
DEFOPCD("fild", RdMq, FallThrough ), // 05
|
|
DEFOPCD("fbstp", WrMt, FallThrough ), // 06
|
|
DEFOPCD("fistp", WrMq, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdD8_[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fadd", ST_STi, FallThrough ), // 00
|
|
DEFOPCD("fmul", ST_STi, FallThrough ), // 01
|
|
DEFOPCD("fcom", STi, FallThrough ), // 02
|
|
DEFOPCD("fcomp", STi, FallThrough ), // 03
|
|
DEFOPCD("fsub", ST_STi, FallThrough ), // 04
|
|
DEFOPCD("fsubr", ST_STi, FallThrough ), // 05
|
|
DEFOPCD("fdiv", ST_STi, FallThrough ), // 06
|
|
DEFOPCD("fdivr", ST_STi, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdD9_[64] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fld", STi, FallThrough ), // 00
|
|
DEFOPCD("fld", STi, FallThrough ), // 01
|
|
DEFOPCD("fld", STi, FallThrough ), // 02
|
|
DEFOPCD("fld", STi, FallThrough ), // 03
|
|
DEFOPCD("fld", STi, FallThrough ), // 04
|
|
DEFOPCD("fld", STi, FallThrough ), // 05
|
|
DEFOPCD("fld", STi, FallThrough ), // 06
|
|
DEFOPCD("fld", STi, FallThrough ), // 07
|
|
DEFOPCD("fxch", STi, FallThrough ), // 08
|
|
DEFOPCD("fxch", STi, FallThrough ), // 09
|
|
DEFOPCD("fxch", STi, FallThrough ), // 0A
|
|
DEFOPCD("fxch", STi, FallThrough ), // 0B
|
|
DEFOPCD("fxch", STi, FallThrough ), // 0C
|
|
DEFOPCD("fxch", STi, FallThrough ), // 0D
|
|
DEFOPCD("fxch", STi, FallThrough ), // 0E
|
|
DEFOPCD("fxch", STi, FallThrough ), // 0F
|
|
DEFOPCD("fnop", Nil, FallThrough ), // 10
|
|
DEFOPCD(NULL, Nil, Unknown ), // 11
|
|
DEFOPCD(NULL, Nil, Unknown ), // 12
|
|
DEFOPCD(NULL, Nil, Unknown ), // 13
|
|
DEFOPCD(NULL, Nil, Unknown ), // 14
|
|
DEFOPCD(NULL, Nil, Unknown ), // 15
|
|
DEFOPCD(NULL, Nil, Unknown ), // 16
|
|
DEFOPCD(NULL, Nil, Unknown ), // 17
|
|
DEFOPCD(NULL, Nil, Unknown ), // 18
|
|
DEFOPCD(NULL, Nil, Unknown ), // 19
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1A
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1B
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1C
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1D
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1E
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1F
|
|
DEFOPCD("fchs", Nil, FallThrough ), // 20
|
|
DEFOPCD("fabs", Nil, FallThrough ), // 21
|
|
DEFOPCD(NULL, Nil, Unknown ), // 22
|
|
DEFOPCD(NULL, Nil, Unknown ), // 23
|
|
DEFOPCD("ftst", Nil, FallThrough ), // 24
|
|
DEFOPCD("fxam", Nil, FallThrough ), // 25
|
|
DEFOPCD(NULL, Nil, Unknown ), // 26
|
|
DEFOPCD(NULL, Nil, Unknown ), // 27
|
|
DEFOPCD("fld1", Nil, FallThrough ), // 28
|
|
DEFOPCD("fldl2t", Nil, FallThrough ), // 29
|
|
DEFOPCD("fldl2e", Nil, FallThrough ), // 2A
|
|
DEFOPCD("fldpi", Nil, FallThrough ), // 2B
|
|
DEFOPCD("fldlg2", Nil, FallThrough ), // 2C
|
|
DEFOPCD("fldln2", Nil, FallThrough ), // 2D
|
|
DEFOPCD("fldz", Nil, FallThrough ), // 2E
|
|
DEFOPCD(NULL, Nil, Unknown ), // 2F
|
|
DEFOPCD("f2xm1", Nil, FallThrough ), // 30
|
|
DEFOPCD("fyl2x", Nil, FallThrough ), // 31
|
|
DEFOPCD("fptan", Nil, FallThrough ), // 32
|
|
DEFOPCD("fpatan", Nil, FallThrough ), // 33
|
|
DEFOPCD("fxtract", Nil, FallThrough ), // 34
|
|
DEFOPCD("fprem1", Nil, FallThrough ), // 35
|
|
DEFOPCD("fdecstp", Nil, FallThrough ), // 36
|
|
DEFOPCD("fincstp", Nil, FallThrough ), // 37
|
|
DEFOPCD("fprem", Nil, FallThrough ), // 38
|
|
DEFOPCD("fyl2xp1", Nil, FallThrough ), // 39
|
|
DEFOPCD("fsqrt", Nil, FallThrough ), // 3A
|
|
DEFOPCD("fsincos", Nil, FallThrough ), // 3B
|
|
DEFOPCD("frndint", Nil, FallThrough ), // 3C
|
|
DEFOPCD("fscale", Nil, FallThrough ), // 3D
|
|
DEFOPCD("fsin", Nil, FallThrough ), // 3E
|
|
DEFOPCD("fcos", Nil, FallThrough ), // 3F
|
|
};
|
|
|
|
const OPCD opcdDAE9 =
|
|
DEFOPCD("fucompp", Nil, FallThrough );
|
|
|
|
const OPCD rgopcdDA_[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fcmovb", ST_STi, FallThrough ), // 00
|
|
DEFOPCD("fcmove", ST_STi, FallThrough ), // 01
|
|
DEFOPCD("fcmovbe", ST_STi, FallThrough ), // 02
|
|
DEFOPCD("fcmovu", ST_STi, FallThrough ), // 03
|
|
DEFOPCD(NULL, Nil, Unknown ), // 04
|
|
DEFOPCD(NULL, Nil, Unknown ), // 05
|
|
DEFOPCD(NULL, Nil, Unknown ), // 06
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdDB__[17] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("feni", Nil, FallThrough ), // 00
|
|
DEFOPCD("fdisi", Nil, FallThrough ), // 01
|
|
DEFOPCD("fnclex", Nil, FallThrough ), // 02
|
|
DEFOPCD("fninit", Nil, FallThrough ), // 03
|
|
DEFOPCD("fsetpm", Nil, FallThrough ), // 04
|
|
DEFOPCD(NULL, Nil, Unknown ), // 05
|
|
DEFOPCD(NULL, Nil, Unknown ), // 06
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
DEFOPCD("fucomi", ST_STi, Unknown ), // 08
|
|
DEFOPCD(NULL, Nil, Unknown ), // 09
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0A
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0B
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0C
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0D
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0E
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0F
|
|
DEFOPCD("fcomi", ST_STi, Unknown ), // 10
|
|
};
|
|
|
|
const OPCD rgopcdDB_[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fcmovnb", ST_STi, FallThrough ), // 00
|
|
DEFOPCD("fcmovne", ST_STi, FallThrough ), // 01
|
|
DEFOPCD("fcmovnbe", ST_STi, FallThrough ), // 02
|
|
DEFOPCD("fcmovnu", ST_STi, FallThrough ), // 03
|
|
DEFOPCD(NULL, Nil, Unknown ), // 04
|
|
DEFOPCD(NULL, Nil, Unknown ), // 05
|
|
DEFOPCD(NULL, Nil, Unknown ), // 06
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdDC_[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fadd", STi_ST, FallThrough ), // 00
|
|
DEFOPCD("fmul", STi_ST, FallThrough ), // 01
|
|
DEFOPCD(NULL, Nil, Unknown ), // 02
|
|
DEFOPCD(NULL, Nil, Unknown ), // 03
|
|
DEFOPCD("fsubr", STi_ST, FallThrough ), // 04
|
|
DEFOPCD("fsub", STi_ST, FallThrough ), // 05
|
|
DEFOPCD("fdivr", STi_ST, FallThrough ), // 06
|
|
DEFOPCD("fdiv", STi_ST, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdDD_[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("ffree", STi, FallThrough ), // 00
|
|
DEFOPCD(NULL, Nil, Unknown ), // 01
|
|
DEFOPCD("fst", STi, FallThrough ), // 02
|
|
DEFOPCD("fstp", STi, FallThrough ), // 03
|
|
DEFOPCD("fucom", STi, FallThrough ), // 04
|
|
DEFOPCD("fucomp", STi, FallThrough ), // 05
|
|
DEFOPCD(NULL, Nil, Unknown ), // 06
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
};
|
|
|
|
const OPCD rgopcdDE_[8] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("faddp", STi_ST, FallThrough ), // 00
|
|
DEFOPCD("fmulp", STi_ST, FallThrough ), // 01
|
|
DEFOPCD(NULL, Nil, Unknown ), // 02
|
|
DEFOPCD(NULL, Nil, Unknown ), // 03
|
|
DEFOPCD("fsubrp", STi_ST, FallThrough ), // 04
|
|
DEFOPCD("fsubp", STi_ST, FallThrough ), // 05
|
|
DEFOPCD("fdivrp", STi_ST, FallThrough ), // 06
|
|
DEFOPCD("fdivp", STi_ST, FallThrough ), // 07
|
|
};
|
|
|
|
const OPCD opcdDED9 =
|
|
DEFOPCD("fcompp", Nil, FallThrough );
|
|
|
|
const OPCD rgopcdDF__[17] = // Floating point
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("fnstsw", WrRwAX, FallThrough ), // 00
|
|
DEFOPCD(NULL, Nil, Unknown ), // 01
|
|
DEFOPCD(NULL, Nil, Unknown ), // 02
|
|
DEFOPCD(NULL, Nil, Unknown ), // 03
|
|
DEFOPCD(NULL, Nil, Unknown ), // 04
|
|
DEFOPCD(NULL, Nil, Unknown ), // 05
|
|
DEFOPCD(NULL, Nil, Unknown ), // 06
|
|
DEFOPCD(NULL, Nil, Unknown ), // 07
|
|
DEFOPCD("fucomip", ST_STi, Unknown ), // 08
|
|
DEFOPCD(NULL, Nil, Unknown ), // 09
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0A
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0B
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0C
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0D
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0E
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0F
|
|
DEFOPCD("fcomip", ST_STi, Unknown ), // 10
|
|
};
|
|
|
|
|
|
const OPCD rgopcd[256] =
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOPCD("add", RwEb_RdGb, FallThrough ), // 00
|
|
DEFOPCD("add", RwEv_RdGv, FallThrough ), // 01
|
|
DEFOPCD("add", RwGb_RdEb, FallThrough ), // 02
|
|
DEFOPCD("add", RwGv_RdEv, FallThrough ), // 03
|
|
DEFOPCD("add", RwRbAL_Ib, FallThrough ), // 04
|
|
DEFOPCD("add", RwRvAX_Iv, FallThrough ), // 05
|
|
DEFOPCD("push", RdSwES, FallThrough ), // 06
|
|
DEFOPCD("pop", WrSwES, FallThrough ), // 07
|
|
DEFOPCD("or", RwEb_RdGb, FallThrough ), // 08
|
|
DEFOPCD("or", RwEv_RdGv, FallThrough ), // 09
|
|
DEFOPCD("or", RwGb_RdEb, FallThrough ), // 0A
|
|
DEFOPCD("or", RwGv_RdEv, FallThrough ), // 0B
|
|
DEFOPCD("or", RwRbAL_Ib, FallThrough ), // 0C
|
|
DEFOPCD("or", RwRvAX_Iv, FallThrough ), // 0D
|
|
DEFOPCD("push", RdSwCS, FallThrough ), // 0E
|
|
DEFOPCD(NULL, Nil, FallThrough ), // 0F Two byte opcode
|
|
DEFOPCD("adc", RwEb_RdGb, FallThrough ), // 10
|
|
DEFOPCD("adc", RwEv_RdGv, FallThrough ), // 11
|
|
DEFOPCD("adc", RwGb_RdEb, FallThrough ), // 12
|
|
DEFOPCD("adc", RwGv_RdEv, FallThrough ), // 13
|
|
DEFOPCD("adc", RwRbAL_Ib, FallThrough ), // 14
|
|
DEFOPCD("adc", RwRvAX_Iv, FallThrough ), // 15
|
|
DEFOPCD("push", RdSwSS, FallThrough ), // 16
|
|
DEFOPCD("pop", WrSwSS, FallThrough ), // 17
|
|
DEFOPCD("sbb", RwEb_RdGb, FallThrough ), // 18
|
|
DEFOPCD("sbb", RwEv_RdGv, FallThrough ), // 19
|
|
DEFOPCD("sbb", RwGb_RdEb, FallThrough ), // 1A
|
|
DEFOPCD("sbb", RwGv_RdEv, FallThrough ), // 1B
|
|
DEFOPCD("sbb", RwRbAL_Ib, FallThrough ), // 1C
|
|
DEFOPCD("sbb", RwRvAX_Iv, FallThrough ), // 1D
|
|
DEFOPCD("push", RdSwDS, FallThrough ), // 1E
|
|
DEFOPCD("pop", WrSwDS, FallThrough ), // 1F
|
|
DEFOPCD("and", RwEb_RdGb, FallThrough ), // 20
|
|
DEFOPCD("and", RwEv_RdGv, FallThrough ), // 21
|
|
DEFOPCD("and", RwGb_RdEb, FallThrough ), // 22
|
|
DEFOPCD("and", RwGv_RdEv, FallThrough ), // 23
|
|
DEFOPCD("and", RwRbAL_Ib, FallThrough ), // 24
|
|
DEFOPCD("and", RwRvAX_Iv, FallThrough ), // 25
|
|
DEFOPCD(NULL, Nil, FallThrough ), // 26 ES:
|
|
DEFOPCD("daa", Nil, FallThrough ), // 27
|
|
DEFOPCD("sub", RwEb_RdGb, FallThrough ), // 28
|
|
DEFOPCD("sub", RwEv_RdGv, FallThrough ), // 29
|
|
DEFOPCD("sub", RwGb_RdEb, FallThrough ), // 2A
|
|
DEFOPCD("sub", RwGv_RdEv, FallThrough ), // 2B
|
|
DEFOPCD("sub", RwRbAL_Ib, FallThrough ), // 2C
|
|
DEFOPCD("sub", RwRvAX_Iv, FallThrough ), // 2D
|
|
DEFOPCD(NULL, Nil, FallThrough ), // 2E CS:
|
|
DEFOPCD("das", Nil, FallThrough ), // 2F
|
|
DEFOPCD("xor", RwEb_RdGb, FallThrough ), // 30
|
|
DEFOPCD("xor", RwEv_RdGv, FallThrough ), // 31
|
|
DEFOPCD("xor", RwGb_RdEb, FallThrough ), // 32
|
|
DEFOPCD("xor", RwGv_RdEv, FallThrough ), // 33
|
|
DEFOPCD("xor", RwRbAL_Ib, FallThrough ), // 34
|
|
DEFOPCD("xor", RwRvAX_Iv, FallThrough ), // 35
|
|
DEFOPCD(NULL, Nil, FallThrough ), // 36 SS:
|
|
DEFOPCD("aaa", Nil, FallThrough ), // 37
|
|
DEFOPCD("cmp", RdEb_RdGb, FallThrough ), // 38
|
|
DEFOPCD("cmp", RdEv_RdGv, FallThrough ), // 39
|
|
DEFOPCD("cmp", RdGb_RdEb, FallThrough ), // 3A
|
|
DEFOPCD("cmp", RdGv_RdEv, FallThrough ), // 3B
|
|
DEFOPCD("cmp", RdRbAL_Ib, FallThrough ), // 3C
|
|
DEFOPCD("cmp", RdRvAX_Iv, FallThrough ), // 3D
|
|
DEFOPCD(NULL, Nil, FallThrough ), // 3E DS:
|
|
DEFOPCD("aas", Nil, FallThrough ), // 3F
|
|
DEFOPCD("inc", RwGvOp, FallThrough ), // 40
|
|
DEFOPCD("inc", RwGvOp, FallThrough ), // 41
|
|
DEFOPCD("inc", RwGvOp, FallThrough ), // 42
|
|
DEFOPCD("inc", RwGvOp, FallThrough ), // 43
|
|
DEFOPCD("inc", RwGvOp, FallThrough ), // 44
|
|
DEFOPCD("inc", RwGvOp, FallThrough ), // 45
|
|
DEFOPCD("inc", RwGvOp, FallThrough ), // 46
|
|
DEFOPCD("inc", RwGvOp, FallThrough ), // 47
|
|
DEFOPCD("dec", RwGvOp, FallThrough ), // 48
|
|
DEFOPCD("dec", RwGvOp, FallThrough ), // 49
|
|
DEFOPCD("dec", RwGvOp, FallThrough ), // 4A
|
|
DEFOPCD("dec", RwGvOp, FallThrough ), // 4B
|
|
DEFOPCD("dec", RwGvOp, FallThrough ), // 4C
|
|
DEFOPCD("dec", RwGvOp, FallThrough ), // 4D
|
|
DEFOPCD("dec", RwGvOp, FallThrough ), // 4E
|
|
DEFOPCD("dec", RwGvOp, FallThrough ), // 4F
|
|
DEFOPCD("push", RdGvOp, FallThrough ), // 50
|
|
DEFOPCD("push", RdGvOp, FallThrough ), // 51
|
|
DEFOPCD("push", RdGvOp, FallThrough ), // 52
|
|
DEFOPCD("push", RdGvOp, FallThrough ), // 53
|
|
DEFOPCD("push", RdGvOp, FallThrough ), // 54
|
|
DEFOPCD("push", RdGvOp, FallThrough ), // 55
|
|
DEFOPCD("push", RdGvOp, FallThrough ), // 56
|
|
DEFOPCD("push", RdGvOp, FallThrough ), // 57
|
|
DEFOPCD("pop", WrGvOp, FallThrough ), // 58
|
|
DEFOPCD("pop", WrGvOp, FallThrough ), // 59
|
|
DEFOPCD("pop", WrGvOp, FallThrough ), // 5A
|
|
DEFOPCD("pop", WrGvOp, FallThrough ), // 5B
|
|
DEFOPCD("pop", WrGvOp, FallThrough ), // 5C
|
|
DEFOPCD("pop", WrGvOp, FallThrough ), // 5D
|
|
DEFOPCD("pop", WrGvOp, FallThrough ), // 5E
|
|
DEFOPCD("pop", WrGvOp, FallThrough ), // 5F
|
|
DEFOPCD("pusha", Nil, FallThrough ), // 60
|
|
DEFOPCD("popa", Nil, FallThrough ), // 61
|
|
DEFOPCD("bound", RdGv_RdMa, TrapCc ), // 62
|
|
DEFOPCD("arpl", RwEw_RdGw, FallThrough ), // 63
|
|
DEFOPCD(NULL, Nil, FallThrough ), // 64 FS:
|
|
DEFOPCD(NULL, Nil, FallThrough ), // 65 GS:
|
|
DEFOPCD(NULL, Nil, FallThrough ), // 66 Operand Size Override
|
|
DEFOPCD(NULL, Nil, FallThrough ), // 67 Address Size Override
|
|
DEFOPCD("push", Iv, FallThrough ), // 68
|
|
DEFOPCD("imul", WrGv_RdEv_Iv, FallThrough ), // 69
|
|
DEFOPCD("push", Ib, FallThrough ), // 6A
|
|
DEFOPCD("imul", WrGv_RdEv_Ib, FallThrough ), // 6B
|
|
DEFOPCD("ins", WrYb_RdRwDX, FallThrough ), // 6C
|
|
DEFOPCD("ins", WrYv_RdRwDX, FallThrough ), // 6D
|
|
DEFOPCD("outs", RdRwDX_RdXb, FallThrough ), // 6E
|
|
DEFOPCD("outs", RdRwDX_RdXv, FallThrough ), // 6F
|
|
DEFOPCD("jo", Jb, JmpCcShort ), // 70
|
|
DEFOPCD("jno", Jb, JmpCcShort ), // 71
|
|
DEFOPCD("jb", Jb, JmpCcShort ), // 72
|
|
DEFOPCD("jae", Jb, JmpCcShort ), // 73
|
|
DEFOPCD("je", Jb, JmpCcShort ), // 74
|
|
DEFOPCD("jne", Jb, JmpCcShort ), // 75
|
|
DEFOPCD("jbe", Jb, JmpCcShort ), // 76
|
|
DEFOPCD("ja", Jb, JmpCcShort ), // 77
|
|
DEFOPCD("js", Jb, JmpCcShort ), // 78
|
|
DEFOPCD("jns", Jb, JmpCcShort ), // 79
|
|
DEFOPCD("jp", Jb, JmpCcShort ), // 7A
|
|
DEFOPCD("jnp", Jb, JmpCcShort ), // 7B
|
|
DEFOPCD("jl", Jb, JmpCcShort ), // 7C
|
|
DEFOPCD("jge", Jb, JmpCcShort ), // 7D
|
|
DEFOPCD("jle", Jb, JmpCcShort ), // 7E
|
|
DEFOPCD("jg", Jb, JmpCcShort ), // 7F
|
|
DEFOGRP(80), // 80
|
|
DEFOGRP(81), // 81
|
|
DEFOPCD("mov", WrRbAL_Ib, FallThrough ), // 82
|
|
DEFOGRP(83), // 83
|
|
DEFOPCD("test", RdEb_RdGb, FallThrough ), // 84
|
|
DEFOPCD("test", RdEv_RdGv, FallThrough ), // 85
|
|
DEFOPCD("xchg", RwGb_RwEb, FallThrough ), // 86
|
|
DEFOPCD("xchg", RwGv_RwEv, FallThrough ), // 87
|
|
DEFOPCD("mov", WrEb_RdGb, FallThrough ), // 88
|
|
DEFOPCD("mov", WrEv_RdGv, FallThrough ), // 89
|
|
DEFOPCD("mov", WrGb_RdEb, FallThrough ), // 8A
|
|
DEFOPCD("mov", WrGv_RdEv, FallThrough ), // 8B
|
|
DEFOPCD("mov", WrEw_RdSw, FallThrough ), // 8C
|
|
DEFOPCD("lea", WrGv_M, FallThrough ), // 8D
|
|
DEFOPCD("mov", WrSw_RdEw, FallThrough ), // 8E
|
|
DEFOPCD("pop", WrEv, FallThrough ), // 8F
|
|
DEFOPCD("nop", Nil, FallThrough ), // 90
|
|
DEFOPCD("xchg", RwRvAX_RwGvOp, FallThrough ), // 91
|
|
DEFOPCD("xchg", RwRvAX_RwGvOp, FallThrough ), // 92
|
|
DEFOPCD("xchg", RwRvAX_RwGvOp, FallThrough ), // 93
|
|
DEFOPCD("xchg", RwRvAX_RwGvOp, FallThrough ), // 94
|
|
DEFOPCD("xchg", RwRvAX_RwGvOp, FallThrough ), // 95
|
|
DEFOPCD("xchg", RwRvAX_RwGvOp, FallThrough ), // 96
|
|
DEFOPCD("xchg", RwRvAX_RwGvOp, FallThrough ), // 97
|
|
DEFOPCD("cbw", Nil, FallThrough ), // 98
|
|
DEFOPCD("cwd", Nil, FallThrough ), // 99
|
|
DEFOPCD("call", AP, CallFar ), // 9A
|
|
DEFOPCD("wait", Nil, FallThrough ), // 9B
|
|
DEFOPCD("pushf", Nil, FallThrough ), // 9C
|
|
DEFOPCD("popf", Nil, FallThrough ), // 9D
|
|
DEFOPCD("sahf", Nil, FallThrough ), // 9E
|
|
DEFOPCD("lahf", Nil, FallThrough ), // 9F
|
|
DEFOPCD("mov", WrRbAL_RdOb, FallThrough ), // A0
|
|
DEFOPCD("mov", WrRvAX_RdOv, FallThrough ), // A1
|
|
DEFOPCD("mov", WrOb_RdRbAL, FallThrough ), // A2
|
|
DEFOPCD("mov", WrOv_RdRvAX, FallThrough ), // A3
|
|
DEFOPCD("movs", WrYb_RdXb, FallThrough ), // A4
|
|
DEFOPCD("movs", WrYv_RdXv, FallThrough ), // A5
|
|
DEFOPCD("cmps", RdXb_RdYb, FallThrough ), // A6
|
|
DEFOPCD("cmps", RdXv_RdYv, FallThrough ), // A7
|
|
DEFOPCD("test", RdRbAL_Ib, FallThrough ), // A8
|
|
DEFOPCD("test", RdRvAX_Iv, FallThrough ), // A9
|
|
DEFOPCD("stos", WrYb, FallThrough ), // AA
|
|
DEFOPCD("stos", WrYv, FallThrough ), // AB
|
|
DEFOPCD("lods", RdXb, FallThrough ), // AC
|
|
DEFOPCD("lods", RdXv, FallThrough ), // AD
|
|
DEFOPCD("scas", RdYb, FallThrough ), // AE
|
|
DEFOPCD("scas", RdYv, FallThrough ), // AF
|
|
DEFOPCD("mov", WrGbOp_Ib, FallThrough ), // B0
|
|
DEFOPCD("mov", WrGbOp_Ib, FallThrough ), // B1
|
|
DEFOPCD("mov", WrGbOp_Ib, FallThrough ), // B2
|
|
DEFOPCD("mov", WrGbOp_Ib, FallThrough ), // B3
|
|
DEFOPCD("mov", WrGbOp_Ib, FallThrough ), // B4
|
|
DEFOPCD("mov", WrGbOp_Ib, FallThrough ), // B5
|
|
DEFOPCD("mov", WrGbOp_Ib, FallThrough ), // B6
|
|
DEFOPCD("mov", WrGbOp_Ib, FallThrough ), // B7
|
|
DEFOPCD("mov", WrGvOp_Iv, FallThrough ), // B8
|
|
DEFOPCD("mov", WrGvOp_Iv, FallThrough ), // B9
|
|
DEFOPCD("mov", WrGvOp_Iv, FallThrough ), // BA
|
|
DEFOPCD("mov", WrGvOp_Iv, FallThrough ), // BB
|
|
DEFOPCD("mov", WrGvOp_Iv, FallThrough ), // BC
|
|
DEFOPCD("mov", WrGvOp_Iv, FallThrough ), // BD
|
|
DEFOPCD("mov", WrGvOp_Iv, FallThrough ), // BE
|
|
DEFOPCD("mov", WrGvOp_Iv, FallThrough ), // BF
|
|
DEFOGRP(C0), // C0
|
|
DEFOGRP(C1), // C1
|
|
DEFOPCD("ret", Iw, Ret ), // C2
|
|
DEFOPCD("ret", Nil, Ret ), // C3
|
|
DEFOPCD("les", WrGv_RdMp, FallThrough ), // C4
|
|
DEFOPCD("lds", WrGv_RdMp, FallThrough ), // C5
|
|
DEFOPCD("mov", WrEb_Ib, FallThrough ), // C6
|
|
DEFOPCD("mov", WrEv_Iv, FallThrough ), // C7
|
|
DEFOPCD("enter", Iw_Ib, FallThrough ), // C8
|
|
DEFOPCD("leave", Nil, FallThrough ), // C9
|
|
DEFOPCD("retf", Iw, Ret ), // CA
|
|
DEFOPCD("retf", Nil, Ret ), // CB
|
|
DEFOPCD("int", 3, Trap ), // CC
|
|
DEFOPCD("int", Ib, Trap ), // CD
|
|
DEFOPCD("into", Nil, TrapCc ), // CE
|
|
DEFOPCD("iret", Nil, Iret ), // CF
|
|
DEFOGRP(D0), // D0
|
|
DEFOGRP(D1), // D1
|
|
DEFOGRP(D2), // D2
|
|
DEFOGRP(D3), // D3
|
|
DEFOPCD("aam", Nil, FallThrough ), // D4
|
|
DEFOPCD("aad", Nil, FallThrough ), // D5
|
|
DEFOPCD(NULL, Nil, Unknown ), // D6
|
|
DEFOPCD("xlat", RdZb, FallThrough ), // D7
|
|
DEFOGRP(D8), // D8 ESC
|
|
DEFOGRP(D9), // D9 ESC
|
|
DEFOGRP(DA), // DA ESC
|
|
DEFOGRP(DB), // DB ESC
|
|
DEFOGRP(DC), // DC ESC
|
|
DEFOGRP(DD), // DD ESC
|
|
DEFOGRP(DE), // DE ESC
|
|
DEFOGRP(DF), // DF ESC
|
|
DEFOPCD("loopne", Jb, Loop ), // E0
|
|
DEFOPCD("loope", Jb, Loop ), // E1
|
|
DEFOPCD("loop", Jb, Loop ), // E2
|
|
DEFOPCD("jcxz", Jb, Jcxz ), // E3
|
|
DEFOPCD("in", WrRbAL_Ib, FallThrough ), // E4
|
|
DEFOPCD("in", WrRvAX_Ib, FallThrough ), // E5
|
|
DEFOPCD("out", Ib_RdRbAL, FallThrough ), // E6
|
|
DEFOPCD("out", Ib_RdRvAX, FallThrough ), // E7
|
|
DEFOPCD("call", Jv, CallNear32 ), // E8
|
|
DEFOPCD("jmp", Jv, JmpNear ), // E9
|
|
DEFOPCD("jmp", AP, JmpFar ), // EA
|
|
DEFOPCD("jmp", Jb, JmpShort ), // EB
|
|
DEFOPCD("in", WrRbAL_RdRwDX, FallThrough ), // EC
|
|
DEFOPCD("in", WrRvAX_RdRwDX, FallThrough ), // ED
|
|
DEFOPCD("out", RdRwDX_RdRbAL, FallThrough ), // EE
|
|
DEFOPCD("out", RdRwDX_RdRvAX, FallThrough ), // EF
|
|
DEFOPCD(NULL, Nil, Unknown ), // F0 Prefix: LOCK
|
|
DEFOPCD(NULL, Nil, Unknown ), // F1
|
|
DEFOPCD(NULL, Nil, Unknown ), // F2 Prefix: REPNE
|
|
DEFOPCD(NULL, Nil, Unknown ), // F3 Prefix: REP
|
|
DEFOPCD("hlt", Nil, CallInd ), // F4
|
|
DEFOPCD("cmc", Nil, FallThrough ), // F5
|
|
DEFOGRP(F6), // F6
|
|
DEFOGRP(F7), // F7
|
|
DEFOPCD("clc", Nil, FallThrough ), // F8
|
|
DEFOPCD("stc", Nil, FallThrough ), // F9
|
|
DEFOPCD("cli", Nil, FallThrough ), // FA
|
|
DEFOPCD("sti", Nil, FallThrough ), // FB
|
|
DEFOPCD("cld", Nil, FallThrough ), // FC
|
|
DEFOPCD("std", Nil, FallThrough ), // FD
|
|
DEFOGRP(FE), // FE
|
|
DEFOGRP(FF), // FF
|
|
};
|
|
|
|
|
|
const OPCD rgopcd0F[256] =
|
|
{
|
|
// Mnemonic Operands trmtx86
|
|
|
|
DEFOGRP(0F00), // 00
|
|
DEFOGRP(0F01), // 01
|
|
DEFOPCD("lar", WrGv_RdEw, FallThrough ), // 02
|
|
DEFOPCD("lsl", WrGv_RdEw, FallThrough ), // 03
|
|
DEFOPCD(NULL, Nil, Unknown ), // 04
|
|
DEFOPCD("loadall", Nil, FallThrough ), // 05
|
|
DEFOPCD("clts", Nil, FallThrough ), // 06
|
|
DEFOPCD("loadall", RdXv, FallThrough ), // 07
|
|
DEFOPCD("invd", Nil, FallThrough ), // 08
|
|
DEFOPCD("wbinvd", Nil, FallThrough ), // 09
|
|
DEFOPCD("cflsh", Nil, FallThrough ), // 0A UNDONE: Does P6 still have this?
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0B
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0C
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0D
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0E
|
|
DEFOPCD(NULL, Nil, Unknown ), // 0F
|
|
DEFOPCD(NULL, Nil, Unknown ), // 10
|
|
DEFOPCD(NULL, Nil, Unknown ), // 11
|
|
DEFOPCD(NULL, Nil, Unknown ), // 12
|
|
DEFOPCD(NULL, Nil, Unknown ), // 13
|
|
DEFOPCD(NULL, Nil, Unknown ), // 14
|
|
DEFOPCD(NULL, Nil, Unknown ), // 15
|
|
DEFOPCD(NULL, Nil, Unknown ), // 16
|
|
DEFOPCD(NULL, Nil, Unknown ), // 17
|
|
DEFOPCD(NULL, Nil, Unknown ), // 18
|
|
DEFOPCD(NULL, Nil, Unknown ), // 19
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1A
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1B
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1C
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1D
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1E
|
|
DEFOPCD(NULL, Nil, Unknown ), // 1F
|
|
DEFOPCD("mov", WrRd_RdCd, FallThrough ), // 20
|
|
DEFOPCD("mov", WrRd_RdDd, FallThrough ), // 21
|
|
DEFOPCD("mov", WrCd_RdRd, FallThrough ), // 22
|
|
DEFOPCD("mov", WrDd_RdRd, FallThrough ), // 23
|
|
DEFOPCD("mov", WrTd_RdRd, FallThrough ), // 24
|
|
DEFOPCD(NULL, Nil, Unknown ), // 25
|
|
DEFOPCD("mov", WrRd_RdTd, FallThrough ), // 26
|
|
DEFOPCD(NULL, Nil, Unknown ), // 27
|
|
DEFOPCD(NULL, Nil, Unknown ), // 28
|
|
DEFOPCD(NULL, Nil, Unknown ), // 29
|
|
DEFOPCD(NULL, Nil, Unknown ), // 2A
|
|
DEFOPCD(NULL, Nil, Unknown ), // 2B
|
|
DEFOPCD(NULL, Nil, Unknown ), // 2C
|
|
DEFOPCD(NULL, Nil, Unknown ), // 2D
|
|
DEFOPCD(NULL, Nil, Unknown ), // 2E
|
|
DEFOPCD(NULL, Nil, Unknown ), // 2F
|
|
DEFOPCD("wrmsr", Nil, FallThrough ), // 30
|
|
DEFOPCD("rdtsc", Nil, FallThrough ), // 31
|
|
DEFOPCD("rdmsr", Nil, FallThrough ), // 32
|
|
DEFOPCD("rdpmc", Nil, FallThrough ), // 33
|
|
DEFOPCD("wrecr", Nil, FallThrough ), // 34 UNDONE: Does P6 still have this?
|
|
DEFOPCD(NULL, Nil, Unknown ), // 35
|
|
DEFOPCD("rdecr", Nil, FallThrough ), // 36 UNDONE: Does P6 still have this?
|
|
DEFOPCD(NULL, Nil, Unknown ), // 37
|
|
DEFOPCD(NULL, Nil, Unknown ), // 38
|
|
DEFOPCD(NULL, Nil, Unknown ), // 39
|
|
DEFOPCD(NULL, Nil, Unknown ), // 3A
|
|
DEFOPCD(NULL, Nil, Unknown ), // 3B
|
|
DEFOPCD(NULL, Nil, Unknown ), // 3C
|
|
DEFOPCD(NULL, Nil, Unknown ), // 3D
|
|
DEFOPCD(NULL, Nil, Unknown ), // 3E
|
|
DEFOPCD(NULL, Nil, Unknown ), // 3F
|
|
DEFOPCD("cmovo", WrEvReg_RdGv, FallThrough ), // 40
|
|
DEFOPCD("cmovno", WrEvReg_RdGv, FallThrough ), // 41
|
|
DEFOPCD("cmovb", WrEvReg_RdGv, FallThrough ), // 42
|
|
DEFOPCD("cmovae", WrEvReg_RdGv, FallThrough ), // 43
|
|
DEFOPCD("cmove", WrEvReg_RdGv, FallThrough ), // 44
|
|
DEFOPCD("cmovne", WrEvReg_RdGv, FallThrough ), // 45
|
|
DEFOPCD("cmovbe", WrEvReg_RdGv, FallThrough ), // 46
|
|
DEFOPCD("cmova", WrEvReg_RdGv, FallThrough ), // 47
|
|
DEFOPCD("cmovs", WrEvReg_RdGv, FallThrough ), // 48
|
|
DEFOPCD("cmovns", WrEvReg_RdGv, FallThrough ), // 49
|
|
DEFOPCD("cmovp", WrEvReg_RdGv, FallThrough ), // 4A
|
|
DEFOPCD("cmovnp", WrEvReg_RdGv, FallThrough ), // 4B
|
|
DEFOPCD("cmovl", WrEvReg_RdGv, FallThrough ), // 4C
|
|
DEFOPCD("cmovge", WrEvReg_RdGv, FallThrough ), // 4D
|
|
DEFOPCD("cmovle", WrEvReg_RdGv, FallThrough ), // 4E
|
|
DEFOPCD("cmovg", WrEvReg_RdGv, FallThrough ), // 4F
|
|
DEFOPCD(NULL, Nil, Unknown ), // 50
|
|
DEFOPCD(NULL, Nil, Unknown ), // 51
|
|
DEFOPCD(NULL, Nil, Unknown ), // 52
|
|
DEFOPCD(NULL, Nil, Unknown ), // 53
|
|
DEFOPCD(NULL, Nil, Unknown ), // 54
|
|
DEFOPCD(NULL, Nil, Unknown ), // 55
|
|
DEFOPCD(NULL, Nil, Unknown ), // 56
|
|
DEFOPCD(NULL, Nil, Unknown ), // 57
|
|
DEFOPCD(NULL, Nil, Unknown ), // 58
|
|
DEFOPCD(NULL, Nil, Unknown ), // 59
|
|
DEFOPCD(NULL, Nil, Unknown ), // 5A
|
|
DEFOPCD(NULL, Nil, Unknown ), // 5B
|
|
DEFOPCD(NULL, Nil, Unknown ), // 5C
|
|
DEFOPCD(NULL, Nil, Unknown ), // 5D
|
|
DEFOPCD(NULL, Nil, Unknown ), // 5E
|
|
DEFOPCD(NULL, Nil, Unknown ), // 5F
|
|
DEFOPCD("punpcklbw", RwMv_RdMmq, FallThrough ), // 60 MMX
|
|
DEFOPCD("punpcklbd", RwMv_RdMmq, FallThrough ), // 61 MMX
|
|
DEFOPCD("punpcklbq", RwMv_RdMmq, FallThrough ), // 62 MMX
|
|
DEFOPCD("packsswb", RwMv_RdMmq, FallThrough ), // 63 MMX
|
|
DEFOPCD("pcmpgtb", RwMv_RdMmq, Unknown ), // 64 MMX
|
|
DEFOPCD("pcmpgtw", RwMv_RdMmq, Unknown ), // 65 MMX
|
|
DEFOPCD("pcmpgtd", RwMv_RdMmq, Unknown ), // 66 MMX
|
|
DEFOPCD("packuswb", RwMv_RdMmq, FallThrough ), // 67 MMX
|
|
DEFOPCD("punpckhbw", RwMv_RdMmq, FallThrough ), // 68 MMX
|
|
DEFOPCD("punpckhbd", RwMv_RdMmq, FallThrough ), // 69 MMX
|
|
DEFOPCD("punpckhbq", RwMv_RdMmq, FallThrough ), // 6A MMX
|
|
DEFOPCD("packssdw", RwMv_RdMmq, FallThrough ), // 6B MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // 6C
|
|
DEFOPCD(NULL, Nil, Unknown ), // 6D
|
|
DEFOPCD("movd", WrMmd_RdMv, FallThrough ), // 6E MMX
|
|
DEFOPCD("movq", WrMmq_RdMv, FallThrough ), // 6F MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // 70
|
|
DEFOGRP(0F71), // 71
|
|
DEFOGRP(0F72), // 72
|
|
DEFOGRP(0F73), // 73
|
|
DEFOPCD("pcmpeqb", RwMv_RdMmq, Unknown ), // 74 MMX
|
|
DEFOPCD("pcmpeqw", RwMv_RdMmq, Unknown ), // 75 MMX
|
|
DEFOPCD("pcmpeqd", RwMv_RdMmq, Unknown ), // 76 MMX
|
|
DEFOPCD("emms", Nil, FallThrough ), // 77 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // 78
|
|
DEFOPCD(NULL, Nil, Unknown ), // 79
|
|
DEFOPCD(NULL, Nil, Unknown ), // 7A
|
|
DEFOPCD(NULL, Nil, Unknown ), // 7B
|
|
DEFOPCD(NULL, Nil, Unknown ), // 7C
|
|
DEFOPCD(NULL, Nil, Unknown ), // 7D
|
|
DEFOPCD("movd", WrMv_RdMmd, FallThrough ), // 7E MMX
|
|
DEFOPCD("movq", WrMv_RdMmq, FallThrough ), // 7F MMX
|
|
// DEFOPCD("svdc", WrMt_RdSw, FallThrough ), // 78 IBM BL486DX
|
|
// DEFOPCD("rsdc", WrSw_RdMt, FallThrough ), // 79 IBM BL486DX
|
|
// DEFOPCD("svldt", WrMt, FallThrough ), // 7A IBM BL486DX
|
|
// DEFOPCD("rsldt", RdMt, FallThrough ), // 7B IBM BL486DX
|
|
// DEFOPCD("svts", WrMt, FallThrough ), // 7C IBM BL486DX
|
|
// DEFOPCD("rsts", RdMt, FallThrough ), // 7D IBM BL486DX
|
|
// DEFOPCD("smint", Nil, FallThrough ), // 7E IBM BL486DX
|
|
// DEFOPCD(NULL, Nil, Unknown ), // 7F
|
|
DEFOPCD("jo", Jv, JmpCcNear ), // 80
|
|
DEFOPCD("jno", Jv, JmpCcNear ), // 81
|
|
DEFOPCD("jb", Jv, JmpCcNear ), // 82
|
|
DEFOPCD("jae", Jv, JmpCcNear ), // 83
|
|
DEFOPCD("je", Jv, JmpCcNear ), // 84
|
|
DEFOPCD("jne", Jv, JmpCcNear ), // 85
|
|
DEFOPCD("jbe", Jv, JmpCcNear ), // 86
|
|
DEFOPCD("ja", Jv, JmpCcNear ), // 87
|
|
DEFOPCD("js", Jv, JmpCcNear ), // 88
|
|
DEFOPCD("jns", Jv, JmpCcNear ), // 89
|
|
DEFOPCD("jp", Jv, JmpCcNear ), // 8A
|
|
DEFOPCD("jnp", Jv, JmpCcNear ), // 8B
|
|
DEFOPCD("jl", Jv, JmpCcNear ), // 8C
|
|
DEFOPCD("jge", Jv, JmpCcNear ), // 8D
|
|
DEFOPCD("jle", Jv, JmpCcNear ), // 8E
|
|
DEFOPCD("jg", Jv, JmpCcNear ), // 8F
|
|
DEFOPCD("seto", WrEb, FallThrough ), // 90
|
|
DEFOPCD("setno", WrEb, FallThrough ), // 91
|
|
DEFOPCD("setb", WrEb, FallThrough ), // 92
|
|
DEFOPCD("setae", WrEb, FallThrough ), // 93
|
|
DEFOPCD("sete", WrEb, FallThrough ), // 94
|
|
DEFOPCD("setne", WrEb, FallThrough ), // 95
|
|
DEFOPCD("setbe", WrEb, FallThrough ), // 96
|
|
DEFOPCD("seta", WrEb, FallThrough ), // 97
|
|
DEFOPCD("sets", WrEb, FallThrough ), // 98
|
|
DEFOPCD("setns", WrEb, FallThrough ), // 99
|
|
DEFOPCD("setp", WrEb, FallThrough ), // 9A
|
|
DEFOPCD("setnp", WrEb, FallThrough ), // 9B
|
|
DEFOPCD("setl", WrEb, FallThrough ), // 9C
|
|
DEFOPCD("setge", WrEb, FallThrough ), // 9D
|
|
DEFOPCD("setle", WrEb, FallThrough ), // 9E
|
|
DEFOPCD("setg", WrEb, FallThrough ), // 9F
|
|
DEFOPCD("push", RdSwFS, FallThrough ), // A0
|
|
DEFOPCD("pop", WrSwFS, FallThrough ), // A1
|
|
DEFOPCD("cpuid", Nil, FallThrough ), // A2
|
|
DEFOPCD("bt", RdEv_RdGv, FallThrough ), // A3
|
|
DEFOPCD("shld", RwEv_RdGv_Ib, FallThrough ), // A4
|
|
DEFOPCD("shld", RwEv_RdGv_RdRbCL, FallThrough ), // A5
|
|
DEFOPCD("xbts", WrGv_RdEv, FallThrough ), // A6 Invalid instruction
|
|
DEFOPCD("ibts", RwEv_RdGv, FallThrough ), // A7 Invalid instruction
|
|
DEFOPCD("push", RdSwGS, FallThrough ), // A8
|
|
DEFOPCD("pop", WrSwGS, FallThrough ), // A9
|
|
DEFOPCD("rsm", Nil, JmpInd ), // AA
|
|
DEFOPCD("bts", RwEv_RdGv, FallThrough ), // AB
|
|
DEFOPCD("shrd", RwEv_RdGv_Ib, FallThrough ), // AC
|
|
DEFOPCD("shrd", RwEv_RdGv_RdRbCL, FallThrough ), // AD
|
|
DEFOPCD("zalloc", WrMcache, FallThrough ), // AE UNDONE: Does P6 still have this?
|
|
DEFOPCD("imul", RwGv_RdEv, FallThrough ), // AF
|
|
DEFOPCD("cmpxchg", RwEb_RwGb, FallThrough ), // B0
|
|
DEFOPCD("cmpxchg", RwEv_RwGv, FallThrough ), // B1
|
|
DEFOPCD("lss", WrGv_RdMp, FallThrough ), // B2
|
|
DEFOPCD("btr", RwEv_RdGv, FallThrough ), // B3
|
|
DEFOPCD("lfs", WrGv_RdMp, FallThrough ), // B4
|
|
DEFOPCD("lgs", WrGv_RdMp, FallThrough ), // B5
|
|
DEFOPCD("movzx", WrGv_RdEb, FallThrough ), // B6
|
|
DEFOPCD("movzx", WrGd_RdEw, FallThrough ), // B7
|
|
DEFOPCD(NULL, Nil, Unknown ), // B8
|
|
DEFOPCD(NULL, Nil, Unknown ), // B9
|
|
DEFOGRP(0FBA), // BA
|
|
DEFOPCD("btc", RwEv_RdGv, FallThrough ), // BB
|
|
DEFOPCD("bsf", WrGv_RdEv, FallThrough ), // BC
|
|
DEFOPCD("bsr", WrGv_RdEv, FallThrough ), // BD
|
|
DEFOPCD("movsx", WrGv_RdEb, FallThrough ), // BE
|
|
DEFOPCD("movsx", WrGd_RdEw, FallThrough ), // BF
|
|
DEFOPCD("xadd", RwEb_RwGb, FallThrough ), // C0
|
|
DEFOPCD("xadd", RwEv_RwGv, FallThrough ), // C1
|
|
DEFOPCD(NULL, Nil, Unknown ), // C2
|
|
DEFOPCD(NULL, Nil, Unknown ), // C3
|
|
DEFOPCD(NULL, Nil, Unknown ), // C4
|
|
DEFOPCD(NULL, Nil, Unknown ), // C5
|
|
DEFOPCD(NULL, Nil, Unknown ), // C6
|
|
DEFOGRP(0FC7), // C7
|
|
DEFOPCD("bswap", RwGdOp, FallThrough ), // C8
|
|
DEFOPCD("bswap", RwGdOp, FallThrough ), // C9
|
|
DEFOPCD("bswap", RwGdOp, FallThrough ), // CA
|
|
DEFOPCD("bswap", RwGdOp, FallThrough ), // CB
|
|
DEFOPCD("bswap", RwGdOp, FallThrough ), // CC
|
|
DEFOPCD("bswap", RwGdOp, FallThrough ), // CD
|
|
DEFOPCD("bswap", RwGdOp, FallThrough ), // CE
|
|
DEFOPCD("bswap", RwGdOp, FallThrough ), // CF
|
|
DEFOPCD(NULL, Nil, Unknown ), // D0
|
|
DEFOPCD("psrlw", RwMv_RdMmq, FallThrough ), // D1 MMX
|
|
DEFOPCD("psrld", RwMv_RdMmq, FallThrough ), // D2 MMX
|
|
DEFOPCD("psrlq", RwMv_RdMmq, FallThrough ), // D3 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // D4
|
|
DEFOPCD("pmull", RwMv_RdMmq, FallThrough ), // D5 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // D6
|
|
DEFOPCD(NULL, Nil, Unknown ), // D7
|
|
DEFOPCD("psubusb", RwMv_RdMmq, FallThrough ), // D8 MMX
|
|
DEFOPCD("psubusw", RwMv_RdMmq, FallThrough ), // D9 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // DA
|
|
DEFOPCD("pand", RwMv_RdMmq, FallThrough ), // DB
|
|
DEFOPCD("paddusb", RwMv_RdMmq, FallThrough ), // DC MMX
|
|
DEFOPCD("paddusw", RwMv_RdMmq, FallThrough ), // DD MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // DE
|
|
DEFOPCD("pandn", RwMv_RdMmq, FallThrough ), // DF
|
|
DEFOPCD(NULL, Nil, Unknown ), // E0
|
|
DEFOPCD("psraw", RwMv_RdMmq, FallThrough ), // E1 MMX
|
|
DEFOPCD("psrad", RwMv_RdMmq, FallThrough ), // E2 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // E3
|
|
DEFOPCD(NULL, Nil, Unknown ), // E4
|
|
DEFOPCD("pmulh", RwMv_RdMmq, FallThrough ), // E5 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // E6
|
|
DEFOPCD(NULL, Nil, Unknown ), // E7
|
|
DEFOPCD("psubsb", RwMv_RdMmq, FallThrough ), // E8 MMX
|
|
DEFOPCD("psubsw", RwMv_RdMmq, FallThrough ), // E9 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // EA
|
|
DEFOPCD("por", RwMv_RdMmq, FallThrough ), // EB MMX
|
|
DEFOPCD("paddsb", RwMv_RdMmq, FallThrough ), // EC MMX
|
|
DEFOPCD("paddsw", RwMv_RdMmq, FallThrough ), // ED MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // EE
|
|
DEFOPCD("pxor", RwMv_RdMmq, FallThrough ), // EF MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // F0
|
|
DEFOPCD("psllw", RwMv_RdMmq, FallThrough ), // F1 MMX
|
|
DEFOPCD("pslld", RwMv_RdMmq, FallThrough ), // F2 MMX
|
|
DEFOPCD("psllq", RwMv_RdMmq, FallThrough ), // F3 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // F4
|
|
DEFOPCD("pmaddwd", RwMv_RdMmq, FallThrough ), // F5 MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // F6
|
|
DEFOPCD(NULL, Nil, Unknown ), // F7
|
|
DEFOPCD("psubb", RwMv_RdMmq, FallThrough ), // F8 MMX
|
|
DEFOPCD("psubw", RwMv_RdMmq, FallThrough ), // F9 MMX
|
|
DEFOPCD("psubd", RwMv_RdMmq, FallThrough ), // FA MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // FB
|
|
DEFOPCD("paddb", RwMv_RdMmq, FallThrough ), // FC MMX
|
|
DEFOPCD("paddw", RwMv_RdMmq, FallThrough ), // FD MMX
|
|
DEFOPCD("paddd", RwMv_RdMmq, FallThrough ), // FE MMX
|
|
DEFOPCD(NULL, Nil, Unknown ), // FF
|
|
};
|
|
|
|
|
|
inline const OPCD *PopcdFloatingPoint(BYTE bOpcd, BYTE bModrm);
|
|
|
|
|
|
DISX86::DISX86(ARCHT archt) : DIS(archt)
|
|
{
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------
|
|
// Public Methods
|
|
// -----------------------------------------------------------------
|
|
|
|
ADDR DISX86::AddrAddress() const
|
|
{
|
|
size_t ibDisp = 0;
|
|
|
|
const OPS *pops = m_popcd->pops;
|
|
|
|
for (unsigned ioprnd = 0; ioprnd < 3; ioprnd++)
|
|
{
|
|
if (pops->rgoprnd[ioprnd].oprndt == oprndtNil)
|
|
{
|
|
break;
|
|
}
|
|
|
|
switch ((OPRNDT) pops->rgoprnd[ioprnd].oprndt)
|
|
{
|
|
case oprndtModrm : // Memory/register references from MODRM
|
|
if (m_fAddress32)
|
|
{
|
|
ibDisp = IbDispModrm32();
|
|
}
|
|
|
|
else
|
|
{
|
|
ibDisp = IbDispModrm16();
|
|
}
|
|
break;
|
|
|
|
case oprndtOffset : // Address size immediate offset
|
|
ibDisp = IbDispOffset();
|
|
break;
|
|
|
|
default :
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (ibDisp == 0)
|
|
{
|
|
return(addrNil);
|
|
}
|
|
|
|
return(m_addr + ibDisp);
|
|
}
|
|
|
|
|
|
ADDR DISX86::AddrJumpTable() const
|
|
{
|
|
if (m_trmtx86 != trmtx86JmpInd)
|
|
{
|
|
// This isn't a reference to a jump table
|
|
|
|
return(addrNil);
|
|
}
|
|
|
|
ADDR addr;
|
|
|
|
if (m_fAddress32)
|
|
{
|
|
addr = AddrJumpTable32();
|
|
}
|
|
|
|
else
|
|
{
|
|
addr = AddrJumpTable16();
|
|
}
|
|
|
|
return(addr);
|
|
}
|
|
|
|
|
|
ADDR DISX86::AddrOperand(size_t ioperand) const
|
|
{
|
|
if (m_pfndwgetreg == 0)
|
|
{
|
|
return(addrNil);
|
|
}
|
|
|
|
if (ioperand == 0)
|
|
{
|
|
// Implicit operand if any
|
|
|
|
return(addrNil);
|
|
}
|
|
|
|
if (!FValidOperand(ioperand))
|
|
{
|
|
return(addrNil);
|
|
}
|
|
|
|
const OPS *pops = m_popcd->pops;
|
|
|
|
ADDR addr = addrNil;
|
|
|
|
OPRNDT oprndt = (OPRNDT) pops->rgoprnd[ioperand].oprndt;
|
|
|
|
switch ((OPRNDT) pops->rgoprnd[ioperand].oprndt)
|
|
{
|
|
case oprndtModrm : // Memory/register references from MODRM
|
|
if (m_fAddress32)
|
|
{
|
|
addr = AddrOperandModrm32();
|
|
}
|
|
|
|
else
|
|
{
|
|
addr = AddrOperandModrm16();
|
|
}
|
|
break;
|
|
|
|
case oprndtOffset : // Address size immediate offset
|
|
if (m_fAddress32)
|
|
{
|
|
addr = (ADDR) *(DWORD UNALIGNED *) (m_rgbInstr + m_ibImmed);
|
|
}
|
|
|
|
else
|
|
{
|
|
addr = (ADDR) *(WORD UNALIGNED *) (m_rgbInstr + m_ibImmed);
|
|
}
|
|
break;
|
|
|
|
case oprndtX : // DS:[eSI] for string instruction
|
|
addr = (ADDR) (*m_pfndwgetreg)(this, regEsi);
|
|
break;
|
|
|
|
case oprndtY : // ES:[eDI] for string instruction
|
|
addr = (ADDR) (*m_pfndwgetreg)(this, regEdi);
|
|
break;
|
|
|
|
case oprndtZ : // DS:[eBX] for XLAT
|
|
addr = (ADDR) (*m_pfndwgetreg)(this, regEbx);
|
|
break;
|
|
}
|
|
|
|
if (!m_fAddress32)
|
|
{
|
|
addr &= 0x0000FFFF;
|
|
}
|
|
|
|
return(addr);
|
|
}
|
|
|
|
|
|
ADDR DISX86::AddrOperandModrm16() const
|
|
{
|
|
BYTE b = m_rgbInstr[m_ibModrm];
|
|
|
|
if ((b & 0xC0) == 0xC0)
|
|
{
|
|
// Operand is a register
|
|
|
|
return(addrNil);
|
|
}
|
|
|
|
bool fDisp16 = false;
|
|
int ireg = -1;
|
|
const char *szReg = NULL;
|
|
|
|
if ((b & 0xC7) == 0x06)
|
|
{
|
|
// Special case of [disp16] operand
|
|
|
|
fDisp16 = true;
|
|
}
|
|
|
|
else
|
|
{
|
|
ireg = (int) (b & 0x07);
|
|
}
|
|
|
|
WORD wDisp;
|
|
|
|
switch (b & 0xC0)
|
|
{
|
|
case 0x40 :
|
|
wDisp = m_rgbInstr[m_ibModrm + 1];
|
|
|
|
if ((wDisp & 0x80) != 0)
|
|
{
|
|
wDisp |= 0xFF00;
|
|
}
|
|
break;
|
|
|
|
case 0x80 :
|
|
fDisp16 = true;
|
|
break;
|
|
}
|
|
|
|
if (fDisp16)
|
|
{
|
|
wDisp = *(WORD UNALIGNED *) (m_rgbInstr + m_ibModrm + 1);
|
|
}
|
|
|
|
ADDR addr = (ADDR) wDisp;
|
|
|
|
if (ireg != -1)
|
|
{
|
|
addr += (*m_pfndwgetreg)(this, ireg);
|
|
}
|
|
|
|
addr &= 0x0000FFFF;
|
|
|
|
return(addr);
|
|
}
|
|
|
|
|
|
ADDR DISX86::AddrOperandModrm32() const
|
|
{
|
|
BYTE b = m_rgbInstr[m_ibModrm];
|
|
|
|
if ((b & 0xC0) == 0xC0)
|
|
{
|
|
// Operand is a register
|
|
|
|
return(addrNil);
|
|
}
|
|
|
|
bool fDisp32 = false;
|
|
int iregIndex = -1;
|
|
unsigned uScale;
|
|
|
|
const BYTE *pbDisp = m_rgbInstr + m_ibModrm + 1;
|
|
|
|
int ireg = (b & 0x07);
|
|
|
|
if (ireg != 4)
|
|
{
|
|
// There is no SIB byte
|
|
|
|
if ((b & 0xC7) == 0x05)
|
|
{
|
|
// Special case of [disp32] operand
|
|
|
|
fDisp32 = true;
|
|
|
|
ireg = -1;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
// This MODRM is followed by a SIB
|
|
|
|
BYTE bSib = *pbDisp++;
|
|
|
|
int iregBase = (bSib & 0x07);
|
|
|
|
if ((iregBase != 5) || ((b & 0xC0) != 0x00))
|
|
{
|
|
ireg = iregBase;
|
|
}
|
|
|
|
else
|
|
{
|
|
ireg = -1;
|
|
}
|
|
|
|
iregIndex = ((bSib >> 3) & 0x07);
|
|
|
|
if (iregIndex != 4)
|
|
{
|
|
uScale = 1 << (bSib >> 6);
|
|
}
|
|
|
|
else
|
|
{
|
|
iregIndex = -1;
|
|
}
|
|
|
|
if ((iregBase == 5) && ((b & 0xC0) == 0x00))
|
|
{
|
|
fDisp32 = true;
|
|
}
|
|
}
|
|
|
|
DWORD dwDisp;
|
|
|
|
switch (b & 0xC0)
|
|
{
|
|
case 0x40 :
|
|
dwDisp = *pbDisp;
|
|
|
|
if ((dwDisp & 0x80) != 0)
|
|
{
|
|
dwDisp |= 0xFFFFFF00;
|
|
}
|
|
break;
|
|
|
|
case 0x80 :
|
|
fDisp32 = true;
|
|
break;
|
|
}
|
|
|
|
if (fDisp32)
|
|
{
|
|
dwDisp = *(DWORD UNALIGNED *) (m_addr + m_ibModrm + 1);
|
|
}
|
|
|
|
ADDR addr = (ADDR) dwDisp;
|
|
|
|
if (ireg != -1)
|
|
{
|
|
addr += (*m_pfndwgetreg)(this, ireg);
|
|
}
|
|
|
|
if (iregIndex != -1)
|
|
{
|
|
addr += (*m_pfndwgetreg)(this, ireg) * uScale;
|
|
}
|
|
|
|
return(addr);
|
|
}
|
|
|
|
|
|
ADDR DISX86::AddrTarget() const
|
|
{
|
|
ADDR addr;
|
|
|
|
switch (m_trmtx86)
|
|
{
|
|
case trmtx86Unknown :
|
|
case trmtx86FallThrough :
|
|
case trmtx86Trap :
|
|
case trmtx86TrapCc :
|
|
case trmtx86JmpInd :
|
|
case trmtx86Ret :
|
|
case trmtx86Iret :
|
|
case trmtx86CallInd :
|
|
addr = addrNil;
|
|
break;
|
|
|
|
case trmtx86JmpShort :
|
|
case trmtx86JmpCcShort :
|
|
case trmtx86Loop :
|
|
case trmtx86Jcxz :
|
|
addr = m_addr + m_cb + *(signed char *) (m_rgbInstr + m_ibImmed);
|
|
break;
|
|
|
|
case trmtx86JmpNear :
|
|
case trmtx86JmpCcNear :
|
|
case trmtx86CallNear16 :
|
|
case trmtx86CallNear32 :
|
|
if (m_fOperand32)
|
|
{
|
|
addr = m_addr + m_cb + *(signed long UNALIGNED *) (m_rgbInstr + m_ibImmed);
|
|
}
|
|
|
|
else
|
|
{
|
|
addr = m_addr + m_cb + *(signed short UNALIGNED *) (m_rgbInstr + m_ibImmed);
|
|
}
|
|
|
|
if (m_archt == archtX8616)
|
|
{
|
|
// For 16 bit segments, don't change the segment portion.
|
|
|
|
addr = (m_addr & 0xFFFF0000) | (addr & 0x0000FFFF);
|
|
}
|
|
break;
|
|
|
|
case trmtx86JmpFar :
|
|
case trmtx86CallFar :
|
|
addr = *(ADDR UNALIGNED *) (m_rgbInstr + m_ibImmed);
|
|
break;
|
|
}
|
|
|
|
return(addr);
|
|
}
|
|
|
|
|
|
size_t DISX86::Cb() const
|
|
{
|
|
return(m_cb);
|
|
}
|
|
|
|
|
|
size_t DISX86::CbDisassemble(ADDR addr, const BYTE *pb, size_t cbMax)
|
|
{
|
|
m_addr = addr;
|
|
m_pbCur = pb;
|
|
m_cbMax = cbMax;
|
|
|
|
m_cb = 0;
|
|
|
|
m_fAddress32 = (m_archt != archtX8616);
|
|
m_fOperand32 = (m_archt != archtX8616);
|
|
m_bSegOverride = 0x00;
|
|
m_bPrefix = 0x00;
|
|
|
|
m_fOperOverride = false;
|
|
m_fAddrOverride = false;
|
|
|
|
Restart:
|
|
m_ibOp = m_cb;
|
|
|
|
if (m_cb == m_cbMax)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
BYTE bOpcd = *m_pbCur++;
|
|
m_cb++;
|
|
|
|
m_popcd = rgopcd + bOpcd;
|
|
|
|
if (m_popcd->pvMnemonic == NULL)
|
|
{
|
|
// This is not a normal instruction entry
|
|
|
|
switch (bOpcd)
|
|
{
|
|
case 0x0F : // Two byte instruction prefix
|
|
if (m_cb == m_cbMax)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
bOpcd = *m_pbCur++;
|
|
m_cb++;
|
|
|
|
m_popcd = rgopcd0F + bOpcd;
|
|
|
|
if (m_popcd->pvMnemonic == NULL)
|
|
{
|
|
// This is an invalid instruction
|
|
|
|
return(0);
|
|
}
|
|
break;
|
|
|
|
case 0x26 : // ES:
|
|
case 0x2E : // CS:
|
|
case 0x36 : // SS:
|
|
case 0x3E : // DS:
|
|
case 0x64 : // FS:
|
|
case 0x65 : // GS:
|
|
if (m_bSegOverride != 0)
|
|
{
|
|
// Multiple overrides
|
|
return(0);
|
|
}
|
|
|
|
m_bSegOverride = bOpcd;
|
|
goto Restart;
|
|
|
|
case 0x66 : // Operand Size Override
|
|
if (m_fOperOverride)
|
|
{
|
|
// Multiple overrides
|
|
return(0);
|
|
}
|
|
|
|
m_fOperOverride = true;
|
|
m_fOperand32 = !m_fOperand32;
|
|
goto Restart;
|
|
|
|
case 0x67 : // Address Size Override
|
|
if (m_fAddrOverride)
|
|
{
|
|
// Multiple overrides
|
|
return(0);
|
|
}
|
|
|
|
m_fAddrOverride = true;
|
|
m_fAddress32 = !m_fAddress32;
|
|
goto Restart;
|
|
|
|
case 0xF0 : // LOCK
|
|
case 0xF2 : // REPNE
|
|
case 0xF3 : // REP
|
|
if (m_bPrefix != 0)
|
|
{
|
|
// Multiple prefixes
|
|
return(0);
|
|
}
|
|
|
|
m_bPrefix = bOpcd;
|
|
goto Restart;
|
|
|
|
default :
|
|
// This is an invalid instruction
|
|
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
MODRMT modrmt;
|
|
|
|
if (m_popcd->pops != NULL)
|
|
{
|
|
// Get the MODRM type from the instruction operand definition
|
|
|
|
modrmt = m_popcd->pops->modrmt;
|
|
}
|
|
|
|
else
|
|
{
|
|
// This is a group entry. All grouped instructions have a MODRM.
|
|
|
|
modrmt = modrmtYes;
|
|
}
|
|
|
|
BYTE bModrm;
|
|
|
|
if (modrmt != modrmtNo)
|
|
{
|
|
m_ibModrm = m_cb;
|
|
|
|
if (m_cb == m_cbMax)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
bModrm = *m_pbCur++;
|
|
m_cb++;
|
|
|
|
if (m_fAddress32)
|
|
{
|
|
if (!FDisassembleModrm32(bModrm))
|
|
{
|
|
// Invalid instruction
|
|
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
if (!FDisassembleModrm16(bModrm))
|
|
{
|
|
// Invalid instruction
|
|
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
m_cbModrm = m_cb - m_ibModrm;
|
|
}
|
|
|
|
if (m_popcd->pops == NULL)
|
|
{
|
|
// This is a group entry. Get the opcode from the MODRM byte.
|
|
|
|
if (((bOpcd & 0xF8) == 0xD8) && ((bModrm & 0xC0) == 0xC0))
|
|
{
|
|
// This is a floating point instruction with MOD == 11.
|
|
// Note: There are no 0F Dx instructions to be misidentified.
|
|
|
|
m_popcd = PopcdFloatingPoint(bOpcd, bModrm);
|
|
|
|
if (m_popcd == NULL)
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
m_popcd = (OPCD *) m_popcd->pvMnemonic + ((bModrm >> 3) & 0x07);
|
|
}
|
|
|
|
if (m_popcd->pvMnemonic == NULL)
|
|
{
|
|
// This is an invalid instruction
|
|
|
|
return(0);
|
|
}
|
|
|
|
modrmt = m_popcd->pops->modrmt;
|
|
}
|
|
|
|
m_trmtx86 = (TRMTX86) m_popcd->trmtx86;
|
|
|
|
if (!m_fAddress32 && (m_trmtx86 == trmtx86CallNear32))
|
|
{
|
|
// We distinguish between 16 bit and 32 bit near calls in order to
|
|
// support mixed 16 and 32 bit code in NE images.
|
|
|
|
m_trmtx86 = trmtx86CallNear16;
|
|
}
|
|
|
|
// UNDONE: Check for invalid prefix bytes (e.g. REP JE Target)
|
|
|
|
if (modrmt == modrmtMem)
|
|
{
|
|
// This instruction only allows memory operands via MODRM
|
|
|
|
if ((bModrm & 0xC0) == 0xC0)
|
|
{
|
|
// Operand is a register
|
|
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
else if (modrmt == modrmtReg)
|
|
{
|
|
// This instruction only allows register operands via MODRM
|
|
|
|
if ((bModrm & 0xC0) != 0xC0)
|
|
{
|
|
// Operand is not a register
|
|
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
// Check for immediate bytes
|
|
|
|
m_ibImmed = m_cb;
|
|
|
|
size_t cbImmed;
|
|
|
|
switch (m_popcd->pops->icb)
|
|
{
|
|
case icbNil : // No immediate value
|
|
cbImmed = 0;
|
|
break;
|
|
|
|
case icbAP : // Far pointer
|
|
cbImmed = m_fOperand32 ? 6 : 4;
|
|
break;
|
|
|
|
case icbIb : // Immediate byte
|
|
cbImmed = 1;
|
|
break;
|
|
|
|
case icbIv : // Immediate operand size value
|
|
case icbJv : // Operand size displacement
|
|
cbImmed = m_fOperand32 ? 4 : 2;
|
|
break;
|
|
|
|
case icbIw : // Immediate word
|
|
cbImmed = 2;
|
|
break;
|
|
|
|
case icbIw_Ib : // Immediate word and immediate byte
|
|
cbImmed = 3;
|
|
break;
|
|
|
|
case icbJb : // Byte displacement
|
|
cbImmed = 1;
|
|
break;
|
|
|
|
case icbO : // Address size value
|
|
cbImmed = m_fAddress32 ? 4 : 2;
|
|
break;
|
|
}
|
|
|
|
m_cb += cbImmed;
|
|
|
|
if ((m_cb > m_cbMax) || (m_cb > 15))
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
memcpy(m_rgbInstr, pb, m_cb);
|
|
|
|
return(m_cb);
|
|
}
|
|
|
|
|
|
size_t DISX86::CbGenerateLoadAddress(BYTE *pb, size_t cbBuf, size_t *pibAddress) const
|
|
{
|
|
if (m_bSegOverride != 0x00)
|
|
{
|
|
// There is a segment override
|
|
|
|
return(0);
|
|
}
|
|
|
|
size_t cb = 0;
|
|
|
|
// UNDONE: PUSH and POP instructions are not recognized as having an
|
|
// UNDONE: implicit memory reference. Should they?
|
|
|
|
const OPS *pops = m_popcd->pops;
|
|
|
|
for (unsigned ioprnd = 0; ioprnd < 3; ioprnd++)
|
|
{
|
|
if (pops->rgoprnd[ioprnd].oprndt == oprndtNil)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (pops->rgoprnd[ioprnd].opreft == opreftNil)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
switch ((OPRNDT) pops->rgoprnd[ioprnd].oprndt)
|
|
{
|
|
case oprndtModrm : // Memory/register references from MODRM
|
|
cb = CbGenerateLea(pb, cbBuf, pibAddress);
|
|
break;
|
|
|
|
case oprndtOffset : // Address size immediate offset
|
|
cb = CbGenerateMovOffset(pb, cbBuf, pibAddress);
|
|
break;
|
|
|
|
case oprndtX : // DS:[eSI] for string instruction
|
|
cb = CbGenerateMovXSi(pb, cbBuf);
|
|
break;
|
|
|
|
case oprndtY : // ES:[eDI] for string instruction
|
|
cb = CbGenerateMovXDi(pb, cbBuf);
|
|
break;
|
|
|
|
default :
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return(cb);
|
|
}
|
|
|
|
|
|
size_t DISX86::CbJumpEntry() const
|
|
{
|
|
return(m_fAddress32 ? sizeof(DWORD) : sizeof(WORD));
|
|
}
|
|
|
|
|
|
size_t DISX86::CbMemoryReference() const
|
|
{
|
|
size_t cb = 0;
|
|
|
|
// UNDONE: PUSH and POP instructions are not recognized as having an
|
|
// UNDONE: implicit memory reference. Should they?
|
|
|
|
const OPS *pops = m_popcd->pops;
|
|
|
|
for (unsigned ioprnd = 0; ioprnd < 3; ioprnd++)
|
|
{
|
|
if (pops->rgoprnd[ioprnd].oprndt == oprndtNil)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (pops->rgoprnd[ioprnd].opreft == opreftNil)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
switch ((OPRNDT) pops->rgoprnd[ioprnd].oprndt)
|
|
{
|
|
case oprndtModrm : // Memory/register references from MODRM
|
|
if ((m_rgbInstr[m_ibModrm] & 0xC0) == 0xC0)
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case oprndtOffset : // Address size immediate offset
|
|
case oprndtX : // DS:[eSI] for string instruction
|
|
case oprndtY : // ES:[eDI] for string instruction
|
|
break;
|
|
|
|
case oprndtZ : // DS:[eBX] for XLAT
|
|
return(1);
|
|
|
|
default :
|
|
continue;
|
|
}
|
|
|
|
cb = pops->rgoprnd[ioprnd].bValue;
|
|
|
|
if (cb == 0)
|
|
{
|
|
cb = m_fOperand32 ? sizeof(DWORD) : sizeof(WORD);
|
|
|
|
// Check for special cases
|
|
|
|
if (pops == &opsRdGv_RdMa)
|
|
{
|
|
// BOUND instruction reads two operand size values
|
|
|
|
cb *= 2;
|
|
}
|
|
|
|
else if ((pops == &opsRdMp) || (pops == &opsWrGv_RdMp))
|
|
{
|
|
// Operand sized offset plus WORD segment/selector
|
|
|
|
cb += sizeof(WORD);
|
|
}
|
|
|
|
else if ((pops == &opsRdMenv) || (pops == &opsWrMenv))
|
|
{
|
|
// FRSTOR and FNSAVE
|
|
|
|
cb = m_fOperand32 ? 28 : 14;
|
|
}
|
|
|
|
else if ((pops == &opsRdMsta) || (pops == &opsWrMsta))
|
|
{
|
|
// FLDENV and FNSTENV
|
|
|
|
cb = m_fOperand32 ? 108 : 94;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return(cb);
|
|
}
|
|
|
|
|
|
size_t DISX86::CchFormatAddr(ADDR addr, char *sz, size_t cchMax) const
|
|
{
|
|
if (cchMax > INT_MAX)
|
|
{
|
|
cchMax = INT_MAX;
|
|
}
|
|
|
|
ostrstream ostr(sz, (int) cchMax);
|
|
|
|
FormatAddr(ostr, addr);
|
|
|
|
ostr << ends;
|
|
|
|
if (ostr.fail())
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
return((size_t) ostr.pcount());
|
|
}
|
|
|
|
|
|
size_t DISX86::CchFormatBytes(char *sz, size_t cchMax) const
|
|
{
|
|
// UNDONE: Consider grouping immediates as WORDs and DWORDs
|
|
|
|
if (cchMax < (3 * m_cb))
|
|
{
|
|
// Caller's buffer is too small
|
|
|
|
return(0);
|
|
}
|
|
|
|
for (size_t ib = 0; ib < m_cb; ib++)
|
|
{
|
|
if (ib != 0)
|
|
{
|
|
sz[-1] = ' ';
|
|
}
|
|
|
|
sprintf(sz, "%02X", m_rgbInstr[ib]);
|
|
|
|
sz += 3;
|
|
}
|
|
|
|
return(3 * m_cb - 1);
|
|
}
|
|
|
|
|
|
size_t DISX86::CchFormatBytesMax() const
|
|
{
|
|
return(44); // 3 * 15 - 1
|
|
}
|
|
|
|
|
|
size_t DISX86::CchFormatInstr(char *sz, size_t cchMax) const
|
|
{
|
|
if (cchMax > INT_MAX)
|
|
{
|
|
cchMax = INT_MAX;
|
|
}
|
|
|
|
ostrstream ostr(sz, (int) cchMax);
|
|
|
|
FormatInstr(ostr);
|
|
|
|
ostr << ends;
|
|
|
|
if (ostr.fail())
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
return((size_t) ostr.pcount());
|
|
}
|
|
|
|
|
|
size_t DISX86::Coperand() const
|
|
{
|
|
const OPS *pops = m_popcd->pops;
|
|
|
|
for (size_t ioprnd = 0; ioprnd < 3; ioprnd++)
|
|
{
|
|
if (pops->rgoprnd[ioprnd].oprndt == oprndtNil)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(ioprnd);
|
|
}
|
|
|
|
|
|
void DISX86::FormatAddr(ostream& ostr, ADDR addr) const
|
|
{
|
|
long lFlags = ostr.setf(ios::uppercase);
|
|
char chFill = ostr.fill('0');
|
|
|
|
if (m_archt == archtX8616)
|
|
{
|
|
unsigned addrSeg = (unsigned) ((addr & 0xFFFF0000) >> 16);
|
|
unsigned addrOff = (unsigned) (addr & 0x0000FFFF);
|
|
|
|
ostr << hex << setw(4) << addrSeg << ':' << hex << setw(4) << addrOff;
|
|
}
|
|
|
|
else
|
|
{
|
|
ostr << hex << setw(8) << addr;
|
|
}
|
|
|
|
ostr.fill(chFill);
|
|
ostr.flags(lFlags);
|
|
}
|
|
|
|
|
|
void DISX86::FormatInstr(ostream& ostr) const
|
|
{
|
|
long lFlags = ostr.setf(ios::uppercase);
|
|
char chFill = ostr.fill('0');
|
|
|
|
size_t cch = 0;
|
|
|
|
if (m_bPrefix != 0x00)
|
|
{
|
|
switch (m_bPrefix)
|
|
{
|
|
case 0xF0 :
|
|
ostr << "lock ";
|
|
cch = 5;
|
|
break;
|
|
|
|
case 0xF2 :
|
|
ostr << "repne ";
|
|
cch = 6;
|
|
break;
|
|
|
|
case 0xF3 :
|
|
ostr << "rep ";
|
|
cch = 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ostr << (char *) m_popcd->pvMnemonic;
|
|
cch += strlen((char *) m_popcd->pvMnemonic);
|
|
|
|
const OPS *pops = m_popcd->pops;
|
|
|
|
for (unsigned ioprnd = 0; ioprnd < 3; ioprnd++)
|
|
{
|
|
if (pops->rgoprnd[ioprnd].oprndt == oprndtNil)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (ioprnd == 0)
|
|
{
|
|
// Pad opcode field to 12 characters
|
|
|
|
do
|
|
{
|
|
ostr << ' ';
|
|
}
|
|
while (++cch < 12);
|
|
}
|
|
|
|
else
|
|
{
|
|
ostr << ',';
|
|
}
|
|
|
|
FormatOperand(ostr, (OPRNDT) pops->rgoprnd[ioprnd].oprndt, pops->rgoprnd[ioprnd].bValue);
|
|
}
|
|
|
|
ostr.fill(chFill);
|
|
ostr.flags(lFlags);
|
|
}
|
|
|
|
|
|
DIS::MEMREFT DISX86::Memreft() const
|
|
{
|
|
switch (m_bPrefix)
|
|
{
|
|
case 0xF2 : // repne
|
|
case 0xF3 : // rep
|
|
return(memreftOther);
|
|
}
|
|
|
|
MEMREFT memreft = memreftNone;
|
|
|
|
// UNDONE: Instructions with implicit spack references are not recognized
|
|
// UNDONE: as memory references. This includes PUSH, POP, CALL, RET, IRET,
|
|
// UNDONE: ENTER, and LEAVE. Should they?
|
|
|
|
const OPS *pops = m_popcd->pops;
|
|
|
|
for (unsigned ioprnd = 0; ioprnd < 3; ioprnd++)
|
|
{
|
|
if (pops->rgoprnd[ioprnd].oprndt == oprndtNil)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (pops->rgoprnd[ioprnd].opreft == opreftNil)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
switch ((OPRNDT) pops->rgoprnd[ioprnd].oprndt)
|
|
{
|
|
case oprndtModrm : // Memory/register references from MODRM
|
|
if ((m_rgbInstr[m_ibModrm] & 0xC0) == 0xC0)
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case oprndtOffset : // Address size immediate offset
|
|
break;
|
|
|
|
case oprndtX : // DS:[eSI] for string instruction
|
|
case oprndtY : // ES:[eDI] for string instruction
|
|
case oprndtZ : // DS:[eBX] for XLAT
|
|
// UNDONE: Should these be Other or Read, Write, Read?
|
|
|
|
return(memreftOther);
|
|
|
|
default :
|
|
continue;
|
|
}
|
|
|
|
if (memreft != memreftNone)
|
|
{
|
|
// Multiple memory references
|
|
|
|
return(memreftOther);
|
|
}
|
|
|
|
switch ((OPREFT) pops->rgoprnd[ioprnd].opreft)
|
|
{
|
|
case opreftRd : // Operand is read
|
|
memreft = memreftRead;
|
|
break;
|
|
|
|
case opreftRw : // Operand is read and written
|
|
memreft = memreftRdWr;
|
|
break;
|
|
|
|
case opreftWr : // Operand is written
|
|
memreft = memreftWrite;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(memreft);
|
|
}
|
|
|
|
|
|
TRMT DISX86::Trmt() const
|
|
{
|
|
return(mptrmtx86trmt[m_trmtx86]);
|
|
}
|
|
|
|
|
|
TRMTA DISX86::Trmta() const
|
|
{
|
|
return((TRMTA) m_trmtx86);
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------
|
|
// Private Methods
|
|
// -----------------------------------------------------------------
|
|
|
|
inline ADDR DISX86::AddrJumpTable32() const
|
|
{
|
|
BYTE b = m_rgbInstr[m_ibModrm];
|
|
|
|
const BYTE *pb = m_rgbInstr + m_ibModrm + 1;
|
|
|
|
if ((b & 0x07) == 0x04)
|
|
{
|
|
// This MODRM is followed by a SIB
|
|
|
|
pb++;
|
|
|
|
if ((b & 0xC0) == 0x00)
|
|
{
|
|
BYTE bSib = m_rgbInstr[m_ibModrm+1];
|
|
|
|
if ((bSib & 0x07) != 0x05)
|
|
{
|
|
// Operand is not [XX+disp32]
|
|
|
|
return(addrNil);
|
|
}
|
|
|
|
return(*(ADDR UNALIGNED *) pb);
|
|
}
|
|
}
|
|
|
|
if ((b & 0xC0) != 0x80)
|
|
{
|
|
// Operand is not [XX+disp32]
|
|
|
|
return(addrNil);
|
|
}
|
|
|
|
return(*(ADDR UNALIGNED *) pb);
|
|
}
|
|
|
|
|
|
inline ADDR DISX86::AddrJumpTable16() const
|
|
{
|
|
BYTE b = m_rgbInstr[m_ibModrm];
|
|
|
|
if (m_bSegOverride != 0x2E)
|
|
{
|
|
// No CS override
|
|
|
|
return(addrNil);
|
|
}
|
|
|
|
if ((b & 0xC0) != 0x80)
|
|
{
|
|
// Operand is not [XX+disp16]
|
|
|
|
return(addrNil);
|
|
}
|
|
|
|
WORD w = *(WORD UNALIGNED *) (m_rgbInstr + m_ibModrm + 1);
|
|
|
|
ADDR addr = (m_addr & 0xFFFF0000) | w;
|
|
|
|
return(addr);
|
|
}
|
|
|
|
|
|
inline size_t DISX86::CbGenerateLea(BYTE *pb, size_t cbBuf, size_t *pibAddress) const
|
|
{
|
|
BYTE b = m_rgbInstr[m_ibModrm];
|
|
|
|
if ((b & 0xC0) == 0xC0)
|
|
{
|
|
// Operand is a register
|
|
|
|
return(0);
|
|
}
|
|
|
|
// Calculate size of generated instruction starting with opcode byte
|
|
|
|
size_t cb = 1;
|
|
|
|
if (m_fAddrOverride)
|
|
{
|
|
// If the source had an address override, we need one too
|
|
|
|
cb++;
|
|
}
|
|
|
|
if (pibAddress != NULL)
|
|
{
|
|
size_t ibDisp;
|
|
|
|
if (m_fAddress32)
|
|
{
|
|
ibDisp = IbDispModrm32();
|
|
}
|
|
|
|
else
|
|
{
|
|
ibDisp = IbDispModrm16();
|
|
}
|
|
|
|
*pibAddress = cb + (ibDisp - m_ibModrm);
|
|
}
|
|
|
|
cb += m_cbModrm;
|
|
|
|
if (cb > cbBuf)
|
|
{
|
|
// The generated instruction won't fit
|
|
|
|
return(0);
|
|
}
|
|
|
|
// Generate the instruction
|
|
|
|
// UNDONE: We always generate an LEA when a MOV may be sufficient
|
|
|
|
if (m_fAddrOverride)
|
|
{
|
|
*pb++ = 0x67;
|
|
}
|
|
|
|
*pb++ = 0x8D;
|
|
|
|
memcpy(pb, m_rgbInstr + m_ibModrm, m_cbModrm);
|
|
|
|
// UNDONE: Force the target register to be EAX
|
|
|
|
*pb = (BYTE) (*pb & 0xC7);
|
|
|
|
return(cb);
|
|
}
|
|
|
|
|
|
inline size_t DISX86::CbGenerateMovOffset(BYTE *pb, size_t cbBuf, size_t *pibAddress) const
|
|
{
|
|
// Calculate size of generated instruction starting with opcode byte
|
|
|
|
size_t cb = 1;
|
|
|
|
bool fNeedOperOverride = (m_fAddress32 ^ (m_archt != archtX8616));
|
|
|
|
if (fNeedOperOverride)
|
|
{
|
|
// If the source had an address override, we need an operand override
|
|
|
|
cb++;
|
|
}
|
|
|
|
if (pibAddress != NULL)
|
|
{
|
|
// If there is an immediate displacement, it follows the MODRM byte
|
|
|
|
*pibAddress = cb;
|
|
}
|
|
|
|
size_t cbOffset = m_fAddress32 ? sizeof(DWORD) : sizeof(WORD);
|
|
|
|
cb += cbOffset;
|
|
|
|
if (cb > cbBuf)
|
|
{
|
|
// The generated instruction won't fit
|
|
|
|
return(0);
|
|
}
|
|
|
|
if (fNeedOperOverride)
|
|
{
|
|
*pb++ = 0x66;
|
|
}
|
|
|
|
// UNDONE: The target register is always AX/EAX
|
|
|
|
*pb++ = 0xb8;
|
|
|
|
memcpy(pb, m_rgbInstr + m_ibImmed, cbOffset);
|
|
|
|
return(cb);
|
|
}
|
|
|
|
|
|
inline size_t DISX86::CbGenerateMovXDi(BYTE *pb, size_t cbBuf) const
|
|
{
|
|
bool fNeedOperOverride = (m_fAddress32 ^ (m_archt != archtX8616));
|
|
|
|
size_t cb = fNeedOperOverride + 2;
|
|
|
|
if (cb > cbBuf)
|
|
{
|
|
// The generated instruction won't fit
|
|
|
|
return(0);
|
|
}
|
|
|
|
if (fNeedOperOverride)
|
|
{
|
|
*pb++ = 0x66;
|
|
}
|
|
|
|
// UNDONE: The target register is always AX/EAX
|
|
|
|
*pb++ = 0x8b;
|
|
*pb++ = 0xc7;
|
|
|
|
return(cb);
|
|
}
|
|
|
|
|
|
inline size_t DISX86::CbGenerateMovXSi(BYTE *pb, size_t cbBuf) const
|
|
{
|
|
bool fNeedOperOverride = (m_fAddress32 ^ (m_archt != archtX8616));
|
|
|
|
size_t cb = fNeedOperOverride + 2;
|
|
|
|
if (cb > cbBuf)
|
|
{
|
|
// The generated instruction won't fit
|
|
|
|
return(0);
|
|
}
|
|
|
|
if (fNeedOperOverride)
|
|
{
|
|
*pb++ = 0x66;
|
|
}
|
|
|
|
// UNDONE: The target register is always AX/EAX
|
|
|
|
*pb++ = 0x8b;
|
|
*pb++ = 0xc6;
|
|
|
|
return(cb);
|
|
}
|
|
|
|
|
|
inline bool DISX86::FDisassembleModrm32(BYTE b)
|
|
{
|
|
if (((b & 0x07) == 0x04) && ((b & 0xC0) != 0xC0))
|
|
{
|
|
// This MODRM is followed by a SIB
|
|
|
|
if (m_cb == m_cbMax)
|
|
{
|
|
return(false);
|
|
}
|
|
|
|
BYTE bSib = *m_pbCur++;
|
|
m_cb++;
|
|
|
|
if ((bSib & 0x38) == 0x20)
|
|
{
|
|
// No index register selected. SS must be 0.
|
|
|
|
if ((bSib & 0xC0) != 0x00)
|
|
{
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
if ((bSib & 0x07) == 0x05)
|
|
{
|
|
// Base register is EBP. Check for special case of disp32.
|
|
|
|
if ((b & 0xC0) == 0x00)
|
|
{
|
|
// Operand is [disp32]
|
|
|
|
m_cb += sizeof(DWORD);
|
|
|
|
if (m_cb > m_cbMax)
|
|
{
|
|
return(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (b & 0xC0)
|
|
{
|
|
case 0x00 :
|
|
if ((b & 0x07) == 0x05)
|
|
{
|
|
// Operand is [disp32]
|
|
|
|
m_cb += sizeof(DWORD);
|
|
|
|
if (m_cb > m_cbMax)
|
|
{
|
|
return(false);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x40 :
|
|
// Operand is [XX+disp8]
|
|
|
|
m_cb += sizeof(BYTE);
|
|
|
|
if (m_cb > m_cbMax)
|
|
{
|
|
return(false);
|
|
}
|
|
break;
|
|
|
|
case 0x80 :
|
|
// Operand is [XX+disp32]
|
|
|
|
m_cb += sizeof(DWORD);
|
|
|
|
if (m_cb > m_cbMax)
|
|
{
|
|
return(false);
|
|
}
|
|
break;
|
|
|
|
case 0xC0 :
|
|
// Operand is REG
|
|
|
|
break;
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
inline bool DISX86::FDisassembleModrm16(BYTE b)
|
|
{
|
|
switch (b & 0xC0)
|
|
{
|
|
case 0x00 :
|
|
if ((b & 0x07) == 0x06)
|
|
{
|
|
// Operand is [disp16]
|
|
|
|
m_cb += sizeof(WORD);
|
|
|
|
if (m_cb > m_cbMax)
|
|
{
|
|
return(false);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x40 :
|
|
// Operand is [XX+disp8]
|
|
|
|
m_cb += sizeof(BYTE);
|
|
|
|
if (m_cb > m_cbMax)
|
|
{
|
|
return(false);
|
|
}
|
|
break;
|
|
|
|
case 0x80 :
|
|
// Operand is [XX+disp16]
|
|
|
|
m_cb += sizeof(WORD);
|
|
|
|
if (m_cb > m_cbMax)
|
|
{
|
|
return(false);
|
|
}
|
|
break;
|
|
|
|
case 0xC0 :
|
|
// Operand is REG
|
|
|
|
break;
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
void DISX86::FormatHex(ostream& ostr, DWORD dw) const
|
|
{
|
|
if (dw <= 9)
|
|
{
|
|
ostr << dw;
|
|
return;
|
|
}
|
|
|
|
char szHex[11];
|
|
sprintf(szHex, "%lX", dw);
|
|
|
|
if (!isdigit(szHex[0]))
|
|
{
|
|
ostr << '0';
|
|
}
|
|
|
|
ostr << szHex << 'h';
|
|
}
|
|
|
|
|
|
void DISX86::FormatModrm16(ostream& ostr, unsigned cb, bool fMm) const
|
|
{
|
|
BYTE b = m_rgbInstr[m_ibModrm];
|
|
|
|
if ((b & 0xC0) == 0xC0)
|
|
{
|
|
// Operand is a register
|
|
|
|
if (fMm)
|
|
{
|
|
ostr << "mm" << (unsigned) (b & 0x07);
|
|
}
|
|
|
|
else
|
|
{
|
|
FormatRegister(ostr, b & 0x07, cb);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
bool fDisp16 = false;
|
|
const char *szReg = NULL;
|
|
|
|
if ((b & 0xC7) == 0x06)
|
|
{
|
|
// Special case of [disp16] operand
|
|
|
|
fDisp16 = true;
|
|
}
|
|
|
|
else
|
|
{
|
|
szReg = rgszBase16[b & 0x07];
|
|
}
|
|
|
|
char chDisp = '\0';
|
|
DWORD dwDisp;
|
|
|
|
switch (b & 0xC0)
|
|
{
|
|
BYTE bDisp;
|
|
|
|
case 0x40 :
|
|
bDisp = m_rgbInstr[m_ibModrm + 1];
|
|
|
|
if ((bDisp & 0x80) == 0x00)
|
|
{
|
|
chDisp = '+';
|
|
dwDisp = bDisp;
|
|
}
|
|
|
|
else
|
|
{
|
|
chDisp = '-';
|
|
dwDisp = -bDisp & 0xFF;
|
|
}
|
|
break;
|
|
|
|
case 0x80 :
|
|
fDisp16 = true;
|
|
break;
|
|
}
|
|
|
|
size_t cchSymbol = 0;
|
|
char szSymbol[1024];
|
|
|
|
if (fDisp16)
|
|
{
|
|
if (m_pfncchfixup != 0)
|
|
{
|
|
cchSymbol = (*m_pfncchfixup)(this, m_addr + m_ibModrm + 1, sizeof(WORD), szSymbol, sizeof(szSymbol), &dwDisp);
|
|
}
|
|
|
|
if (cchSymbol != 0)
|
|
{
|
|
fDisp16 = false;
|
|
|
|
if (dwDisp != 0)
|
|
{
|
|
chDisp = '+';
|
|
}
|
|
}
|
|
}
|
|
|
|
FormatOpSize(ostr, cb);
|
|
FormatSegOverride(ostr);
|
|
|
|
if ((m_bSegOverride == 0x00) && (cchSymbol == 0) && (szReg == NULL))
|
|
{
|
|
// Add default DS: override for MASM compatibility if there is no symbol or register
|
|
|
|
ostr << "ds:";
|
|
}
|
|
|
|
// If there is a symbol and a register than the symbol preceeds the brackets
|
|
|
|
if ((cchSymbol != 0) && (szReg != NULL))
|
|
{
|
|
if (m_bSegOverride != 0x00)
|
|
{
|
|
ostr << '[';
|
|
}
|
|
|
|
ostr << szSymbol;
|
|
|
|
if (m_bSegOverride != 0x00)
|
|
{
|
|
ostr << ']';
|
|
}
|
|
}
|
|
|
|
ostr << '[';
|
|
|
|
if (szReg != NULL)
|
|
{
|
|
ostr << szReg;
|
|
}
|
|
|
|
else if (cchSymbol != 0)
|
|
{
|
|
ostr << szSymbol;
|
|
}
|
|
|
|
if (fDisp16)
|
|
{
|
|
// This may be an address w/o fixup information. Format as flat address.
|
|
|
|
if (szReg != NULL)
|
|
{
|
|
ostr << '+';
|
|
}
|
|
|
|
ostr << hex
|
|
<< setw(4)
|
|
<< *(WORD UNALIGNED *) (m_rgbInstr + m_ibModrm + 1)
|
|
<< 'h';
|
|
}
|
|
|
|
else if (chDisp != '\0')
|
|
{
|
|
ostr << chDisp;
|
|
|
|
FormatHex(ostr, dwDisp);
|
|
}
|
|
|
|
ostr << ']';
|
|
}
|
|
|
|
|
|
void DISX86::FormatModrm32(ostream& ostr, unsigned cb, bool fMm) const
|
|
{
|
|
BYTE b = m_rgbInstr[m_ibModrm];
|
|
|
|
if ((b & 0xC0) == 0xC0)
|
|
{
|
|
// Operand is a register
|
|
|
|
if (fMm)
|
|
{
|
|
ostr << "mm" << (unsigned) (b & 0x07);
|
|
}
|
|
|
|
else
|
|
{
|
|
FormatRegister(ostr, b & 0x07, cb);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
bool fDisp32 = false;
|
|
int iregIndex = -1;
|
|
unsigned uScale;
|
|
|
|
const BYTE *pbDisp = m_rgbInstr + m_ibModrm + 1;
|
|
|
|
int ireg = (b & 0x07);
|
|
|
|
if (ireg != 4)
|
|
{
|
|
// There is no SIB byte
|
|
|
|
if ((b & 0xC7) == 0x05)
|
|
{
|
|
// Special case of [disp32] operand
|
|
|
|
fDisp32 = true;
|
|
|
|
ireg = -1;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
// This MODRM is followed by a SIB
|
|
|
|
BYTE bSib = *pbDisp++;
|
|
|
|
int iregBase = (bSib & 0x07);
|
|
|
|
if ((iregBase != 5) || ((b & 0xC0) != 0x00))
|
|
{
|
|
ireg = iregBase;
|
|
}
|
|
|
|
else
|
|
{
|
|
ireg = -1;
|
|
}
|
|
|
|
iregIndex = ((bSib >> 3) & 0x07);
|
|
|
|
if (iregIndex != 4)
|
|
{
|
|
uScale = 1 << (bSib >> 6);
|
|
}
|
|
|
|
else
|
|
{
|
|
iregIndex = -1;
|
|
}
|
|
|
|
if ((iregBase == 5) && ((b & 0xC0) == 0x00))
|
|
{
|
|
fDisp32 = true;
|
|
}
|
|
}
|
|
|
|
bool fDisp = false;
|
|
DWORD dwDisp = 0;
|
|
|
|
switch (b & 0xC0)
|
|
{
|
|
case 0x40 :
|
|
fDisp = true;
|
|
|
|
dwDisp = *pbDisp;
|
|
|
|
if ((dwDisp & 0x80) != 0)
|
|
{
|
|
dwDisp |= 0xFFFFFF00;
|
|
}
|
|
break;
|
|
|
|
case 0x80 :
|
|
fDisp32 = true;
|
|
break;
|
|
}
|
|
|
|
size_t cchSymbol = 0;
|
|
char szSymbol[1024];
|
|
|
|
if (fDisp32)
|
|
{
|
|
DWORD dw;
|
|
|
|
if (m_pfncchfixup != 0)
|
|
{
|
|
cchSymbol = (*m_pfncchfixup)(this, m_addr + m_ibModrm + 1, sizeof(DWORD), szSymbol, sizeof(szSymbol), &dw);
|
|
}
|
|
|
|
if (cchSymbol != 0)
|
|
{
|
|
fDisp32 = false;
|
|
fDisp = (dw != 0);
|
|
|
|
dwDisp = dw;
|
|
}
|
|
|
|
else
|
|
{
|
|
dwDisp = *(DWORD UNALIGNED *) pbDisp;
|
|
}
|
|
}
|
|
|
|
if ((cchSymbol == 0) && (m_pfncchregrel != 0))
|
|
{
|
|
DWORD dw;
|
|
|
|
if (ireg != -1)
|
|
{
|
|
cchSymbol = (*m_pfncchregrel)(this, ireg, dwDisp, szSymbol, sizeof(szSymbol), &dw);
|
|
}
|
|
|
|
if (cchSymbol != 0)
|
|
{
|
|
ireg = -1;
|
|
}
|
|
|
|
else if ((iregIndex != -1) && (uScale == 1))
|
|
{
|
|
cchSymbol = (*m_pfncchregrel)(this, iregIndex, dwDisp, szSymbol, sizeof(szSymbol), &dw);
|
|
|
|
if (cchSymbol != 0)
|
|
{
|
|
iregIndex = -1;
|
|
}
|
|
}
|
|
|
|
if (cchSymbol != 0)
|
|
{
|
|
fDisp32 = false;
|
|
fDisp = (dw != 0);
|
|
|
|
dwDisp = dw;
|
|
}
|
|
}
|
|
|
|
FormatOpSize(ostr, cb);
|
|
FormatSegOverride(ostr);
|
|
|
|
bool fReg = (ireg != -1) || (iregIndex != -1);
|
|
|
|
if ((m_bSegOverride == 0x00) && (cchSymbol == 0) && !fReg)
|
|
{
|
|
// Add default DS: override for MASM compatibility if there is no symbol or register
|
|
|
|
ostr << "ds:";
|
|
}
|
|
|
|
// If there is a symbol and a register than the symbol preceeds the brackets
|
|
|
|
if ((cchSymbol != 0) && fReg)
|
|
{
|
|
if (m_bSegOverride != 0x00)
|
|
{
|
|
ostr << '[';
|
|
}
|
|
|
|
ostr << szSymbol;
|
|
|
|
if (m_bSegOverride != 0x00)
|
|
{
|
|
ostr << ']';
|
|
}
|
|
}
|
|
|
|
ostr << '[';
|
|
|
|
if (fReg)
|
|
{
|
|
if (ireg != -1)
|
|
{
|
|
ostr << rgszReg32[ireg];
|
|
}
|
|
|
|
if (iregIndex != -1)
|
|
{
|
|
if (ireg != -1)
|
|
{
|
|
ostr << '+';
|
|
}
|
|
|
|
ostr << rgszReg32[iregIndex];
|
|
|
|
if (uScale != 1)
|
|
{
|
|
ostr << '*' << uScale;
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (cchSymbol != 0)
|
|
{
|
|
ostr << szSymbol;
|
|
}
|
|
|
|
if (fDisp32)
|
|
{
|
|
// This may be an address w/o fixup information. Format as flat address.
|
|
|
|
if (fReg)
|
|
{
|
|
ostr << '+';
|
|
}
|
|
|
|
ostr << hex
|
|
<< setw(8)
|
|
<< dwDisp
|
|
<< 'h';
|
|
}
|
|
|
|
else if (fDisp)
|
|
{
|
|
if (dwDisp & 0x80000000)
|
|
{
|
|
ostr << '-';
|
|
|
|
dwDisp = 0 - dwDisp;
|
|
}
|
|
|
|
else
|
|
{
|
|
ostr << '+';
|
|
}
|
|
|
|
FormatHex(ostr, dwDisp);
|
|
}
|
|
|
|
ostr << ']';
|
|
}
|
|
|
|
|
|
void DISX86::FormatOperand(ostream &ostr, OPRNDT oprndt, unsigned bValue) const
|
|
{
|
|
size_t cch;
|
|
char szSymbol[1024];
|
|
DWORD dwDisp;
|
|
int ireg;
|
|
|
|
switch (oprndt)
|
|
{
|
|
case oprndtAP : // Far address
|
|
if (m_pfncchfixup != 0)
|
|
{
|
|
size_t cbFixup = (m_fOperand32 ? sizeof(DWORD) : sizeof(WORD)) + sizeof(WORD);
|
|
|
|
cch = (*m_pfncchfixup)(this, m_addr + m_ibImmed, cbFixup, szSymbol, sizeof(szSymbol), &dwDisp);
|
|
}
|
|
|
|
else
|
|
{
|
|
cch = 0;
|
|
}
|
|
|
|
if ((cch == 0) && (m_pfncchaddr != 0) && !m_fOperand32)
|
|
{
|
|
cch = (*m_pfncchaddr)(this, AddrTarget(), szSymbol, sizeof(szSymbol), &dwDisp);
|
|
}
|
|
|
|
if (cch != 0)
|
|
{
|
|
ostr << szSymbol;
|
|
|
|
if (dwDisp != 0)
|
|
{
|
|
ostr << '+';
|
|
|
|
FormatHex(ostr, dwDisp);
|
|
}
|
|
}
|
|
|
|
else if (m_fOperand32)
|
|
{
|
|
ostr << hex
|
|
<< setw(4)
|
|
<< *(WORD UNALIGNED *) (m_rgbInstr + m_ibImmed + sizeof(DWORD))
|
|
<< ':'
|
|
<< hex
|
|
<< setw(8)
|
|
<< *(DWORD UNALIGNED *) (m_rgbInstr + m_ibImmed);
|
|
}
|
|
|
|
else
|
|
{
|
|
ostr << hex
|
|
<< setw(4)
|
|
<< *(WORD UNALIGNED *) (m_rgbInstr + m_ibImmed + sizeof(WORD))
|
|
<< ':'
|
|
<< hex
|
|
<< setw(4)
|
|
<< *(WORD UNALIGNED *) (m_rgbInstr + m_ibImmed);
|
|
|
|
}
|
|
break;
|
|
|
|
case oprndtCd : // CRx register from MODRM reg
|
|
ireg = (m_rgbInstr[m_ibModrm] >> 3) & 0x07;
|
|
|
|
ostr << "cr" << ireg;
|
|
break;
|
|
|
|
case oprndtConst : // Constant from bValue
|
|
ostr << bValue;
|
|
break;
|
|
|
|
case oprndtDd : // DRx register from MODRM reg
|
|
ireg = (m_rgbInstr[m_ibModrm] >> 3) & 0x07;
|
|
|
|
ostr << "dr" << ireg;
|
|
break;
|
|
|
|
case oprndtGvOp : // General register (operand size) from opcode
|
|
ireg = m_rgbInstr[m_ibOp] & 0x07;
|
|
|
|
FormatRegister(ostr, ireg, bValue);
|
|
break;
|
|
|
|
case oprndtIb : // Immediate byte
|
|
FormatHex(ostr, m_rgbInstr[m_ibImmed]);
|
|
break;
|
|
|
|
case oprndtIb2 : // Immediate byte
|
|
FormatHex(ostr, m_rgbInstr[m_ibImmed + 2]);
|
|
break;
|
|
|
|
case oprndtIv : // Immediate operand size value
|
|
if (m_pfncchfixup != 0)
|
|
{
|
|
size_t cbFixup = m_fOperand32 ? sizeof(DWORD) : sizeof(WORD);
|
|
|
|
cch = (*m_pfncchfixup)(this, m_addr + m_ibImmed, cbFixup, szSymbol, sizeof(szSymbol), &dwDisp);
|
|
}
|
|
|
|
else
|
|
{
|
|
cch = 0;
|
|
}
|
|
|
|
if (cch != 0)
|
|
{
|
|
ostr << "offset " << szSymbol;
|
|
|
|
if (dwDisp != 0)
|
|
{
|
|
ostr << '+';
|
|
|
|
FormatHex(ostr, dwDisp);
|
|
}
|
|
}
|
|
|
|
else if (m_fOperand32)
|
|
{
|
|
FormatHex(ostr, *(DWORD UNALIGNED *) (m_rgbInstr + m_ibImmed));
|
|
}
|
|
|
|
else
|
|
{
|
|
FormatHex(ostr, *(WORD UNALIGNED *) (m_rgbInstr + m_ibImmed));
|
|
}
|
|
break;
|
|
|
|
case oprndtIw : // Immediate word
|
|
FormatHex(ostr, *(WORD UNALIGNED *) (m_rgbInstr + m_ibImmed));
|
|
break;
|
|
|
|
case oprndtJb : // Relative address byte
|
|
case oprndtJv : // Relative address operand size value
|
|
if ((oprndt == oprndtJv) && (m_pfncchfixup != 0))
|
|
{
|
|
size_t cbFixup = m_fOperand32 ? sizeof(DWORD) : sizeof(WORD);
|
|
|
|
cch = (*m_pfncchfixup)(this, m_addr + m_ibImmed, cbFixup, szSymbol, sizeof(szSymbol), &dwDisp);
|
|
}
|
|
|
|
else
|
|
{
|
|
cch = 0;
|
|
}
|
|
|
|
if ((cch == 0) && (m_pfncchaddr != 0))
|
|
{
|
|
cch = (*m_pfncchaddr)(this, AddrTarget(), szSymbol, sizeof(szSymbol), &dwDisp);
|
|
}
|
|
|
|
if (cch != 0)
|
|
{
|
|
ostr << szSymbol;
|
|
|
|
if (dwDisp != 0)
|
|
{
|
|
ostr << '+';
|
|
|
|
FormatHex(ostr, dwDisp);
|
|
}
|
|
}
|
|
|
|
else if (m_fAddress32)
|
|
{
|
|
ostr << hex << setw(8) << AddrTarget();
|
|
}
|
|
|
|
else
|
|
{
|
|
ostr << hex << setw(4) << (AddrTarget() & 0xFFFF);
|
|
}
|
|
break;
|
|
|
|
case oprndtMmModrm : // Memory/MM register references from MODRM (MMX)
|
|
if (m_fAddress32)
|
|
{
|
|
FormatModrm32(ostr, bValue, true);
|
|
}
|
|
|
|
else
|
|
{
|
|
FormatModrm16(ostr, bValue, true);
|
|
}
|
|
break;
|
|
|
|
case oprndtMmModrmReg : // MM register from MODRM reg (MMX)
|
|
ireg = (m_rgbInstr[m_ibModrm] >> 3) & 0x07;
|
|
|
|
ostr << "mm" << ireg;
|
|
break;
|
|
|
|
case oprndtModrm : // Memory references from MODRM
|
|
if (m_fAddress32)
|
|
{
|
|
FormatModrm32(ostr, bValue, false);
|
|
}
|
|
|
|
else
|
|
{
|
|
FormatModrm16(ostr, bValue, false);
|
|
}
|
|
break;
|
|
|
|
case oprndtModrmReg : // General register from MODRM reg
|
|
ireg = (m_rgbInstr[m_ibModrm] >> 3) & 0x07;
|
|
|
|
FormatRegister(ostr, ireg, bValue);
|
|
break;
|
|
|
|
case oprndtModrmSReg : // Segment register from MODRM reg
|
|
ireg = (m_rgbInstr[m_ibModrm] >> 3) & 0x07;
|
|
|
|
ostr << rgszSReg[ireg];
|
|
break;
|
|
|
|
case oprndtOffset : // Address size immediate offset
|
|
FormatSegOverride(ostr);
|
|
|
|
if (m_pfncchfixup != 0)
|
|
{
|
|
size_t cbFixup = m_fAddress32 ? sizeof(DWORD) : sizeof(WORD);
|
|
|
|
cch = (*m_pfncchfixup)(this, m_addr + m_ibImmed, cbFixup, szSymbol, sizeof(szSymbol), &dwDisp);
|
|
}
|
|
|
|
else
|
|
{
|
|
cch = 0;
|
|
}
|
|
|
|
if (cch != 0)
|
|
{
|
|
ostr << '[' << szSymbol;
|
|
|
|
if (dwDisp != 0)
|
|
{
|
|
ostr << '+';
|
|
|
|
FormatHex(ostr, dwDisp);
|
|
}
|
|
|
|
ostr << ']';
|
|
}
|
|
|
|
else if (m_fAddress32)
|
|
{
|
|
ostr << '['
|
|
<< hex
|
|
<< setw(8)
|
|
<< *(DWORD UNALIGNED *) (m_rgbInstr + m_ibImmed)
|
|
<< ']';
|
|
}
|
|
|
|
else
|
|
{
|
|
ostr << '['
|
|
<< hex
|
|
<< setw(4)
|
|
<< *(WORD UNALIGNED *) (m_rgbInstr + m_ibImmed)
|
|
<< ']';
|
|
}
|
|
break;
|
|
|
|
case oprndtRb : // General register (byte) from bValue
|
|
ostr << rgszReg8[bValue];
|
|
break;
|
|
|
|
case oprndtRv : // General register (operand size) from bValue
|
|
FormatRegister(ostr, (int) bValue, 0);
|
|
break;
|
|
|
|
case oprndtRw : // General register (word) from bValue
|
|
ostr << rgszReg16[bValue];
|
|
break;
|
|
|
|
case oprndtST : // Floating point top of stack
|
|
ostr << "st";
|
|
break;
|
|
|
|
case oprndtSTi : // Floating point register from MODRM reg
|
|
ireg = m_rgbInstr[m_ibModrm] & 0x07;
|
|
|
|
ostr << "st(" << ireg << ')';
|
|
break;
|
|
|
|
case oprndtSw : // Segment register (word) from bValue
|
|
ostr << rgszSReg[bValue];
|
|
break;
|
|
|
|
case oprndtTd : // TRx register from MODRM reg
|
|
ireg = (m_rgbInstr[m_ibModrm] >> 3) & 0x07;
|
|
|
|
ostr << "tr" << ireg;
|
|
break;
|
|
|
|
case oprndtX : // DS:[eSI] for string instruction
|
|
FormatOpSize(ostr, bValue);
|
|
FormatSegOverride(ostr);
|
|
|
|
if (m_fAddress32)
|
|
{
|
|
ostr << "[esi]";
|
|
}
|
|
|
|
else
|
|
{
|
|
ostr << "[si]";
|
|
}
|
|
break;
|
|
|
|
case oprndtY : // ES:[eDI] for string instruction
|
|
FormatOpSize(ostr, bValue);
|
|
|
|
if (m_fAddress32)
|
|
{
|
|
ostr << "es:[edi]";
|
|
}
|
|
|
|
else
|
|
{
|
|
ostr << "es:[di]";
|
|
}
|
|
break;
|
|
|
|
case oprndtZ : // DS:[eBX] for XLAT
|
|
FormatOpSize(ostr, 1);
|
|
FormatSegOverride(ostr);
|
|
|
|
if (m_fAddress32)
|
|
{
|
|
ostr << "[ebx]";
|
|
}
|
|
|
|
else
|
|
{
|
|
ostr << "[bx]";
|
|
}
|
|
break;
|
|
|
|
default :
|
|
AssertSz(false, "Invalid operand type");
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void DISX86::FormatOpSize(ostream& ostr, unsigned cb) const
|
|
{
|
|
const char *szSize;
|
|
|
|
if (cb == 1)
|
|
{
|
|
szSize = "byte";
|
|
}
|
|
|
|
else if (cb == 2)
|
|
{
|
|
szSize = "word";
|
|
}
|
|
|
|
else if (cb == 4)
|
|
{
|
|
szSize = "dword";
|
|
}
|
|
|
|
else if (m_fOperand32)
|
|
{
|
|
szSize = "dword";
|
|
}
|
|
|
|
else
|
|
{
|
|
szSize = "word";
|
|
}
|
|
|
|
ostr << szSize << " ptr ";
|
|
}
|
|
|
|
|
|
void DISX86::FormatRegister(ostream& ostr, int ireg, unsigned cb) const
|
|
{
|
|
const char *szReg;
|
|
|
|
if (cb == 1)
|
|
{
|
|
szReg = rgszReg8[ireg];
|
|
}
|
|
|
|
else if (cb == 2)
|
|
{
|
|
szReg = rgszReg16[ireg];
|
|
}
|
|
|
|
else if (cb == 4)
|
|
{
|
|
szReg = rgszReg32[ireg];
|
|
}
|
|
|
|
else if (m_fOperand32)
|
|
{
|
|
szReg = rgszReg32[ireg];
|
|
}
|
|
|
|
else
|
|
{
|
|
szReg = rgszReg16[ireg];
|
|
}
|
|
|
|
ostr << szReg;
|
|
}
|
|
|
|
|
|
void DISX86::FormatSegOverride(ostream& ostr) const
|
|
{
|
|
const char *szSeg;
|
|
|
|
switch (m_bSegOverride)
|
|
{
|
|
case 0x00 : // None
|
|
return;
|
|
|
|
case 0x26 : // ES:
|
|
szSeg = "es:";
|
|
break;
|
|
|
|
case 0x2E : // CS:
|
|
szSeg = "cs:";
|
|
break;
|
|
|
|
case 0x36 : // SS:
|
|
szSeg = "ss:";
|
|
break;
|
|
|
|
case 0x3E : // DS:
|
|
szSeg = "ds:";
|
|
break;
|
|
|
|
case 0x64 : // FS:
|
|
szSeg = "fs:";
|
|
break;
|
|
|
|
case 0x65 : // GS:
|
|
szSeg = "gs:";
|
|
break;
|
|
|
|
default :
|
|
AssertSz(false, "Invalid segment override byte");
|
|
return;
|
|
}
|
|
|
|
ostr << szSeg;
|
|
}
|
|
|
|
|
|
bool DISX86::FValidOperand(size_t ioperand) const
|
|
{
|
|
if (ioperand == 0)
|
|
{
|
|
// Implicit operand if any
|
|
|
|
return(true);
|
|
}
|
|
|
|
if (ioperand > 3)
|
|
{
|
|
return(false);
|
|
}
|
|
|
|
const OPS *pops = m_popcd->pops;
|
|
|
|
OPRNDT oprndt = (OPRNDT) pops->rgoprnd[ioperand].oprndt;
|
|
|
|
return(oprndt != oprndtNil);
|
|
}
|
|
|
|
|
|
inline size_t DISX86::IbDispModrm16() const
|
|
{
|
|
BYTE b = m_rgbInstr[m_ibModrm];
|
|
|
|
if ((b & 0xC0) == 0xC0)
|
|
{
|
|
// Operand is a register
|
|
|
|
return(0);
|
|
}
|
|
|
|
size_t ibDisp = m_ibModrm + 1;
|
|
|
|
if ((b & 0xC7) == 0x06)
|
|
{
|
|
// Special case of [disp16] operand
|
|
|
|
return(ibDisp);
|
|
}
|
|
|
|
switch (b & 0xC0)
|
|
{
|
|
case 0x40 :
|
|
case 0x80 :
|
|
return(ibDisp);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
inline size_t DISX86::IbDispModrm32() const
|
|
{
|
|
BYTE b = m_rgbInstr[m_ibModrm];
|
|
|
|
if ((b & 0xC0) == 0xC0)
|
|
{
|
|
// Operand is a register
|
|
|
|
return(0);
|
|
}
|
|
|
|
size_t ibDisp = m_ibModrm + 1;
|
|
|
|
if ((b & 0x07) != 0x04)
|
|
{
|
|
// There is no SIB byte
|
|
|
|
if ((b & 0xC7) == 0x05)
|
|
{
|
|
// Special case of [disp32] operand
|
|
|
|
return(ibDisp);
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
// This MODRM is followed by a SIB
|
|
|
|
// If there is an immediate displacement, it follows the SIB byte
|
|
|
|
ibDisp++;
|
|
|
|
BYTE bSib = m_rgbInstr[m_ibModrm + 1];
|
|
|
|
// Special case base == EBP, mod == 0, means _no_ EBP, but disp32.
|
|
// Normally, mod == 0 with SIB means no disp32.
|
|
|
|
if (((bSib & 0x07) == 0x05) && ((b & 0xC0) == 0x00))
|
|
{
|
|
return(ibDisp);
|
|
}
|
|
}
|
|
|
|
switch (b & 0xC0)
|
|
{
|
|
case 0x40 :
|
|
case 0x80 :
|
|
return(ibDisp);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
inline size_t DISX86::IbDispOffset() const
|
|
{
|
|
return(m_ibImmed);
|
|
}
|
|
|
|
|
|
inline const OPCD *PopcdFloatingPoint(BYTE bOpcd, BYTE bModrm)
|
|
{
|
|
switch (bOpcd & 0x07)
|
|
{
|
|
case 0x00 : // D8
|
|
return(rgopcdD8_ + ((bModrm >> 3) & 0x07));
|
|
|
|
case 0x01 : // D9
|
|
return(rgopcdD9_ + (bModrm & 0x3F));
|
|
|
|
case 0x02 : // DA
|
|
if (bModrm == 0xE9)
|
|
{
|
|
return(&opcdDAE9);
|
|
}
|
|
|
|
return(rgopcdDA_ + ((bModrm >> 3) & 0x07));
|
|
|
|
case 0x03 : // DB
|
|
if ((bModrm >= 0xE0) && (bModrm <= 0xF0))
|
|
{
|
|
return(rgopcdDB__ + (bModrm - 0xE0));
|
|
}
|
|
|
|
return(rgopcdDB_ + ((bModrm >> 3) & 0x07));
|
|
|
|
case 0x04 : // DC
|
|
return(rgopcdDC_ + ((bModrm >> 3) & 0x07));
|
|
|
|
case 0x05 : // DD
|
|
return(rgopcdDD_ + ((bModrm >> 3) & 0x07));
|
|
|
|
case 0x06 : // DE
|
|
if ((bModrm & 0x38) != 0x18)
|
|
{
|
|
return(rgopcdDE_ + ((bModrm >> 3) & 0x07));
|
|
}
|
|
|
|
if (bModrm == 0xD9)
|
|
{
|
|
return(&opcdDED9);
|
|
}
|
|
break;
|
|
|
|
case 0x07 : // DF
|
|
if ((bModrm >= 0xE0) && (bModrm <= 0xF0))
|
|
{
|
|
return(rgopcdDF__ + (bModrm - 0xE0));
|
|
}
|
|
break;
|
|
}
|
|
|
|
return(NULL);
|
|
}
|