|
|
/*++
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)
|