windows-nt/Source/XPSP1/NT/base/wow64/mscpu/decoder/common.c

615 lines
17 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995-2000 Microsoft Corporation
Module Name:
common.c
Abstract:
Instructions with common (shared) BYTE, WORD, and DWORD flavors.
Author:
29-Jun-1995 BarryBo
Revision History:
--*/
// THIS FILE IS #include'd INTO FILES WHICH DEFINE THE FOLLOWING MACROS:
// GET_REG - function returning pointer to register
// MSB - most signigicant bit
// MOD_RM - decode mod/rm bits
// UTYPE - UNSIGNED type which defines registers (BYTE/USHORT/DWORD)
// STYPE - SIGNED type which defines registers (char/short/long)
// GET_VAL - dereference a pointer of the right type (GET_BYTE/...)
// PUT_VAL - writes a value into memory
// DISPATCHCOMMON - mangles function name by appening 8/16/32
// AREG - GP_AL/GP_AX/GP_EAX, etc.
// BREG - ...
// CREG - ...
// DREG - ...
OPERATION MANGLENAME(Group1Map)[8] = {OPNAME(Add),
OPNAME(Or),
OPNAME(Adc),
OPNAME(Sbb),
OPNAME(And),
OPNAME(Sub),
OPNAME(Xor),
OPNAME(Cmp)};
OPERATION MANGLENAME(Group1LockMap)[8] = {LOCKOPNAME(Add),
LOCKOPNAME(Or),
LOCKOPNAME(Adc),
LOCKOPNAME(Sbb),
LOCKOPNAME(And),
LOCKOPNAME(Sub),
LOCKOPNAME(Xor),
OPNAME(Cmp)};
// A macro to generate _m_r functions
#define DC_M_R(x, y) \
DISPATCHCOMMON(x ## _m_r) \
{ \
int cbInstr = MOD_RM(State, &Instr->Operand1, &Instr->Operand2); \
\
Instr->Operation = y; \
DEREF(Instr->Operand2); \
Instr->Size = cbInstr+1; \
}
// A macro to generate _r_m functions
#define DC_R_M(x, y) \
DISPATCHCOMMON(x ## _r_m) \
{ \
int cbInstr = MOD_RM(State, &Instr->Operand2, &Instr->Operand1); \
\
Instr->Operation = y; \
DEREF(Instr->Operand2); \
Instr->Size = cbInstr+1; \
}
// A macro to generate _a_i functions
#define DC_A_I(x, y) \
DISPATCHCOMMON(x ## _a_i) \
{ \
Instr->Operation = y; \
Instr->Operand1.Type = OPND_REGREF; \
Instr->Operand1.Reg = AREG; \
Instr->Operand2.Type = OPND_IMM; \
Instr->Operand2.Immed = GET_VAL(eipTemp+1); \
Instr->Size = 1+sizeof(UTYPE); \
}
// The monster macro which generates all three
#define DC_ALL(x, y) \
DC_M_R(x,y) \
DC_R_M(x,y) \
DC_A_I(x,y)
// SETSIZE sets the size of a jump instruction
#if MSB==0x80
#define SETSIZE Instr->Size = 1+sizeof(UTYPE); // 1 byte opcode
#else
#define SETSIZE Instr->Size = 2+sizeof(UTYPE); // 2 byte opcode
#endif
#if DBG
#define CLEAR_ADRPREFIX State->AdrPrefix = FALSE;
#else
#define CLEAR_ADRPREFIX
#endif
// This macro generates jump functions
// If the ADR: prefix is set, get the 16-bit loword from the 32-bit
// immediate value following the JMP instruction, and add that value
// to the loword of EIP, and use that value as the new IP register.
#define DISPATCHJUMP(x) \
DISPATCHCOMMON(j ## x) \
{ \
Instr->Operand1.Type = OPND_NOCODEGEN; \
if (State->AdrPrefix) { \
Instr->Operand1.Immed = MAKELONG((short)GET_SHORT(eipTemp+1)+1+sizeof(UTYPE)+(short)LOWORD(eipTemp), HIWORD(eipTemp)); \
CLEAR_ADRPREFIX; \
} else { \
Instr->Operand1.Immed = (STYPE)GET_VAL(eipTemp+1)+1+sizeof(UTYPE)+eipTemp; \
} \
if (Instr->Operand1.Immed > eipTemp) { \
Instr->Operation = OP_CTRL_COND_J ## x ## Fwd; \
} else { \
Instr->Operation = OP_CTRL_COND_J ## x ##; \
} \
SETSIZE \
}
DC_ALL(LOCKadd, LOCKOPNAME(Add))
DC_ALL(LOCKor, LOCKOPNAME(Or))
DC_ALL(LOCKadc, LOCKOPNAME(Adc))
DC_ALL(LOCKsbb, LOCKOPNAME(Sbb))
DC_ALL(LOCKand, LOCKOPNAME(And))
DC_ALL(LOCKsub, LOCKOPNAME(Sub))
DC_ALL(LOCKxor, LOCKOPNAME(Xor))
DC_ALL(add, OPNAME(Add))
DC_ALL(or, OPNAME(Or))
DC_ALL(adc, OPNAME(Adc))
DC_ALL(sbb, OPNAME(Sbb))
DC_ALL(and, OPNAME(And))
DC_ALL(sub, OPNAME(Sub))
DC_ALL(xor, OPNAME(Xor))
DISPATCHCOMMON(cmp_m_r)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, &Instr->Operand2);
Instr->Operation = OPNAME(Cmp);
DEREF(Instr->Operand1); // both params are byval
DEREF(Instr->Operand2);
Instr->Size = cbInstr+1;
}
DISPATCHCOMMON(cmp_r_m)
{
int cbInstr = MOD_RM(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OPNAME(Cmp);
DEREF(Instr->Operand1); // both params are byval
DEREF(Instr->Operand2);
Instr->Size = cbInstr+1;
}
DISPATCHCOMMON(cmp_a_i)
{
Instr->Operation = OPNAME(Cmp);
Instr->Operand1.Type = OPND_REGVALUE; // both params are byval
Instr->Operand1.Reg = AREG;
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_VAL(eipTemp+1);
Instr->Size = 1+sizeof(UTYPE);
}
DISPATCHCOMMON(GROUP_1)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, NULL);
BYTE g = GET_BYTE(eipTemp+1);
// <instruction> modrm, imm
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_VAL(eipTemp+1+cbInstr); // get immB
g = (g >> 3) & 0x07;
Instr->Operation = MANGLENAME(Group1Map)[g];
if (g == 7) {
// Cmp takes both params as byval
DEREF(Instr->Operand1);
}
Instr->Size = cbInstr+sizeof(UTYPE)+1;
}
DISPATCHCOMMON(LOCKGROUP_1)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, NULL);
BYTE g = GET_BYTE(eipTemp+1);
// <instruction> modrm, imm
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_VAL(eipTemp+1+cbInstr); // get immB
g = (g >> 3) & 0x07;
Instr->Operation = MANGLENAME(Group1LockMap)[g];
if (g == 7) {
// Cmp takes both args as byval
DEREF(Instr->Operand1);
}
Instr->Size = cbInstr+sizeof(UTYPE)+1;
}
DISPATCHCOMMON(test_r_m)
{
int cbInstr = MOD_RM(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OPNAME(Test);
DEREF(Instr->Operand1); // both args are byval
DEREF(Instr->Operand2);
Instr->Size = cbInstr+1;
}
DISPATCHCOMMON(xchg_r_m)
{
int cbInstr = MOD_RM(State, &Instr->Operand2, &Instr->Operand1);
// Operand2 is always a register. If operand1 is a memory location,
// we must use the locked version, otherwise use the regular version.
if (Instr->Operand1.Type == OPND_REGREF){
Instr->Operation = OPNAME(Xchg);
} else {
Instr->Operation = LOCKOPNAME(Xchg);
}
Instr->Size = cbInstr+1;
}
DISPATCHCOMMON(xadd_m_r)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, &Instr->Operand2);
Instr->Operation = OPNAME(Xadd);
Instr->Size = cbInstr+2;
}
DISPATCHCOMMON(cmpxchg_m_r)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, &Instr->Operand2);
Instr->Operation = OPNAME(CmpXchg);
Instr->Size = cbInstr+2;
}
DISPATCHCOMMON(LOCKxadd_m_r)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, &Instr->Operand2);
Instr->Operation = LOCKOPNAME(Xadd);
Instr->Size = cbInstr+2;
}
DISPATCHCOMMON(LOCKcmpxchg_m_r)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, &Instr->Operand2);
Instr->Operation = LOCKOPNAME(CmpXchg);
Instr->Size = cbInstr+2;
}
DC_M_R(mov, OPNAME(Mov))
DC_R_M(mov, OPNAME(Mov))
DISPATCHCOMMON(mov_a_m) // mov accum, [full displacement]
{
Instr->Operation = OPNAME(Mov);
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = AREG;
Instr->Operand2.Type = OPND_ADDRREF;
DEREF(Instr->Operand2); // this is a klunky ADDRVAL8/16/32 expansion
if (State->AdrPrefix) {
Instr->Operand2.Immed = GET_SHORT(eipTemp+1);
Instr->Size = 3;
#if DBG
State->AdrPrefix = FALSE;
#endif
} else {
Instr->Operand2.Immed = GET_LONG(eipTemp+1);
Instr->Size = 5;
}
}
DISPATCHCOMMON(mov_m_a) // mov [full displacement], accum
{
Instr->Operation = OPNAME(Mov);
Instr->Operand1.Type = OPND_ADDRREF;
Instr->Operand2.Type = OPND_REGVALUE;
Instr->Operand2.Reg = AREG;
if (State->AdrPrefix) {
Instr->Operand1.Immed = GET_SHORT(eipTemp+1);
Instr->Size = 3;
#if DBG
State->AdrPrefix = FALSE;
#endif
} else {
Instr->Operand1.Immed = GET_LONG(eipTemp+1);
Instr->Size = 5;
}
}
DISPATCHCOMMON(test_a_i)
{
Instr->Operation = OPNAME(Test);
Instr->Operand1.Type = OPND_REGVALUE;
Instr->Operand1.Reg = AREG;
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_VAL(eipTemp+1);
Instr->Size = 1+sizeof(UTYPE);
}
DISPATCHCOMMON(mov_a_i)
{
Instr->Operation = OPNAME(Mov);
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = AREG;
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_VAL(eipTemp+1);
Instr->Size = sizeof(UTYPE)+1;
}
DISPATCHCOMMON(mov_b_i)
{
Instr->Operation = OPNAME(Mov);
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = BREG;
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_VAL(eipTemp+1);
Instr->Size = sizeof(UTYPE)+1;
}
DISPATCHCOMMON(mov_c_i)
{
Instr->Operation = OPNAME(Mov);
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = CREG;
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_VAL(eipTemp+1);
Instr->Size = sizeof(UTYPE)+1;
}
DISPATCHCOMMON(mov_d_i)
{
Instr->Operation = OPNAME(Mov);
Instr->Operand1.Type = OPND_REGREF;
Instr->Operand1.Reg = DREG;
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_VAL(eipTemp+1);
Instr->Size = sizeof(UTYPE)+1;
}
DISPATCHCOMMON(GROUP_2)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, NULL);
BYTE g = GET_BYTE(eipTemp+1);
// <instruction> modrm, imm
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_VAL(eipTemp+1+cbInstr) & 0x1f;
switch ((g >> 3) & 0x07) {
case 0: // rol
if (Instr->Operand2.Immed)
Instr->Operation = OPNAME(Rol);
else
Instr->Operation = OP_Nop;
break;
case 1: // ror
if (Instr->Operand2.Immed)
Instr->Operation = OPNAME(Ror);
else
Instr->Operation = OP_Nop;
break;
case 2: // rcl
Instr->Operation = OPNAME(Rcl);
break;
case 3: // rcr
Instr->Operation = OPNAME(Rcr);
break;
case 4: // shl
Instr->Operation = OPNAME(Shl);
break;
case 5: // shr
Instr->Operation = OPNAME(Shr);
break;
case 7: // sar
Instr->Operation = OPNAME(Sar);
break;
case 6: // <bad>
BAD_INSTR;
break;
}
Instr->Size = 2+cbInstr;
}
DISPATCHCOMMON(mov_m_i)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, NULL);
Instr->Operation = OPNAME(Mov);
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_VAL(eipTemp+cbInstr+1);
Instr->Size = cbInstr+sizeof(UTYPE)+1;
}
DISPATCHCOMMON(GROUP_2_1)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, NULL);
BYTE g = GET_BYTE(eipTemp+1);
// <instruction> modrm, 1
switch ((g >> 3) & 0x07) {
case 0: // rol
Instr->Operation = OPNAME(Rol1);
break;
case 1: // ror
Instr->Operation = OPNAME(Ror1);
break;
case 2: // rcl
Instr->Operation = OPNAME(Rcl1);
break;
case 3: // rcr
Instr->Operation = OPNAME(Rcr1);
break;
case 4: // shl
Instr->Operation = OPNAME(Shl1);
break;
case 5: // shr
Instr->Operation = OPNAME(Shr1);
break;
case 7: // sar
Instr->Operation = OPNAME(Sar1);
break;
case 6: // <bad>
BAD_INSTR;
break;
}
Instr->Size = cbInstr+1;
}
DISPATCHCOMMON(GROUP_2_CL)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, NULL);
BYTE g = GET_BYTE(eipTemp+1);
Instr->Operand2.Type = OPND_REGVALUE;
Instr->Operand2.Reg = GP_CL; //UNDONE: the fragments must mask by 31
// <instruction> modrm, imm
switch ((g >> 3) & 0x07) {
case 0: // rol
Instr->Operation = OPNAME(Rol);
break;
case 1: // ror
Instr->Operation = OPNAME(Ror);
break;
case 2: // rcl
Instr->Operation = OPNAME(Rcl);
break;
case 3: // rcr
Instr->Operation = OPNAME(Rcr);
break;
case 4: // shl
Instr->Operation = OPNAME(Shl);
break;
case 5: // shr
Instr->Operation = OPNAME(Shr);
break;
case 7: // sar
Instr->Operation = OPNAME(Sar);
break;
case 6: // <bad>
BAD_INSTR;
break;
}
Instr->Size = 1+cbInstr;
}
DISPATCHCOMMON(GROUP_3)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, NULL);
BYTE g = GET_BYTE(eipTemp+1);
switch ((g >> 3) & 0x07) {
case 1: // bad
BAD_INSTR;
break;
case 0: // test modrm, imm
Instr->Operation = OPNAME(Test);
DEREF(Instr->Operand1); // both args are byval
Instr->Operand2.Type = OPND_IMM;
Instr->Operand2.Immed = GET_VAL(eipTemp+1+cbInstr);
cbInstr += sizeof(UTYPE); // account for the imm size
break;
case 2: // not, modrm
Instr->Operation = OPNAME(Not);
break;
case 3: // neg, modrm
Instr->Operation = OPNAME(Neg);
break;
case 4: // mul al, modrm
Instr->Operation = OPNAME(Mul);
break;
case 5: // imul al, modrm
Instr->Operation = OPNAME(Muli);
break;
case 6: // div al, modrm
Instr->Operation = OPNAME(Div);
break;
case 7: // idiv al, modrm
Instr->Operation = OPNAME(Idiv);
break;
}
Instr->Size = cbInstr+1;
}
DISPATCHCOMMON(LOCKGROUP_3)
{
int cbInstr = MOD_RM(State, &Instr->Operand1, NULL);
BYTE g = GET_BYTE(eipTemp+1);
switch ((g >> 3) & 0x07) {
case 0:
case 1: // bad
BAD_INSTR;
break;
case 2: // not, modrm
Instr->Operation = LOCKOPNAME(Not);
break;
case 3: // neg, modrm
Instr->Operation = LOCKOPNAME(Neg);
break;
default:
BAD_INSTR;
break;
}
Instr->Size = cbInstr+1;
}
DISPATCHCOMMON(lods)
{
if (Instr->FsOverride) {
if (State->RepPrefix) {
Instr->Operation = OPNAME(FsRepLods);
} else {
Instr->Operation = OPNAME(FsLods);
}
} else {
if (State->RepPrefix) {
Instr->Operation = OPNAME(RepLods);
} else {
Instr->Operation = OPNAME(Lods);
}
}
}
DISPATCHCOMMON(scas)
{
OPERATION ScasMap[6] = {OPNAME(Scas),
OPNAME(RepzScas),
OPNAME(RepnzScas),
OPNAME(FsScas),
OPNAME(FsRepzScas),
OPNAME(FsRepnzScas)
};
Instr->Operation = ScasMap[State->RepPrefix + 3*Instr->FsOverride];
}
DISPATCHCOMMON(stos)
{
if (State->RepPrefix) {
Instr->Operation = OPNAME(RepStos);
} else {
Instr->Operation = OPNAME(Stos);
}
}
DISPATCHCOMMON(movs)
{
if (Instr->FsOverride) {
if (State->RepPrefix) {
Instr->Operation = OPNAME(FsRepMovs);
} else {
Instr->Operation = OPNAME(FsMovs);
}
} else {
if (State->RepPrefix) {
Instr->Operation = OPNAME(RepMovs);
} else {
Instr->Operation = OPNAME(Movs);
}
}
}
DISPATCHCOMMON(cmps)
{
OPERATION CmpsMap[6] = {OPNAME(Cmps),
OPNAME(RepzCmps),
OPNAME(RepnzCmps),
OPNAME(FsCmps),
OPNAME(FsRepzCmps),
OPNAME(FsRepnzCmps)
};
Instr->Operation = CmpsMap[State->RepPrefix + 3*Instr->FsOverride];
}
// Now the jump instructions:
DISPATCHJUMP(o)
DISPATCHJUMP(no)
DISPATCHJUMP(b)
DISPATCHJUMP(ae)
DISPATCHJUMP(e)
DISPATCHJUMP(ne)
DISPATCHJUMP(be)
DISPATCHJUMP(a)
DISPATCHJUMP(s)
DISPATCHJUMP(ns)
DISPATCHJUMP(p)
DISPATCHJUMP(np)
DISPATCHJUMP(l)
DISPATCHJUMP(nl)
DISPATCHJUMP(le)
DISPATCHJUMP(g)