#include "x86assembler.h" #include "x86emitter.h" #include "x86operand.h" #include "X86BufferWriter.h" #include #include #include #include int _vscprintf(const char * format, va_list pargs); ASMJIT_BEGIN_SUB_NAMESPACE(x86) static ASMJIT_FORCE_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept { ASMJIT_ASSERT(m <= 3); ASMJIT_ASSERT(o <= 7); ASMJIT_ASSERT(rm <= 7); return (m << 6) + (o << 3) + rm; } //! Memory operand's info bits. //! //! A lookup table that contains various information based on the BASE and INDEX information of a memory operand. This //! is much better and safer than playing with IFs in the code and can check for errors must faster and better. enum X86MemInfo_Enum { kX86MemInfo_0 = 0x00, kX86MemInfo_BaseGp = 0x01, //!< Has BASE reg, REX.B can be 1, compatible with REX.B byte. kX86MemInfo_Index = 0x02, //!< Has INDEX reg, REX.X can be 1, compatible with REX.X byte. kX86MemInfo_BaseLabel = 0x10, //!< Base is Label. kX86MemInfo_BaseRip = 0x20, //!< Base is RIP. kX86MemInfo_67H_X86 = 0x40, //!< Address-size override in 32-bit mode. kX86MemInfo_67H_X64 = 0x80, //!< Address-size override in 64-bit mode. kX86MemInfo_67H_Mask = 0xC0 //!< Contains all address-size override bits. }; void Internal_CPU_Message(Assembler * _emitter, const char * format, ...) { va_list args; va_start(args, format); int nlen = _vscprintf(format, args) + 1; if (nlen > 0) { char* buffer = static_cast(alloca(nlen * sizeof(char))); if (buffer != nullptr) { int result = vsnprintf(buffer, nlen, format, args); if (result >= 0 && result < nlen) { _emitter->_logger->_log(buffer, result); } } } va_end(args); }; #define CPU_Message(format, ...) \ do { \ if (_emitter->_logger != nullptr) { \ Internal_CPU_Message(_emitter, (format), ##__VA_ARGS__); \ } \ } while (0) template<> Error EmitterExplicitT::adc(Gp const & /*o0*/, Gp const & /*o1*/) { __debugbreak(); return 0; } template<> Error EmitterExplicitT::adc(Gp const & /*o0*/, Mem const & /*o1*/) { __debugbreak(); return 0; } template<> Error EmitterExplicitT::adc(Gp const & /*o0*/, Imm const & /*o1*/) { __debugbreak(); return 0; } template<> Error EmitterExplicitT::add(Gp const & o0, Gp const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && o1.size() == 4) { CPU_Message("add %s, %s", x86_Name(o0), x86_Name(o1)); writer.emit16(0xC003 + (o0.id() << 11) + (o1.id() << 8)); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } template<> Error EmitterExplicitT::add(Gp const & o0, Mem const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && !o1.hasBase() && !o1.hasIndex() && !o1.hasShift()) { CPU_Message("add %s, dword ptr [0x%X]", x86_Name(o0), (uint32_t)o1.offsetLo32()); writer.emit16(0x0503 | (o0.id() << 11)); writer.emit32((uint32_t)o1.offsetLo32()); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } template<> Error EmitterExplicitT::add(Gp const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 8) { int64_t immValue = o1.value(); if (!Support::isInt32(immValue)) { __debugbreak(); return kErrorInvalidRegType; } if ((o0.id() & ~7) != 0) { __debugbreak(); return kErrorInvalidRegType; } CPU_Message("add %s, 0x%X", x86_Name(o0), (uint32_t)immValue); writer.emit8(0x48); if (Support::isInt8(immValue)) { writer.emit8(0x83); writer.emit8(0xC0 + (o0.id() & 7)); writer.emit8((uint8_t)immValue); } else { writer.emit8(0x81); writer.emit8(0xC0 + (o0.id() & 7)); writer.emit32(immValue); } return kErrorOk; } if (o0.size() == 4) { int32_t immValue = (uint32_t)o1.value(); CPU_Message("add %s, 0x%X", x86_Name(o0), immValue); if (Support::isInt8(immValue)) { writer.emit16(0xC083 + (o0.id() << 8)); writer.emit8(immValue); return kErrorOk; } writer.emit16(0xC081 + (o0.id() << 8)); writer.emit32(immValue); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::add(Mem const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (!o0.hasBase() && !o0.hasIndex() && !o0.hasShift()) { CPU_Message("add dword ptr [0x%X], 0x%X", (uint32_t)o0.offsetLo32(), (uint32_t)o1.value()); writer.emit16(0x0581); writer.emit32((uint32_t)o0.offsetLo32()); writer.emit32((uint32_t)o1.value()); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::and_(Gp const & /*o0*/, Gp const & /*o0*/) { int a = 5; a = 66; __debugbreak(); return 0; } Error EmitterExplicitT::and_(Gp const & o0, Mem const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && !o1.hasBase() && !o1.hasIndex() && !o1.hasShift()) { CPU_Message("and %s, dword ptr [0x%X]", x86_Name(o0), (uint32_t)o1.offsetLo32()); writer.emit16(0x0523 + (o0.id() << 11)); writer.emit32(o1.offsetLo32()); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::and_(Gp const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4) { int32_t immValue = (uint32_t)o1.value(); CPU_Message("and %s, %Xh", x86_Name(o0), immValue); if (Support::isInt8(immValue)) { writer.emit8(0x83); writer.emit8(x86EncodeMod(3, 4, o0.id())); writer.emit8((uint8_t)immValue); } else { writer.emit8(0x81); writer.emit8(x86EncodeMod(3, 4, o0.id())); writer.emit32(immValue); } return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::and_(Mem const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (!o0.hasBase() && !o0.hasIndex() && !o0.hasShift()) { int32_t immValue = (uint32_t)o1.value(); CPU_Message("and dword ptr [0x%X], 0x%X", (uint32_t)o0.offsetLo32(), immValue); if (Support::isInt8(immValue)) { writer.emit16(0x2580); writer.emit32((uint32_t)o0.offsetLo32()); writer.emit8((uint8_t)immValue); return kErrorOk; } writer.emit16(0x2581); writer.emit32((uint32_t)o0.offsetLo32()); writer.emit32(immValue); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::call(Gp const & o0) { X86BufferWriter writer(_emitter); if (o0.size() == 8) { if ((o0.id() & ~7) != 0) { __debugbreak(); return kErrorInvalidRegType; } CPU_Message("call %s", x86_Name(o0)); writer.emit8(0xFF); writer.emit8(0xD0 + (o0.id() & 7)); return kErrorOk; } __debugbreak(); return 0; } Error EmitterExplicitT::call(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::call(Imm const & o0) { X86BufferWriter writer(_emitter); CodeHolder * _code = _emitter->code(); uint64_t baseAddress = _code->baseAddress(); uint64_t jumpAddress = o0.value(); CPU_Message("call offset 0x%X", (uint32_t)jumpAddress); if (baseAddress != Globals::kNoBaseAddress) { __debugbreak(); return kErrorInvalidInstruction; } RelocEntry * re = nullptr; Error err = _code->newRelocEntry(&re, RelocType::kAbsToRel); if (ASMJIT_UNLIKELY(err)) { __debugbreak(); return kErrorInvalidInstruction; } re->_sourceOffset = _emitter->offset(); re->_sourceSectionId = _emitter->_section->id(); re->_payload = jumpAddress; re->_format.resetToSimpleValue(OffsetType::kSignedOffset, 4); writer.emit8(0xE8); re->_format.setLeadingAndTrailingSize(writer.offsetFrom(_emitter->_bufferPtr), 0); writer.emit32(0); return kErrorOk; } Error EmitterExplicitT::cmp(Gp const & o0, Gp const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && o1.size() == 4) { CPU_Message("cmp %s, %s", x86_Name(o0), x86_Name(o1)); writer.emit16(0xC03B + (o0.id() << 11) + (o1.id() << 8)); return kErrorOk; } __debugbreak(); return kErrorInvalidInstruction; } Error EmitterExplicitT::cmp(Gp const & o0, Mem const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && !o1.hasBase() && !o1.hasIndex() && !o1.hasShift()) { CPU_Message("cmp %s, dword ptr [0x%X]", x86_Name(o0), (uint32_t)o1.offsetLo32()); writer.emit16(0x053B + (o0.id() << 11)); writer.emit32(o1.offsetLo32()); return kErrorOk; } __debugbreak(); return kErrorInvalidInstruction; } Error EmitterExplicitT::cmp(Gp const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); int32_t immValue = (uint32_t)o1.value(); if (o0.size() == 4) { CPU_Message("cmp %s, %Xh", x86_Name(o0), immValue); if (Support::isInt8(immValue)) { writer.emit16(0xF883 + (o0.id() << 8)); writer.emit8((int8_t)immValue); return kErrorOk; } else { __debugbreak(); return kErrorInvalidInstruction; } } __debugbreak(); return kErrorInvalidInstruction; } Error EmitterExplicitT::cmp(Mem const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (!o0.hasBase() && !o0.hasIndex() && !o0.hasShift()) { int32_t immValue = (uint32_t)o1.value(); CPU_Message("cmp dword ptr [0x%X], 0x%X", (uint32_t)o0.offsetLo32(), immValue); if (Support::isInt8(immValue)) { writer.emit16(0x3D80); writer.emit32((uint32_t)o0.offsetLo32()); writer.emit8((uint8_t)immValue); return kErrorOk; } writer.emit16(0x3D81); writer.emit32((uint32_t)o0.offsetLo32()); writer.emit32(immValue); return kErrorOk; } __debugbreak(); return kErrorInvalidInstruction; } Error EmitterExplicitT::dec(Gp const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::inc(Gp const & o0) { X86BufferWriter writer(_emitter); if (o0.size() == 4) { CPU_Message("inc %s", x86_Name(o0)); if (o0.id() == Gp::kIdSp) { writer.emit8(0x44); } else if (o0.id() == Gp::kIdBp) { writer.emit8(0x45); } else { writer.emit16(0xC0FF | (o0.id() << 8)); } return kErrorOk; } __debugbreak(); return kErrorInvalidInstruction; } Error EmitterExplicitT::j(CondCode /*cc*/, const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::ja(const Label & o0) { CPU_Message("ja L%u", o0.id()); return emitJump(0x870F, 2, o0); } Error EmitterExplicitT::jae(const Label & /*o0*/) { int a = 5; a = 7; __debugbreak(); return 0; } Error EmitterExplicitT::jb(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jbe(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jc(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::je(const Label & o0) { CPU_Message("je L%u", o0.id()); return emitJump(0x840F, 2, o0); } Error EmitterExplicitT::jg(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jge(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jl(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jle(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jna(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jnae(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jnb(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jnbe(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jnc(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jne(const Label & o0) { CPU_Message("jne L%u", o0.id()); return emitJump(0x850F, 2, o0); } Error EmitterExplicitT::jng(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jnge(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jnl(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jnle(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jno(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jnp(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jns(const Label & o0) { CPU_Message("jns L%u", o0.id()); return emitJump(0x890F, 2, o0); } Error EmitterExplicitT::jnz(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jo(const Label & o0) { CPU_Message("jo L%u", o0.id()); return emitJump(0x800F, 2, o0); } Error EmitterExplicitT::jp(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jpe(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jpo(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::js(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jz(const Label & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::jmp(const Label & o0) { CPU_Message("jmp L%u", o0.id()); return emitJump(0xE9, 1, o0); } Error EmitterExplicitT::lea(Gp const & o0, Mem const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && o1.hasBase()) { if (o1.baseId() == Gp::kIdSp) { __debugbreak(); return kErrorInvalidInstruction; } if (o1.baseId() != Gp::kIdBp && o1.offsetLo32() == 0) { __debugbreak(); return kErrorInvalidInstruction; } if (Support::isInt8(o1.offsetLo32())) { CPU_Message("lea %s, [%s+0x%X]", x86_Name(o0), x86_Name(Gpd(o1.baseId())), (uint8_t)o1.offsetLo32()); writer.emit16(0x408D + (o0.id() << 11) + (o1.baseId() << 8)); writer.emit8(o1.offsetLo32()); return kErrorOk; } __debugbreak(); return kErrorInvalidInstruction; } __debugbreak(); return kErrorInvalidInstruction; } Error EmitterExplicitT::mov(Gp const & o0, Gp const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 8 && o1.size() == 8) { if ((o0.id() & ~7) != 0 || (o1.id() & ~7) != 0) { __debugbreak(); return kErrorInvalidRegType; } writer.emit8(0x48); writer.emit16(0xC089 + ((o0.id() & 7) << 8) + ((o1.id() & 7) << 11)); return kErrorOk; } if (o0.size() == 4 && o1.size() == 4) { CPU_Message("mov %s, %s", x86_Name(o0), x86_Name(o1)); writer.emit16(0xC089 + (o0.id() << 8) + (o1.id() << 11)); return kErrorOk; } __debugbreak(); return kErrorInvalidInstruction; } Error EmitterExplicitT::mov(Gp const & o0, Mem const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && !o1.hasBase() && !o1.hasIndex() && !o1.hasShift()) { CPU_Message("mov %s, dword ptr [0x%X]", x86_Name(o0), (uint32_t)o1.offsetLo32()); if (o0.id() == Gp::kIdAx) { writer.emit8(0xA1); writer.emit32(o1.offsetLo32()); return kErrorOk; } writer.emit8(0x8b); writer.emit8(x86EncodeMod(0, o0.id(), 5)); writer.emit32(o1.offsetLo32()); return kErrorOk; } if (o0.size() == 4 && !o1.hasBase() && o1.hasIndex()) { CPU_Message("mov %s, dword ptr [0x%X+%s%s]", x86_Name(o0), (uint32_t)o1.offsetLo32(), x86_Name(Gpd(o1.id())), o1.hasShift() ? stdstr_f("*%i", o1.shift() << 1).c_str() : ""); writer.emit16(0x048B | (o0.id() << 11)); writer.emit8(0x05 | (o1.indexId() << 3) | ((o1.hasShift() ? o1.shift() : 0) << 6)); writer.emit32((uint32_t)o1.offsetLo32()); return kErrorOk; } if (o0.size() == 4 && o1.hasBase() && o1.hasIndex() && !o1.hasShift()) { if (o1.id() == Gp::kIdSp || o1.id() == Gp::kIdBp) { __debugbreak(); return kErrorInvalidRegType; } CPU_Message("mov %s, dword ptr [%s+%s]", x86_Name(o0), x86_Name(Gpd(o1.id())), x86_Name(Gpd(o1.indexId()))); writer.emit16(0x048B | (o0.id() << 11)); writer.emit8(o1.id() | (o1.indexId() << 3)); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::mov(Gp const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 8) { int64_t immValue = o1.value(); if (Support::isInt32(immValue)) { CPU_Message("mov %s, %Xh", x86_Name(o0), (uint32_t)immValue); writer.emit8(0x48 | ((o0.id() & 0x08) >> 3)); writer.emit16(0xC0C7 | ((o0.id() & 7) << 8)); writer.emit32((uint32_t)immValue); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } if (o0.size() == 4) { int32_t immValue = (uint32_t)o1.value(); CPU_Message("mov %s, %Xh", x86_Name(o0), immValue); if (Support::isInt8(immValue)) { __debugbreak(); return kErrorInvalidRegType; } writer.emit16(0xC0C7 | (o0.id() << 8)); writer.emit32(immValue); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::mov(Mem const & o0, Gp const & o1) { X86BufferWriter writer(_emitter); if (o0.hasBase() && !o0.hasIndex() && !o0.hasShift() && o1.size() == 4 ) { CPU_Message("mov dword ptr [%s%s], %s", x86_Name(Gpd(o0.id())), (uint8_t)o0.offsetLo32() != 0 ? stdstr_f("+0x%X",(uint8_t)o0.offsetLo32()).c_str() : "", x86_Name(o1)); writer.emit16(0x4089 | (o1.id() << 11) | (o0.id() << 8)); writer.emit8((uint8_t)o0.offsetLo32()); return kErrorOk; } if (o0.hasBase() && o0.hasIndex() && !o0.hasShift() && o1.size() == 4) { __debugbreak(); return kErrorInvalidRegType; } if (!o0.hasBase() && !o0.hasIndex() && o1.size() == 4) { CPU_Message("mov dword ptr [0x%X], %s", (uint32_t)o0.offsetLo32(), x86_Name(o1)); writer.emit16(0x0589 | (o1.id() << 11)); writer.emit32((uint32_t)o0.offsetLo32()); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::mov(Mem const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (!o0.hasBase() && !o0.hasIndex() && !o0.hasShift()) { CPU_Message("mov dword ptr [0x%X], 0x%X", (uint32_t)o0.offsetLo32(), (uint32_t)o1.value()); writer.emit16(0x05C7); writer.emit32((uint32_t)o0.offsetLo32()); writer.emit32((uint32_t)o1.value()); return kErrorOk; } else if (o0.hasBase() && o0.hasIndex() && !o0.hasShift() && o0.size() == 4) { CPU_Message("mov dword ptr [%s+%s],%Xh", x86_Name(Gpd(o0.baseId())), x86_Name(Gpd(o0.indexId())), (uint32_t)o1.value()); writer.emit16(0x04C7); writer.emit8(o0.baseId() + (o0.indexId() << 3)); writer.emit32((uint32_t)o1.value()); return kErrorOk; } else if (o0.hasBase() && !o0.hasIndex() && !o0.hasShift() && o0.size() == 4) { CPU_Message("mov dword ptr [%s+%Xh], %Xh", x86_Name(Gpd(o0.baseId())), o0.offsetLo32(), (uint32_t)o1.value()); if (Support::isInt8(o0.offsetLo32())) { writer.emit16(0x40C7 + (o0.baseId() << 8)); writer.emit8((int8_t)(o0.offsetLo32())); } else { writer.emit16(0x80C7 + (o0.baseId() << 8)); writer.emit32(o0.offsetLo32()); } writer.emit32((uint32_t)o1.value()); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::movsx(Gp const & /*o0*/, Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::movzx(Gp const & /*o0*/, Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::not_(Gp const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::or_(Gp const & o0, Gp const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && o1.size() == 4) { CPU_Message("or %s, %s", x86_Name(o0), x86_Name(o1)); writer.emit16(0xC00B + (o0.id() << 11) + (o1.id() << 8)); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::or_(Gp const & /*o0*/, Mem const & /*o0*/) { int a = 71; a = 71; __debugbreak(); return 0; } Error EmitterExplicitT::or_(Gp const & o0, Imm const & o1) { if (o1.value() == 0) { return kErrorOk; } int32_t immValue = (int32_t)o1.value(); CPU_Message("or %s, %Xh", x86_Name(o0), immValue); X86BufferWriter writer(_emitter); if (Support::isInt8(immValue)) { writer.emit16(0xC883 | (o0.id() << 8)); writer.emit8((uint8_t)immValue); } else { writer.emit16(0xC881 | (o0.id() << 8)); writer.emit32(immValue); } return kErrorOk; } Error EmitterExplicitT::or_(Mem const & /*o0*/, Gp const & /*o0*/) { int a = 73; a = 73; __debugbreak(); return 0; } Error EmitterExplicitT::or_(Mem const & /*o0*/, Imm const & /*o1*/) { int a = 4; a = 74; __debugbreak(); return 0; } Error EmitterExplicitT::pop(Gp const & o0) { X86BufferWriter writer(_emitter); CPU_Message("pop %s", x86_Name(o0)); if (o0.size() == 8) { if ((o0.id() & ~7) != 0) { __debugbreak(); return kErrorInvalidRegType; } writer.emit8(0x58 | (o0.id() & 7)); return kErrorOk; } if (o0.size() == 4) { writer.emit8(0x58 | o0.id()); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::popad(void) { CPU_Message("pushad"); X86BufferWriter writer(_emitter); writer.emit8(0x61); return kErrorOk; } Error EmitterExplicitT::push(Gp const & o0) { CPU_Message("push %s", x86_Name(o0)); X86BufferWriter writer(_emitter); if (o0.size() == 4 || o0.size() == 8) { if ((o0.id() & ~7) != 0) { __debugbreak(); return kErrorInvalidRegType; } writer.emit8(0x50 | (o0.id() & 7)); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::push(Imm const & o0) { X86BufferWriter writer(_emitter); int32_t immValue = (int32_t)o0.value(); CPU_Message("push 0x%X", (uint32_t)(immValue)); if (Support::isInt8(immValue) == 1) { writer.emit8(0x6A); writer.emit8((int8_t)(immValue)); } else { writer.emit8(0x68); writer.emit32(immValue); } return kErrorOk; } Error EmitterExplicitT::pushad() { CPU_Message("pushad"); X86BufferWriter writer(_emitter); writer.emit8(0x60); return kErrorOk; } Error EmitterExplicitT::sbb(Gp const & /*o0*/, Gp const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::sbb(Gp const & /*o0*/, Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::sbb(Gp const & /*o0*/, Imm const & /*o1*/) { __debugbreak(); return 0; } Error EmitterExplicitT::sar(Gp const & /*o0*/, Gp const & /*o1*/) { __debugbreak(); return 0; } Error EmitterExplicitT::sar(Gp const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4) { uint8_t immValue = (uint8_t)o1.value(); CPU_Message("sar %s, %Xh", x86_Name(o0), immValue); writer.emit16(0xF8C1 | (o0.id() << 8)); writer.emit8((uint8_t)immValue); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::seta(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::setb(Mem const & o0) { X86BufferWriter writer(_emitter); if (!o0.hasBase() && !o0.hasIndex() && !o0.hasShift()) { CPU_Message("setb byte ptr [0x%X]", (uint32_t)o0.offsetLo32()); writer.emit16(0x920F); writer.emit8(0x05); writer.emit32((uint32_t)o0.offsetLo32()); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::setg(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::setl(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::setg(Gp const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::setl(Gp const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::setnz(Gp const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::shl(Gp const & o0, Gp const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && o1.size() == 1 && o1.isGpbLo() && o1.id() == Gp::kIdCx) { CPU_Message("shl %s, cl", x86_Name(o0)); writer.emit16(0xE0D3 + (o0.id() << 8)); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::shl(Gp const & /*o0*/, Imm const & /*o1*/) { __debugbreak(); return 0; } Error EmitterExplicitT::shr(Gp const & o0, Gp const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && o1.size() == 1 && o1.isGpbLo() && o1.id() == Gp::kIdCx) { CPU_Message("shr %s, cl", x86_Name(o0)); writer.emit16(0xE8D3 + (o0.id() << 8)); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::shr(Gp const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); uint32_t immValue = (uint32_t)o1.value(); if (o0.size() == 4) { CPU_Message("shr %s, %Xh", x86_Name(o0), immValue); writer.emit16(0xE8C1 + (o0.id() << 8)); writer.emit8((uint8_t)immValue); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::shld(Gp const & /*o0*/, Gp const & /*o1*/, Gp const & /*o2*/) { __debugbreak(); return 0; } Error EmitterExplicitT::shld(Gp const & /*o0*/, Gp const & /*o1*/, Imm const & /*o2*/) { __debugbreak(); return 0; } Error EmitterExplicitT::shrd(Gp const & /*o0*/, Gp const & /*o1*/, Gp const & /*o2*/) { __debugbreak(); return 0; } Error EmitterExplicitT::shrd(Gp const & /*o0*/, Gp const & /*o1*/, Imm const & /*o1*/) { __debugbreak(); return 0; } Error EmitterExplicitT::sub(Gp const & o0, Gp const & o1) { X86BufferWriter writer(_emitter); CPU_Message("sub %s, %s", x86_Name(o0), x86_Name(o1)); if (o0.size() == 4 && o1.size() == 4) { writer.emit16(0xC02B + (o0.id() << 11) + (o1.id() << 8)); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::sub(Gp const & /*o0*/, Mem const & /*o0*/) { int a = 5; a = 7774; __debugbreak(); return 0; } Error EmitterExplicitT::sub(Gp const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 8) { int64_t immValue = o1.value(); if (!Support::isInt32(immValue)) { __debugbreak(); return kErrorInvalidRegType; } if ((o0.id() & ~7) != 0) { __debugbreak(); return kErrorInvalidRegType; } CPU_Message("sub %s, 0x%X", x86_Name(o0), (uint32_t)immValue); writer.emit8(0x48); if (Support::isInt8(immValue)) { writer.emit16(0xE883 | ((o0.id() & 7) << 8)); writer.emit8((uint8_t)immValue); } else { writer.emit16(0xE881 | ((o0.id() & 7) << 8)); writer.emit32((uint32_t)immValue); } return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::sub(Mem const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (!o0.hasBase() && !o0.hasIndex() && !o0.hasShift()) { int32_t immValue = (uint32_t)o1.value(); CPU_Message("sub dword ptr [0x%X], 0x%X", (uint32_t)o0.offsetLo32(), immValue); if (Support::isInt8(immValue)) { writer.emit16(0x2D83); writer.emit32((uint32_t)o0.offsetLo32()); writer.emit8((uint8_t)immValue); return kErrorOk; } writer.emit16(0x2D81); writer.emit32((uint32_t)o0.offsetLo32()); writer.emit32(immValue); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::test(Gp const & o0, Gp const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 1 && o1.size() == 1) { CPU_Message("test %s, %s", x86_Name(o0), x86_Name(o1)); writer.emit8(0x84); writer.emit8(x86EncodeMod(3, o0.id(), o1.id())); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::test(Gp const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4) { uint32_t immValue = (uint32_t)o1.value(); CPU_Message("test %s, 0x%X", x86_Name(o0), immValue); if (o0.id() == Gp::kIdAx) { writer.emit8(0xA9); } else { writer.emit16(0xC0F7 + (o0.id() << 8)); } writer.emit32(immValue); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::test(Mem const & o0, Imm const & o1) { X86BufferWriter writer(_emitter); if (!o0.hasBaseOrIndex()) { CPU_Message("test dword ptr ds:[0x%X], 0x%X", o0.offsetLo32(), (uint32_t)(o1.value())); writer.emit16(0x05F7); writer.emit32(o0.offsetLo32()); writer.emit32((uint32_t)(o1.value())); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterExplicitT::xor_(Gp const & o0, Gp const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && o1.size() == 4) { CPU_Message("xor %s, %s", x86_Name(o0), x86_Name(o1)); writer.emit16(0xC031 | (o0.id() << 8) | (o1.id() << 11)); return kErrorOk; } __debugbreak(); return kErrorInvalidInstruction; } Error EmitterExplicitT::xor_(Gp const & o0, Mem const & o1) { X86BufferWriter writer(_emitter); if (o0.size() == 4 && !o1.hasBase() && !o1.hasIndex() && !o1.hasShift()) { CPU_Message("xor %s, dword ptr [0x%X]", x86_Name(o0), (uint32_t)o1.offsetLo32()); writer.emit16(0x0533 | (o0.id() << 11)); writer.emit32((uint32_t)o1.offsetLo32()); return kErrorOk; } __debugbreak(); return kErrorInvalidInstruction; } Error EmitterExplicitT::xor_(Gp const & /*o0*/, Imm const & /*o1*/) { __debugbreak(); return 0; } Error EmitterExplicitT::sahf(Gp const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::ldmxcsr(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::stmxcsr(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::int3() { __debugbreak(); return 0; } Error EmitterExplicitT::fabs() { __debugbreak(); return 0; } Error EmitterExplicitT::fadd(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fchs() { __debugbreak(); return 0; } Error EmitterExplicitT::fclex() { __debugbreak(); return 0; } Error EmitterExplicitT::fcomp(St const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fcomp(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fcompp() { __debugbreak(); return 0; } Error EmitterExplicitT::fdiv(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::ffree(St const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fild(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fincstp() { __debugbreak(); return 0; } Error EmitterExplicitT::finit() { X86BufferWriter writer(_emitter); writer.emit8(0x9B); writer.emit16(0xE3DB); return kErrorInvalidRegType; } Error EmitterExplicitT::fist(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fistp(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fld(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fld(St const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fldcw(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fmul(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fnstcw(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fsqrt() { __debugbreak(); return 0; } Error EmitterExplicitT::fst(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fstp(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fsub(Mem const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fxch(St const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fstsw(Gp const & /*o0*/) { __debugbreak(); return 0; } Error EmitterExplicitT::fnstsw(Gp const & /*o0*/) { __debugbreak(); return 0; } Error EmitterImplicitT::div(Gp const & /*o0*/) { __debugbreak(); return 0; } Error EmitterImplicitT::idiv(Gp const & /*o0*/) { __debugbreak(); return 0; } Error EmitterImplicitT::imul(Gp const & /*o0*/) { int a = 5; a = 533; __debugbreak(); return 0; } Error EmitterImplicitT::jecxz(Label const & /*o0*/) { __debugbreak(); return 0; } Error EmitterImplicitT::mul(Gp const & o0) { X86BufferWriter writer(_emitter); if (o0.size() == 4) { CPU_Message("mul %s", x86_Name(o0)); writer.emit16(0xE0F7 | (o0.id() << 8)); return kErrorOk; } __debugbreak(); return kErrorInvalidRegType; } Error EmitterImplicitT::ret() { CPU_Message("ret"); X86BufferWriter writer(_emitter); writer.emit8(0xC3); return kErrorOk; } Error EmitterImplicitT::sahf() { __debugbreak(); return 0; } template<> Error EmitterImplicitT::emitJump(uint16_t Opcode, uint8_t OpcodeSize, const Label & o0) { X86BufferWriter writer(_emitter); CodeHolder *& code = _emitter->_code; Section *& section = _emitter->_section; LabelEntry * label = code->labelEntry(o0); if (ASMJIT_UNLIKELY(!label)) { __debugbreak(); return kErrorInvalidInstruction; } if (!label->isBoundTo(section)) { if (OpcodeSize == 1) { writer.emit8((uint8_t)Opcode); } else if (OpcodeSize == 2) { writer.emit16(Opcode); } else { __debugbreak(); return kErrorInvalidInstruction; } size_t offset = size_t(writer.offsetFrom(_emitter->_bufferData)); OffsetFormat of; of.resetToSimpleValue(OffsetType::kSignedOffset, 4); LabelLink* link = code->newLabelLink(label, section->id(), offset, -4, of); if (ASMJIT_UNLIKELY(!link)) { __debugbreak(); return kErrorOutOfMemory; } writer.emit32(0); return kErrorOk; } __debugbreak(); return kErrorInvalidInstruction; } template<> const char * EmitterExplicitT::x86_Name(const asmjit::x86::Gp & Reg) { if (Reg.size() == 1 && Reg.isGpbLo()) { switch (Reg.id()) { case Gp::kIdAx: return "al"; case Gp::kIdCx: return "cl"; case Gp::kIdDx: return "dl"; case Gp::kIdBx: return "bl"; } } else if (Reg.size() == 4) { switch (Reg.id()) { case Gp::kIdAx: return "eax"; case Gp::kIdCx: return "ecx"; case Gp::kIdDx: return "edx"; case Gp::kIdBx: return "ebx"; case Gp::kIdSp: return "esp"; case Gp::kIdBp: return "ebp"; case Gp::kIdSi: return "esi"; case Gp::kIdDi: return "edi"; } } else if (Reg.size() == 8) { switch (Reg.id()) { case Gp::kIdAx: return "rax"; case Gp::kIdCx: return "rcx"; case Gp::kIdDx: return "rdx"; case Gp::kIdBx: return "rbx"; case Gp::kIdSp: return "rsp"; case Gp::kIdBp: return "rbp"; case Gp::kIdSi: return "rsi"; case Gp::kIdDi: return "rdi"; case Gp::kIdR8: return "r8"; case Gp::kIdR9: return "r9"; case Gp::kIdR10: return "r10"; case Gp::kIdR11: return "r11"; case Gp::kIdR12: return "r12"; case Gp::kIdR13: return "r13"; case Gp::kIdR14: return "r14"; case Gp::kIdR15: return "r15"; } } __debugbreak(); return "unknown"; } ASMJIT_END_SUB_NAMESPACE