int ASM_Move_32(InstructionInfoStruct *CurInstruction) { //output the bytes for a mov based on required setup switch(CurInstruction->Flags & FLAG_X86MASK) { case (FLAG_INX86REG | FLAG_OUTX86REG): *(u16 *)(DynaRecMemPtr) = (ModRM(0x03, CurInstruction->InReg, CurInstruction->OutReg) << 8) | 0x89; RegAssignment[CurInstruction->OutReg].Modified = 1; return 2; case (FLAG_VALUE | FLAG_OUTX86REG): *(u16 *)(DynaRecMemPtr) = (ModRM(0x03, 0, CurInstruction->OutReg) << 8) | 0xC7; *(u32 *)(DynaRecMemPtr+2) = CurInstruction->InMemPos; RegAssignment[CurInstruction->OutReg].Modified = 1; return 6; case (FLAG_INX86REG | FLAG_MEMORYOUT): *(u16 *)(DynaRecMemPtr) = (ModRM(0x00, CurInstruction->InReg, 0x05) << 8) | 0x89; *(u32 *)(DynaRecMemPtr+2) = (unsigned int)(CurInstruction->OutMemPos); return 6; case (FLAG_OUTX86REG | FLAG_MEMORYIN): *(u16 *)(DynaRecMemPtr) = (ModRM(0x00, CurInstruction->OutReg, 0x05) << 8) | 0x8B; *(u32 *)(DynaRecMemPtr+2) = (unsigned int)(CurInstruction->InMemPos); RegAssignment[CurInstruction->OutReg].Modified = 1; return 6; default: return 0; }; }
int ASM_MoveZX_32(InstructionInfoStruct *CurInstruction) { int Ret; //output the bytes for a mov based on required setup switch(CurInstruction->Flags & FLAG_X86MASK) { case (FLAG_INX86REG | FLAG_OUTX86REG): *(u16 *)(DynaRecMemPtr) = 0xb70f; *(u8 *)(DynaRecMemPtr+2) = ModRM(0x03, CurInstruction->OutReg, CurInstruction->InReg); RegAssignment[CurInstruction->OutReg].Modified = 1; return 3; case (FLAG_VALUE | FLAG_OUTX86REG): //write the value to a register Ret = ASM_Move(CurInstruction); //now movzx the register to itself *(u16 *)(DynaRecMemPtr+Ret) = 0xb70f; *(u8 *)(DynaRecMemPtr+2+Ret) = ModRM(0x03, CurInstruction->OutReg, CurInstruction->OutReg); RegAssignment[CurInstruction->OutReg].Modified = 1; return Ret+3; default: return 0; }; }
////////////////////////////////////////////////////////////////////////////////////////// // Conditionally generates Sib encoding information! // // regfield - register field to be written to the ModRm. This is either a register specifier // or an opcode extension. In either case, the instruction determines the value for us. // void EmitSibMagic(uint regfield, const xIndirectVoid &info) { // 3 bits also on x86_64 (so max is 8) // We might need to mask it on x86_64 pxAssertDev(regfield < 8, "Invalid x86 register identifier."); int displacement_size = (info.Displacement == 0) ? 0 : ((info.IsByteSizeDisp()) ? 1 : 2); pxAssert(!info.Base.IsEmpty() || !info.Index.IsEmpty() || displacement_size == 2); if (!NeedsSibMagic(info)) { // Use ModRm-only encoding, with the rm field holding an index/base register, if // one has been specified. If neither register is specified then use Disp32 form, // which is encoded as "EBP w/o displacement" (which is why EBP must always be // encoded *with* a displacement of 0, if it would otherwise not have one). if (info.Index.IsEmpty()) { EmitSibMagic(regfield, (void *)info.Displacement); return; } else { if (info.Index == ebp && displacement_size == 0) displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]! ModRM(displacement_size, regfield, info.Index.Id); } } else { // In order to encode "just" index*scale (and no base), we have to encode // it as a special [index*scale + displacement] form, which is done by // specifying EBP as the base register and setting the displacement field // to zero. (same as ModRm w/o SIB form above, basically, except the // ModRm_UseDisp flag is specified in the SIB instead of the ModRM field). if (info.Base.IsEmpty()) { ModRM(0, regfield, ModRm_UseSib); SibSB(info.Scale, info.Index.Id, ModRm_UseDisp32); xWrite<s32>(info.Displacement); return; } else { if (info.Base == ebp && displacement_size == 0) displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]! ModRM(displacement_size, regfield, ModRm_UseSib); SibSB(info.Scale, info.Index.Id, info.Base.Id); } } if (displacement_size != 0) { if (displacement_size == 1) xWrite<s8>(info.Displacement); else xWrite<s32>(info.Displacement); } }
int ASM_MoveB_ToRegMemPtr(InstructionInfoStruct *CurInstruction) { switch(CurInstruction->Flags & FLAG_X86MASK) { case (FLAG_INX86REG | FLAG_OUTX86REG): *(u16 *)(DynaRecMemPtr) = (ModRM(0x00, CurInstruction->InReg, CurInstruction->OutReg) << 8) | 0x88; return 2; case (FLAG_VALUE | FLAG_OUTX86REG): *(u16 *)(DynaRecMemPtr) = (ModRM(0x00, 0, CurInstruction->OutReg) << 8) | 0xC6; *(u8 *)(DynaRecMemPtr+2) = CurInstruction->InVal & 0xFF; return 3; default: return 0; }; }
int ASM_Move_ToRegMemPtr(InstructionInfoStruct *CurInstruction) { switch(CurInstruction->Flags & FLAG_X86MASK) { case (FLAG_INX86REG | FLAG_OUTX86REG): *(u8 *)DynaRecMemPtr = 0x66; *(u16 *)(DynaRecMemPtr+1) = (ModRM(0x00, CurInstruction->InReg, CurInstruction->OutReg) << 8) | 0x89; return 3; case (FLAG_VALUE | FLAG_OUTX86REG): *(u8 *)DynaRecMemPtr = 0x66; *(u16 *)(DynaRecMemPtr+1) = (ModRM(0x00, 0, CurInstruction->OutReg) << 8) | 0xC7; *(u16 *)(DynaRecMemPtr+3) = CurInstruction->InVal; return 5; default: return 0; }; }
void EmitSibMagic( uint regfield, const void* address ) { ModRM( 0, regfield, ModRm_UseDisp32 ); // SIB encoding only supports 32bit offsets, even on x86_64 // We must make sure that the displacement is within the 32bit range // Else we will fail out in a spectacular fashion sptr displacement = (sptr)address; pxAssertDev(displacement >= -0x80000000LL && displacement < 0x80000000LL, "SIB target is too far away, needs an indirect register"); xWrite<s32>( (s32)displacement ); }
int ASM_MoveZX_FromRegMemPtr(InstructionInfoStruct *CurInstruction) { switch(CurInstruction->Flags & FLAG_X86MASK) { case (FLAG_INX86REG | FLAG_OUTX86REG): *(u16 *)(DynaRecMemPtr) = 0xb60f; *(u8 *)(DynaRecMemPtr+2) = ModRM(0x00, CurInstruction->OutReg, CurInstruction->InReg); RegAssignment[CurInstruction->OutReg].Modified = 1; return 3; default: return 0; }; }
/* fistp m32 from fpu reg stack */ void FISTP32( u32 from ) { write8( 0xDB ); ModRM( 0, 0x3, DISP32 ); write32( MEMADDR(from, 4) ); }
/* fstp m32 from fpu reg stack */ emitterT void FSTP32( u32 to ) { xWrite8( 0xD9 ); ModRM( 0, 0x3, DISP32 ); xWrite32( MEMADDR(to, 4) ); }
/* fnstcw fpu control word to m16 */ void FNSTCW( u32 to ) { write8( 0xD9 ); ModRM( 0, 0x7, DISP32 ); write32( MEMADDR(to, 4) ); }
/* fld m32 to fpu reg stack */ emitterT void FLD32( u32 from ) { xWrite8( 0xD9 ); ModRM( 0, 0x0, DISP32 ); xWrite32( MEMADDR(from, 4) ); }
/* 0: Opcode 1: Register Target 2: Short/Long 3: mem-reg, reg/reg, mem-reg/mem-reg 4~5: mod rm info */ BYTE option[6]; } INSTRUCTIONS; static const INSTRUCTIONS inst_info[] = { {"ERR", PREFIX::_PF_ERR}, // Priority: Short > EAX > Long {"ADD", PREFIX::_PF_ATH, 0x83, 0, 0, (BYTE)PREFIX::_PF_RM, ModRM(3,(int)ExtensionGroup1::add,0)}, {"ADD", PREFIX::_PF_ATH, 0x05, AX|EXX, 0, (BYTE)PREFIX::_PF_RM}, {"ADD", PREFIX::_PF_ATH, 0x81, 0, 1, (BYTE)PREFIX::_PF_RM, ModRM(3,(int)ExtensionGroup1::add,0)}, {"ADD", PREFIX::_PF_ATH, 0x03, 0, 0, (BYTE)PREFIX::_PF_MR}, {"AND", PREFIX::_PF_LOC, 0x83, 0, 0, (BYTE)PREFIX::_PF_RM, ModRM(3,(int)ExtensionGroup1::and,0)}, {"AND", PREFIX::_PF_LOC, 0x25, AX|EXX, 0, (BYTE)PREFIX::_PF_RM}, {"AND", PREFIX::_PF_LOC, 0x81, 0, 1, (BYTE)PREFIX::_PF_RM, ModRM(3,(int)ExtensionGroup1::and,0)}, {"AND", PREFIX::_PF_LOC, 0x23, 0, 0, (BYTE)PREFIX::_PF_MR}, { "OR", PREFIX::_PF_LOC, 0x83, 0, 0, (BYTE)PREFIX::_PF_RM, ModRM(3,(int)ExtensionGroup1::or,0)}, { "OR", PREFIX::_PF_LOC, 0x0d, AX|EXX, 0, (BYTE)PREFIX::_PF_RM}, { "OR", PREFIX::_PF_LOC, 0x81, 0, 1, (BYTE)PREFIX::_PF_RM, ModRM(3,(int)ExtensionGroup1::or,0)}, { "OR", PREFIX::_PF_LOC, 0x0b, 0, 0, (BYTE)PREFIX::_PF_MR}, {"SUB", PREFIX::_PF_ATH, 0x83, 0, 0, 0, ModRM(3,(int)ExtensionGroup1::sub,0)},
/* fcomp m32 to fpu reg stack */ void FCOMP32( u32 from ) { write8( 0xD8 ); ModRM( 0, 0x3, DISP32 ); write32( MEMADDR(from, 4) ); }
/* fdiv m32 to fpu reg stack */ void FDIV32( u32 from ) { write8( 0xD8 ); ModRM( 0, 0x6, DISP32 ); write32( MEMADDR(from, 4) ); }
/* fmul m32 to fpu reg stack */ void FMUL32( u32 from ) { write8( 0xD8 ); ModRM( 0, 0x1, DISP32 ); write32( MEMADDR(from, 4) ); }
/* fsub m32 to fpu reg stack */ void FSUB32( u32 from ) { write8( 0xD8 ); ModRM( 0, 0x4, DISP32 ); write32( MEMADDR(from, 4) ); }
/* fmul m32 to fpu reg stack */ emitterT void FMUL32( u32 from ) { xWrite8( 0xD8 ); ModRM( 0, 0x1, DISP32 ); xWrite32( MEMADDR(from, 4) ); }
// ------------------------------------------------------------------------ // Internal implementation of EmitSibMagic which has been custom tailored // to optimize special forms of the Lea instructions accordingly, such // as when a LEA can be replaced with a "MOV reg,imm" or "MOV reg,reg". // // preserve_flags - set to ture to disable use of SHL on [Index*Base] forms // of LEA, which alters flags states. // static void EmitLeaMagic( const xRegisterInt& to, const xIndirectVoid& src, bool preserve_flags ) { int displacement_size = (src.Displacement == 0) ? 0 : ( ( src.IsByteSizeDisp() ) ? 1 : 2 ); // See EmitSibMagic for commenting on SIB encoding. if( !NeedsSibMagic( src ) ) { // LEA Land: means we have either 1-register encoding or just an offset. // offset is encodable as an immediate MOV, and a register is encodable // as a register MOV. if( src.Index.IsEmpty() ) { xMOV( to, src.Displacement ); return; } else if( displacement_size == 0 ) { _xMovRtoR( to, src.Index ); return; } else { if( !preserve_flags ) { // encode as MOV and ADD combo. Make sure to use the immediate on the // ADD since it can encode as an 8-bit sign-extended value. _xMovRtoR( to, src.Index ); xADD( to, src.Displacement ); return; } else { // note: no need to do ebp+0 check since we encode all 0 displacements as // register assignments above (via MOV) xWrite8( 0x8d ); ModRM( displacement_size, to.Id, src.Index.Id ); } } } else { if( src.Base.IsEmpty() ) { if( !preserve_flags && (displacement_size == 0) ) { // Encode [Index*Scale] as a combination of Mov and Shl. // This is more efficient because of the bloated LEA format which requires // a 32 bit displacement, and the compact nature of the alternative. // // (this does not apply to older model P4s with the broken barrel shifter, // but we currently aren't optimizing for that target anyway). _xMovRtoR( to, src.Index ); xSHL( to, src.Scale ); return; } xWrite8( 0x8d ); ModRM( 0, to.Id, ModRm_UseSib ); SibSB( src.Scale, src.Index.Id, ModRm_UseDisp32 ); xWrite32( src.Displacement ); return; } else { if( src.Scale == 0 ) { if( !preserve_flags ) { if( src.Index == esp ) { // ESP is not encodable as an index (ix86 ignores it), thus: _xMovRtoR( to, src.Base ); // will do the trick! if( src.Displacement ) xADD( to, src.Displacement ); return; } else if( src.Displacement == 0 ) { _xMovRtoR( to, src.Base ); _g1_EmitOp( G1Type_ADD, to, src.Index ); return; } } else if( (src.Index == esp) && (src.Displacement == 0) ) { // special case handling of ESP as Index, which is replaceable with // a single MOV even when preserve_flags is set! :D _xMovRtoR( to, src.Base ); return; } } if( src.Base == ebp && displacement_size == 0 ) displacement_size = 1; // forces [ebp] to be encoded as [ebp+0]! xWrite8( 0x8d ); ModRM( displacement_size, to.Id, ModRm_UseSib ); SibSB( src.Scale, src.Index.Id, src.Base.Id ); } } if( displacement_size != 0 ) { if( displacement_size == 1 ) xWrite<s8>( src.Displacement ); else xWrite<s32>( src.Displacement ); } }
/* fstp m32 from fpu reg stack */ void FSTP32( u32 to ) { write8( 0xD9 ); ModRM( 0, 0x3, DISP32 ); write32( MEMADDR(to, 4) ); }
#include "x86.hpp" std::vector<x86_insn_mnemonic> x86_format_table = { {"mov", { {0x88, DFDX_OPC_MOV, true,ModRM(), 0}, {0x89, DFDX_OPC_MOV, false, ModRM(), 0}, {0x8a, DFDX_OPC_MOV, true, ModRM(), 1}, {0x8b, DFDX_OPC_MOV, false, ModRM(), 1}, }, }, {"add", { {0x04, DFDX_OPC_ADD, false, Imm8(), 1}, {0x05, DFDX_OPC_ADD, false, Imm(), 1}, {0x80, DFDX_OPC_ADD, true, ModRM_Imm(), 0}, {0x81, DFDX_OPC_ADD, false, ModRM_Imm(), 0}, {0x83, DFDX_OPC_ADD, false, ModRM_Op_Imm8(0), 0}, {0x00, DFDX_OPC_ADD, true, ModRM(), 0}, {0x01, DFDX_OPC_ADD, false, ModRM(), 0}, {0x02, DFDX_OPC_ADD, true, ModRM(), 1}, {0x03, DFDX_OPC_ADD, false, ModRM(), 1}, }, }, {"sub", { {0x2c, DFDX_OPC_SUB, false, Imm8(), 1}, {0x2d, DFDX_OPC_SUB, false, Imm(), 1}, {0x80, DFDX_OPC_SUB, true, ModRM_Op_Imm8(5), 0}, {0x81, DFDX_OPC_SUB, false, ModRM_Op_Imm(5), 0}, {0x83, DFDX_OPC_SUB, false, ModRM_Op_Imm8(5), 0}, {0x28, DFDX_OPC_SUB, true, ModRM(), 0}, {0x29, DFDX_OPC_SUB, false, ModRM(), 0}, {0x2a, DFDX_OPC_SUB, true, ModRM(), 1}, {0x2b, DFDX_OPC_SUB, false, ModRM(), 1},
/* fldcw fpu control word from m16 */ void FLDCW( u32 from ) { write8( 0xD9 ); ModRM( 0, 0x5, DISP32 ); write32( MEMADDR(from, 4) ); }