1612 lines
39 KiB
C++
1612 lines
39 KiB
C++
#include "x86assembler.h"
|
|
#include "x86emitter.h"
|
|
#include "x86operand.h"
|
|
#include "X86BufferWriter.h"
|
|
#include <cstdarg>
|
|
#include <stdio.h>
|
|
#include <Common/Platform.h>
|
|
#include <Common/StdString.h>
|
|
|
|
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<char*>(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<Assembler>::adc(Gp const & /*o0*/, Gp const & /*o1*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
template<>
|
|
Error EmitterExplicitT<Assembler>::adc(Gp const & /*o0*/, Mem const & /*o1*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
template<>
|
|
Error EmitterExplicitT<Assembler>::adc(Gp const & /*o0*/, Imm const & /*o1*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
template<>
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::and_(Gp const & /*o0*/, Gp const & /*o0*/)
|
|
{
|
|
int a = 5;
|
|
a = 66;
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::call(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::dec(Gp const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::j(CondCode /*cc*/, const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::ja(const Label & o0)
|
|
{
|
|
CPU_Message("ja L%u", o0.id());
|
|
return emitJump(0x870F, 2, o0);
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jae(const Label & /*o0*/)
|
|
{
|
|
int a = 5;
|
|
a = 7;
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jb(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jbe(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jc(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::je(const Label & o0)
|
|
{
|
|
CPU_Message("je L%u", o0.id());
|
|
return emitJump(0x840F, 2, o0);
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jg(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jge(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jl(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jle(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jna(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jnae(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jnb(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jnbe(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jnc(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jne(const Label & o0)
|
|
{
|
|
CPU_Message("jne L%u", o0.id());
|
|
return emitJump(0x850F, 2, o0);
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jng(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jnge(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jnl(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jnle(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jno(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jnp(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jns(const Label & o0)
|
|
{
|
|
CPU_Message("jns L%u", o0.id());
|
|
return emitJump(0x890F, 2, o0);
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jnz(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jo(const Label & o0)
|
|
{
|
|
CPU_Message("jo L%u", o0.id());
|
|
return emitJump(0x800F, 2, o0);
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jp(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jpe(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jpo(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::js(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jz(const Label & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::jmp(const Label & o0)
|
|
{
|
|
CPU_Message("jmp L%u", o0.id());
|
|
return emitJump(0xE9, 1, o0);
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::movsx(Gp const & /*o0*/, Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::movzx(Gp const & /*o0*/, Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::not_(Gp const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::or_(Gp const & /*o0*/, Mem const & /*o0*/)
|
|
{
|
|
int a = 71;
|
|
a = 71;
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::or_(Mem const & /*o0*/, Gp const & /*o0*/)
|
|
{
|
|
int a = 73;
|
|
a = 73;
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::or_(Mem const & /*o0*/, Imm const & /*o1*/)
|
|
{
|
|
int a = 4;
|
|
a = 74;
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::popad(void)
|
|
{
|
|
CPU_Message("pushad");
|
|
X86BufferWriter writer(_emitter);
|
|
writer.emit8(0x61);
|
|
return kErrorOk;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::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<Assembler>::pushad()
|
|
{
|
|
CPU_Message("pushad");
|
|
X86BufferWriter writer(_emitter);
|
|
writer.emit8(0x60);
|
|
return kErrorOk;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::sbb(Gp const & /*o0*/, Gp const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::sbb(Gp const & /*o0*/, Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::sbb(Gp const & /*o0*/, Imm const & /*o1*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::sar(Gp const & /*o0*/, Gp const & /*o1*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::seta(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::setg(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::setl(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
|
|
Error EmitterExplicitT<Assembler>::setg(Gp const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::setl(Gp const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::setnz(Gp const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::shl(Gp const & /*o0*/, Imm const & /*o1*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::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<Assembler>::shld(Gp const & /*o0*/, Gp const & /*o1*/, Gp const & /*o2*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::shld(Gp const & /*o0*/, Gp const & /*o1*/, Imm const & /*o2*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::shrd(Gp const & /*o0*/, Gp const & /*o1*/, Gp const & /*o2*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::shrd(Gp const & /*o0*/, Gp const & /*o1*/, Imm const & /*o1*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::sub(Gp const & /*o0*/, Mem const & /*o0*/)
|
|
{
|
|
int a = 5;
|
|
a = 7774;
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::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<Assembler>::xor_(Gp const & /*o0*/, Imm const & /*o1*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::sahf(Gp const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::ldmxcsr(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::stmxcsr(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::int3()
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fabs()
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
Error EmitterExplicitT<Assembler>::fadd(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
Error EmitterExplicitT<Assembler>::fchs()
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fclex()
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fcomp(St const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fcomp(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fcompp()
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fdiv(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::ffree(St const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fild(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fincstp()
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::finit()
|
|
{
|
|
X86BufferWriter writer(_emitter);
|
|
writer.emit8(0x9B);
|
|
writer.emit16(0xE3DB);
|
|
return kErrorInvalidRegType;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fist(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fistp(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fld(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fld(St const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fldcw(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fmul(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fnstcw(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fsqrt()
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fst(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fstp(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fsub(Mem const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fxch(St const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fstsw(Gp const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterExplicitT<Assembler>::fnstsw(Gp const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterImplicitT<Assembler>::div(Gp const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterImplicitT<Assembler>::idiv(Gp const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterImplicitT<Assembler>::imul(Gp const & /*o0*/)
|
|
{
|
|
int a = 5;
|
|
a = 533;
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterImplicitT<Assembler>::jecxz(Label const & /*o0*/)
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
Error EmitterImplicitT<Assembler>::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<Assembler>::ret()
|
|
{
|
|
CPU_Message("ret");
|
|
X86BufferWriter writer(_emitter);
|
|
writer.emit8(0xC3);
|
|
return kErrorOk;
|
|
}
|
|
|
|
Error EmitterImplicitT<Assembler>::sahf()
|
|
{
|
|
__debugbreak();
|
|
return 0;
|
|
}
|
|
|
|
template<>
|
|
Error EmitterImplicitT<Assembler>::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<Assembler>::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 |