/* * ix86 core v0.6.2 * Authors: linuzappz * alexey silinov * goldfinger * zerofrog(@gmail.com) */ #ifdef __x86_64__ // stop compiling if NORECBUILD build (only for Visual Studio) #if !(defined(_MSC_VER) && defined(PCSX2_NORECBUILD)) #include #include #include #include "ix86-64.h" #ifdef __x86_64__ #ifdef _MSC_VER // visual studio calling convention x86IntRegType g_x86savedregs[] = { RBX, RBP, RSI, RDI, R12, R13, R14, R15 }; x86IntRegType g_x86tempregs[] = { R8, R9, R10, R11, RDX, RCX }; // arranged in savedreg -> tempreg order x86IntRegType g_x86allregs[14] = { RBX, RBP, RSI, RDI, R12, R13, R14, R15, R8, R9, R10, R11, RDX, RCX }; #else // standard calling convention // registers saved by called functions (no need to flush them across calls) x86IntRegType g_x86savedregs[] = { RBX, RBP, R12, R13, R14, R15 }; // temp registers that need to be saved across calls x86IntRegType g_x86tempregs[] = { RCX, RDX, R8, R9, R10, R11, RSI, RDI }; // arranged in savedreg -> tempreg order x86IntRegType g_x86allregs[14] = { RBX, RBP, R12, R13, R14, R15, RCX, RDX, R8, R9, R10, R11, RSI, RDI }; #endif x86IntRegType g_x868bitregs[11] = { RBX, R12, R13, R14, R15, RCX, RDX, R8, R9, R10, R11 }; x86IntRegType g_x86non8bitregs[3] = { RBP, RSI, RDI }; #endif // __x86_64__ s8 *x86Ptr; u8 *j8Ptr[32]; u32 *j32Ptr[32]; void WriteRmOffset(x86IntRegType to, int offset) { if( (to&7) == ESP ) { if( offset == 0 ) { ModRM( 0, 0, 4 ); ModRM( 0, ESP, 4 ); } else if( offset < 128 && offset >= -128 ) { ModRM( 1, 0, 4 ); ModRM( 0, ESP, 4 ); write8(offset); } else { ModRM( 2, 0, 4 ); ModRM( 0, ESP, 4 ); write32(offset); } } else { if( offset == 0 ) { ModRM( 0, 0, to ); } else if( offset < 128 && offset >= -128 ) { ModRM( 1, 0, to ); write8(offset); } else { ModRM( 2, 0, to ); write32(offset); } } } void WriteRmOffsetFrom(x86IntRegType to, x86IntRegType from, int offset) { if ((from&7) == ESP) { if( offset == 0 ) { ModRM( 0, to, 0x4 ); SibSB( 0, 0x4, 0x4 ); } else if( offset < 128 && offset >= -128 ) { ModRM( 1, to, 0x4 ); SibSB( 0, 0x4, 0x4 ); write8(offset); } else { ModRM( 2, to, 0x4 ); SibSB( 0, 0x4, 0x4 ); write32(offset); } } else { if( offset == 0 ) { ModRM( 0, to, from ); } else if( offset < 128 && offset >= -128 ) { ModRM( 1, to, from ); write8(offset); } else { ModRM( 2, to, from ); write32(offset); } } } // This function is just for rec debugging purposes void CheckX86Ptr( void ) { } void writeVAROP(unsigned opl, u64 op) { while (opl--) { write8(op & 0xFF); op >>= 8; } } #define writeVARROP(REX, opl, op) ({ \ if (opl > 1 && ((op & 0xFF) == 0x66 || (op & 0xFF) == 0xF3 || (op & 0xFF) == 0xF2)) { \ write8(op & 0xFF); \ opl --; \ op >>= 8; \ } \ REX; \ writeVAROP(opl, op); \ }) void MEMADDR_OP(bool w, unsigned opl, u64 op, bool isreg, int reg, uptr p, sptr off) { #ifdef __x86_64__ sptr pr = MEMADDR_(p, 5 + opl + (w || reg >= 8) + off); if (SPTR32(pr)) { writeVARROP(RexR(w, reg), opl, op); ModRM(0, reg, DISP32); write32(pr); } else if (UPTR32(p)) { writeVARROP(RexR(w, reg), opl, op); ModRM(0, reg, SIB); SibSB(0, SIB, DISP32); write32(p); } else { assert(!isreg || reg != X86_TEMP); MOV64ItoR(X86_TEMP, p); writeVARROP(RexRB(w, reg, X86_TEMP), opl, op); ModRM(0, reg, X86_TEMP); } #else writeVARROP(RexR(w, reg), opl, op); ModRM(0, reg, DISP32); write32(p); #endif } void SET8R( int cc, int to ) { RexB(0, to); write8( 0x0F ); write8( cc ); write8( 0xC0 | ( to ) ); } u8* J8Rel( int cc, int to ) { write8( cc ); write8( to ); return x86Ptr - 1; } u16* J16Rel( int cc, u32 to ) { write16( 0x0F66 ); write8( cc ); write16( to ); return (u16*)( x86Ptr - 2 ); } u32* J32Rel( int cc, u32 to ) { write8( 0x0F ); write8( cc ); write32( to ); return (u32*)( x86Ptr - 4 ); } void CMOV32RtoR( int cc, int to, int from ) { RexRB(0,to, from); write8( 0x0F ); write8( cc ); ModRM( 3, to, from ); } void CMOV32MtoR( int cc, x86IntRegType to, uptr from ) { MEMADDR_OP(0, VAROP2(0x0F, cc), true, to, from, 0); } //////////////////////////////////////////////////// void x86SetPtr( char* ptr ) { x86Ptr = ptr; } //////////////////////////////////////////////////// void x86Shutdown( void ) { } //////////////////////////////////////////////////// void x86SetJ8( u8* j8 ) { u32 jump = ( x86Ptr - (s8*)j8 ) - 1; if ( jump > 0x7f ) { SysPrintf( "j8 greater than 0x7f!!\n" ); assert(0); } *j8 = (u8)jump; } void x86SetJ8A( u8* j8 ) { u32 jump = ( x86Ptr - (s8*)j8 ) - 1; if ( jump > 0x7f ) { SysPrintf( "j8 greater than 0x7f!!\n" ); //assert(0); } if( ((uptr)x86Ptr&0xf) > 4 ) { uptr newjump = jump + 16-((uptr)x86Ptr&0xf); if( newjump <= 0x7f ) { jump = newjump; while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; } } *j8 = (u8)jump; } void x86SetJ16( u16 *j16 ) { // doesn't work u32 jump = ( x86Ptr - (s8*)j16 ) - 2; if ( jump > 0x7fff ) { SysPrintf( "j16 greater than 0x7fff!!\n" ); //assert(0); } *j16 = (u16)jump; } void x86SetJ16A( u16 *j16 ) { if( ((uptr)x86Ptr&0xf) > 4 ) { while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; } x86SetJ16(j16); } //////////////////////////////////////////////////// void x86SetJ32( u32* j32 ) { *j32 = ( x86Ptr - (s8*)j32 ) - 4; } void x86SetJ32A( u32* j32 ) { while((uptr)x86Ptr&0xf) *x86Ptr++ = 0x90; x86SetJ32(j32); } //////////////////////////////////////////////////// void x86Align( int bytes ) { // fordward align x86Ptr = (s8*)( ( (uptr)x86Ptr + bytes - 1) & ~( bytes - 1 ) ); } /********************/ /* IX86 intructions */ /********************/ void STC( void ) { write8( 0xF9 ); } void CLC( void ) { write8( 0xF8 ); } //////////////////////////////////// // mov instructions / //////////////////////////////////// /* mov r64 to r64 */ void MOV64RtoR( x86IntRegType to, x86IntRegType from ) { RexRB(1, from, to); write8( 0x89 ); ModRM( 3, from, to ); } /* mov r64 to m64 */ void MOV64RtoM( uptr to, x86IntRegType from ) { if (from == RAX) { RexR(1, 0); write8(0xA3); write64(to); } else { MEMADDR_OP(1, VAROP1(0x89), true, from, to, 0); } } /* mov m64 to r64 */ void MOV64MtoR( x86IntRegType to, uptr from ) { if (to == RAX) { RexR(1, 0); write8(0xA1); write64(from); } else { MEMADDR_OP(1, VAROP1(0x8B), true, to, from, 0); } } /* mov imm32 to m64 */ void MOV64I32toM(uptr to, u32 from ) { MEMADDR_OP(1, VAROP1(0xC7), false, 0, to, 4); write32(from); } // mov imm64 to r64 void MOV64ItoR( x86IntRegType to, u64 from) { RexB(1, to); write8( 0xB8 | (to & 0x7) ); write64( from ); } /* mov imm32 to r64 */ void MOV64I32toR( x86IntRegType to, s32 from ) { RexB(1, to); write8( 0xC7 ); ModRM( 0, 0, to ); write32( from ); } // mov imm64 to [r64+off] void MOV64ItoRmOffset( x86IntRegType to, u32 from, int offset) { RexB(1,to); write8( 0xC7 ); WriteRmOffset(to, offset); write32(from); } // mov [r64+offset] to r64 void MOV64RmOffsettoR( x86IntRegType to, x86IntRegType from, int offset ) { RexRB(1, to, from); write8( 0x8B ); WriteRmOffsetFrom(to, from, offset); } /* mov [r64][r64*scale] to r64 */ void MOV64RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { RexRXB(1, to, from2, from); write8( 0x8B ); ModRM( 0, to, 0x4 ); SibSB(scale, from2, from ); } /* mov r64 to [r64+offset] */ void MOV64RtoRmOffset( x86IntRegType to, x86IntRegType from, int offset ) { RexRB(1,from,to); write8( 0x89 ); WriteRmOffsetFrom(from, to, offset); } /* mov r64 to [r64][r64*scale] */ void MOV64RtoRmS( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { RexRXB(1, to, from2, from); write8( 0x89 ); ModRM( 0, to, 0x4 ); SibSB(scale, from2, from ); } /* mov r32 to r32 */ void MOV32RtoR( x86IntRegType to, x86IntRegType from ) { RexRB(0, from, to); write8( 0x89 ); ModRM( 3, from, to ); } /* mov r32 to m32 */ void MOV32RtoM( uptr to, x86IntRegType from ) { if (from == EAX) { write8(0xA3); write64(to); } else { MEMADDR_OP(0, VAROP1(0x89), true, from, to, 0); } } /* mov m32 to r32 */ void MOV32MtoR( x86IntRegType to, uptr from ) { if (to == RAX) { write8(0xA1); write64(from); } else { MEMADDR_OP(0, VAROP1(0x8B), true, to, from, 0); } } /* mov [r32] to r32 */ void MOV32RmtoR( x86IntRegType to, x86IntRegType from ) { RexRB(0, to, from); write8(0x8B); WriteRmOffsetFrom(to, from, 0); } void MOV32RmtoROffset( x86IntRegType to, x86IntRegType from, int offset ) { RexRB(0, to, from); write8( 0x8B ); WriteRmOffsetFrom(to, from, offset); } /* mov [r32+r32*scale] to r32 */ void MOV32RmStoR( x86IntRegType to, x86IntRegType from, x86IntRegType from2, int scale) { RexRXB(0,to,from2,from); write8( 0x8B ); ModRM( 0, to, 0x4 ); SibSB(scale, from2, from ); } // mov r32 to [r32< 0x7f ) { assert( to <= 0xffffffff ); return (u8*)JMP32( to ); } else { return (u8*)JMP8( to ); } } /* jmp rel8 */ u8* JMP8( u8 to ) { write8( 0xEB ); write8( to ); return x86Ptr - 1; } /* jmp rel32 */ u32* JMP32( uptr to ) { assert(SPTR32((sptr)to)); write8( 0xE9 ); write32( (sptr)to ); return (u32*)(x86Ptr - 4 ); } /* jmp r32/r64 */ void JMPR( x86IntRegType to ) { RexB(0, to); write8( 0xFF ); ModRM( 3, 4, to ); } // jmp m32 void JMP32M( uptr to ) { /* FIXME */ MEMADDR_OP(0, VAROP1(0xFF), false, 4, to, 0); } /* jp rel8 */ u8* JP8( u8 to ) { return J8Rel( 0x7A, to ); } /* jnp rel8 */ u8* JNP8( u8 to ) { return J8Rel( 0x7B, to ); } /* je rel8 */ u8* JE8( u8 to ) { return J8Rel( 0x74, to ); } /* jz rel8 */ u8* JZ8( u8 to ) { return J8Rel( 0x74, to ); } /* js rel8 */ u8* JS8( u8 to ) { return J8Rel( 0x78, to ); } /* jns rel8 */ u8* JNS8( u8 to ) { return J8Rel( 0x79, to ); } /* jg rel8 */ u8* JG8( u8 to ) { return J8Rel( 0x7F, to ); } /* jge rel8 */ u8* JGE8( u8 to ) { return J8Rel( 0x7D, to ); } /* jl rel8 */ u8* JL8( u8 to ) { return J8Rel( 0x7C, to ); } /* ja rel8 */ u8* JA8( u8 to ) { return J8Rel( 0x77, to ); } u8* JAE8( u8 to ) { return J8Rel( 0x73, to ); } /* jb rel8 */ u8* JB8( u8 to ) { return J8Rel( 0x72, to ); } /* jbe rel8 */ u8* JBE8( u8 to ) { return J8Rel( 0x76, to ); } /* jle rel8 */ u8* JLE8( u8 to ) { return J8Rel( 0x7E, to ); } /* jne rel8 */ u8* JNE8( u8 to ) { return J8Rel( 0x75, to ); } /* jnz rel8 */ u8* JNZ8( u8 to ) { return J8Rel( 0x75, to ); } /* jng rel8 */ u8* JNG8( u8 to ) { return J8Rel( 0x7E, to ); } /* jnge rel8 */ u8* JNGE8( u8 to ) { return J8Rel( 0x7C, to ); } /* jnl rel8 */ u8* JNL8( u8 to ) { return J8Rel( 0x7D, to ); } /* jnle rel8 */ u8* JNLE8( u8 to ) { return J8Rel( 0x7F, to ); } /* jo rel8 */ u8* JO8( u8 to ) { return J8Rel( 0x70, to ); } /* jno rel8 */ u8* JNO8( u8 to ) { return J8Rel( 0x71, to ); } // jb rel8 u16* JB16( u16 to ) { return J16Rel( 0x82, to ); } // jb rel32 u32* JB32( u32 to ) { return J32Rel( 0x82, to ); } /* je rel32 */ u32* JE32( u32 to ) { return J32Rel( 0x84, to ); } /* jz rel32 */ u32* JZ32( u32 to ) { return J32Rel( 0x84, to ); } /* jg rel32 */ u32* JG32( u32 to ) { return J32Rel( 0x8F, to ); } /* jge rel32 */ u32* JGE32( u32 to ) { return J32Rel( 0x8D, to ); } /* jl rel32 */ u32* JL32( u32 to ) { return J32Rel( 0x8C, to ); } /* jle rel32 */ u32* JLE32( u32 to ) { return J32Rel( 0x8E, to ); } /* jae rel32 */ u32* JAE32( u32 to ) { return J32Rel( 0x83, to ); } /* jne rel32 */ u32* JNE32( u32 to ) { return J32Rel( 0x85, to ); } /* jnz rel32 */ u32* JNZ32( u32 to ) { return J32Rel( 0x85, to ); } /* jng rel32 */ u32* JNG32( u32 to ) { return J32Rel( 0x8E, to ); } /* jnge rel32 */ u32* JNGE32( u32 to ) { return J32Rel( 0x8C, to ); } /* jnl rel32 */ u32* JNL32( u32 to ) { return J32Rel( 0x8D, to ); } /* jnle rel32 */ u32* JNLE32( u32 to ) { return J32Rel( 0x8F, to ); } /* jo rel32 */ u32* JO32( u32 to ) { return J32Rel( 0x80, to ); } /* jno rel32 */ u32* JNO32( u32 to ) { return J32Rel( 0x81, to ); } // js rel32 u32* JS32( u32 to ) { return J32Rel( 0x88, to ); } /* call func */ void CALLFunc( uptr func ) { sptr p = MEMADDR_(func, 5); if (SPTR32(p)) { CALL32(p); } else { MOV64ItoR(X86_TEMP, func); CALL64R(X86_TEMP); } } /* call rel32 */ void CALL32( s32 to ) { write8( 0xE8 ); write32( to ); } /* call r32 */ void CALL32R( x86IntRegType to ) { RexB(0, to); write8( 0xFF ); ModRM( 3, 2, to ); } /* call r64 */ void CALL64R( x86IntRegType to ) { RexB(0, to); write8( 0xFF ); ModRM( 3, 2, to ); } //////////////////////////////////// // misc instructions / //////////////////////////////////// /* cmp imm32 to r64 */ void CMP64I32toR( x86IntRegType to, u32 from ) { RexB(1, to); if ( to == EAX ) { write8( 0x3D ); } else { write8( 0x81 ); ModRM( 3, 7, to ); } write32( from ); } /* cmp m64 to r64 */ void CMP64MtoR( x86IntRegType to, uptr from ) { MEMADDR_OP(1, VAROP1(0x3B), true, 2, from, 0); } // cmp r64 to r64 void CMP64RtoR( x86IntRegType to, x86IntRegType from ) { RexRB(1,from,to); write8( 0x39 ); ModRM( 3, from, to ); } /* cmp imm32 to r32 */ void CMP32ItoR( x86IntRegType to, u32 from ) { RexB(0,to); if ( to == EAX ) { write8( 0x3D ); } else { write8( 0x81 ); ModRM( 3, 7, to ); } write32( from ); } /* cmp imm32 to m32 */ void CMP32ItoM( uptr to, u32 from ) { MEMADDR_OP(0, VAROP1(0x81), false, 7, to, 4); write32(from); } /* cmp r32 to r32 */ void CMP32RtoR( x86IntRegType to, x86IntRegType from ) { RexRB(0,from,to); write8( 0x39 ); ModRM( 3, from, to ); } /* cmp m32 to r32 */ void CMP32MtoR( x86IntRegType to, uptr from ) { MEMADDR_OP(0, VAROP1(0x3B), true, to, from, 0); } // cmp imm8 to [r32] void CMP32I8toRm( x86IntRegType to, u8 from) { RexB(0,to); write8( 0x83 ); ModRM( 0, 7, to ); write8(from); } // cmp imm32 to [r32+off] void CMP32I8toRmOffset8( x86IntRegType to, u8 from, u8 off) { RexB(0,to); write8( 0x83 ); ModRM( 1, 7, to ); write8(off); write8(from); } // cmp imm8 to [r32] void CMP32I8toM( uptr to, u8 from) { MEMADDR_OP(0, VAROP1(0x83), false, 7, to, 1); write8( from ); } /* cmp imm16 to r16 */ void CMP16ItoR( x86IntRegType to, u16 from ) { write8( 0x66 ); RexB(0,to); if ( to == EAX ) { write8( 0x3D ); } else { write8( 0x81 ); ModRM( 3, 7, to ); } write16( from ); } /* cmp imm16 to m16 */ void CMP16ItoM( uptr to, u16 from ) { MEMADDR_OP(0, VAROP2(0x66, 0x81), false, 7, to, 2); write16( from ); } /* cmp r16 to r16 */ void CMP16RtoR( x86IntRegType to, x86IntRegType from ) { write8( 0x66 ); RexRB(0,from,to); write8( 0x39 ); ModRM( 3, from, to ); } /* cmp m16 to r16 */ void CMP16MtoR( x86IntRegType to, uptr from ) { MEMADDR_OP(0, VAROP2(0x66, 0x3B), true, to, from, 0); } // cmp imm8 to r8 void CMP8ItoR( x86IntRegType to, u8 from ) { RexB(0,to); if ( to == EAX ) { write8( 0x3C ); } else { write8( 0x80 ); ModRM( 3, 7, to ); } write8( from ); } // cmp m8 to r8 void CMP8MtoR( x86IntRegType to, uptr from ) { MEMADDR_OP(0, VAROP1(0x3A), true, to, from, 0); } /* test r64 to r64 */ void TEST64RtoR( x86IntRegType to, x86IntRegType from ) { RexRB(1, from, to); write8( 0x85 ); ModRM( 3, from, to ); } /* test imm32 to r32 */ void TEST32ItoR( x86IntRegType to, u32 from ) { RexB(0,to); if ( to == EAX ) { write8( 0xA9 ); } else { write8( 0xF7 ); ModRM( 3, 0, to ); } write32( from ); } void TEST32ItoM( uptr to, u32 from ) { MEMADDR_OP(0, VAROP1(0xF7), false, 0, to, 4); write32( from ); } /* test r32 to r32 */ void TEST32RtoR( x86IntRegType to, x86IntRegType from ) { RexRB(0,from,to); write8( 0x85 ); ModRM( 3, from, to ); } // test imm32 to [r32] void TEST32ItoRm( x86IntRegType to, u32 from ) { RexB(0,to); write8( 0xF7 ); ModRM( 0, 0, to ); write32(from); } // test imm16 to r16 void TEST16ItoR( x86IntRegType to, u16 from ) { write8(0x66); RexB(0,to); if ( to == EAX ) { write8( 0xA9 ); } else { write8( 0xF7 ); ModRM( 3, 0, to ); } write16( from ); } // test r16 to r16 void TEST16RtoR( x86IntRegType to, x86IntRegType from ) { write8(0x66); RexRB(0,from,to); write16( 0x85 ); ModRM( 3, from, to ); } // test imm8 to r8 void TEST8ItoR( x86IntRegType to, u8 from ) { RexB(0,to); if ( to == EAX ) { write8( 0xA8 ); } else { write8( 0xF6 ); ModRM( 3, 0, to ); } write8( from ); } // test imm8 to r8 void TEST8ItoM( uptr to, u8 from ) { MEMADDR_OP(0, VAROP1(0xF6), false, 0, to, 1); write8( from ); } /* sets r8 */ void SETS8R( x86IntRegType to ) { SET8R( 0x98, to ); } /* setl r8 */ void SETL8R( x86IntRegType to ) { SET8R( 0x9C, to ); } // setge r8 void SETGE8R( x86IntRegType to ) { SET8R(0x9d, to); } // setg r8 void SETG8R( x86IntRegType to ) { SET8R(0x9f, to); } // seta r8 void SETA8R( x86IntRegType to ) { SET8R(0x97, to); } // setae r8 void SETAE8R( x86IntRegType to ) { SET8R(0x99, to); } /* setb r8 */ void SETB8R( x86IntRegType to ) { SET8R( 0x92, to ); } /* setb r8 */ void SETNZ8R( x86IntRegType to ) { SET8R( 0x95, to ); } // setz r8 void SETZ8R( x86IntRegType to ) { SET8R(0x94, to); } // sete r8 void SETE8R( x86IntRegType to ) { SET8R(0x94, to); } /* push imm32 */ void PUSH32I( u32 from ) { //X86_64ASSERT(); //becomes sign extended in x86_64 write8( 0x68 ); write32( from ); } #ifdef __x86_64__ /* push r64 */ void PUSH64R( x86IntRegType from ) { RexB(0,from); //write8( 0x51 | from ); write8( 0x50 | from ); } /* push m64 */ void PUSH64M( uptr from ) { MEMADDR_OP(0, VAROP1(0xFF), false, 6, from, 0); } /* pop r64 */ void POP64R( x86IntRegType from ) { RexB(0,from); //write8( 0x59 | from ); write8( 0x58 | from ); } void PUSHR(x86IntRegType from) { PUSH64R(from); } void POPR(x86IntRegType from) { POP64R(from); } #else /* push r32 */ void PUSH32R( x86IntRegType from ) { write8( 0x50 | from ); } /* push m32 */ void PUSH32M( uptr from ) { MEMADDR_OP(0, VAROP1(0xFF), false, 6, from, 0); } /* pop r32 */ void POP32R( x86IntRegType from ) { write8( 0x58 | from ); } /* pushad */ void PUSHA32( void ) { write8( 0x60 ); } /* popad */ void POPA32( void ) { write8( 0x61 ); } void PUSHR(x86IntRegType from) { PUSH32R(from); } void POPR(x86IntRegType from) { POP32R(from); } #endif /* pushfd */ void PUSHFD( void ) { write8( 0x9C ); } /* popfd */ void POPFD( void ) { write8( 0x9D ); } void RET( void ) { write8( 0xC3 ); } void RET2( void ) { write16( 0xc3f3 ); } void CBW( void ) { write16( 0x9866 ); } void CWD( void ) { write8( 0x98 ); } void CDQ( void ) { write8( 0x99 ); } void CWDE() { write8(0x98); } #ifdef __x86_64__ void CDQE( void ) { RexR(1,0); write8( 0x98 ); } #endif void LAHF() { write8(0x9f); } void SAHF() { write8(0x9e); } void BT32ItoR( x86IntRegType to, x86IntRegType from ) { write16( 0xBA0F ); write8( 0xE0 | to ); write8( from ); } void BSRRtoR(x86IntRegType to, x86IntRegType from) { write16( 0xBD0F ); ModRM( 3, from, to ); } void BSWAP32R( x86IntRegType to ) { write8( 0x0F ); write8( 0xC8 + to ); } // to = from + offset void LEA16RtoR(x86IntRegType to, x86IntRegType from, u16 offset) { write8(0x66); LEA32RtoR(to, from, offset); } void LEA32RtoR(x86IntRegType to, x86IntRegType from, u32 offset) { RexRB(0,to,from); write8(0x8d); if( (from&7) == ESP ) { if( offset == 0 ) { ModRM(1, to, from); write8(0x24); } else if( offset < 128 ) { ModRM(1, to, from); write8(0x24); write8(offset); } else { ModRM(2, to, from); write8(0x24); write32(offset); } } else { if( offset == 0 && from != EBP && from!=ESP ) { ModRM(0, to, from); } else if( offset < 128 ) { ModRM(1, to, from); write8(offset); } else { ModRM(2, to, from); write32(offset); } } } // to = from0 + from1 void LEA16RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1) { write8(0x66); LEA32RRtoR(to, from0, from1); } void LEA32RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1) { RexRXB(0, to, from0, from1); write8(0x8d); if( (from1&7) == EBP ) { ModRM(1, to, 4); ModRM(0, from0, from1); write8(0); } else { ModRM(0, to, 4); ModRM(0, from0, from1); } } // to = from << scale (max is 3) void LEA16RStoR(x86IntRegType to, x86IntRegType from, u32 scale) { write8(0x66); LEA32RStoR(to, from, scale); } void LEA32RStoR(x86IntRegType to, x86IntRegType from, u32 scale) { if( to == from ) { SHL32ItoR(to, scale); return; } if( from != ESP ) { RexRXB(0,to,from,0); write8(0x8d); ModRM(0, to, 4); ModRM(scale, from, 5); write32(0); } else { assert( to != ESP ); MOV32RtoR(to, from); LEA32RStoR(to, to, scale); } } #endif #endif