Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tree: 5bd697b616
Fetching contributors…

Cannot retrieve contributors at this time

1073 lines (925 sloc) 24.555 kB
#include "virtual_asm.h"
#include <limits.h>
#include <stdarg.h>
#include <stack>
//See http://ref.x86asm.net/coder32.html for a list of x86 opcode bytes
namespace assembler {
enum OpExtension : byte {
EX_0 = 0,
EX_1 = 1,
EX_2 = 2,
EX_3 = 3,
EX_4 = 4,
EX_5 = 5,
EX_6 = 6,
EX_7 = 7,
};
enum ModBits : byte {
ADR = 0,
ADR8 = 1,
ADR32 = 2,
REG = 3
};
enum IndexScale : byte {
Scale1 = 0,
Scale2 = 1,
Scale4 = 2,
Scale8 = 3
};
unsigned char mod_rm(unsigned char Reg, unsigned char Mod, unsigned char RM) {
return (Mod<<6) | (Reg<<3) | RM;
}
unsigned char sib(unsigned char ScaledIndex, unsigned char Mode, unsigned char BaseReg) {
return (Mode<<6) | (ScaledIndex<<3) | BaseReg;
}
void moveToUpperDWORD(MemAddress& address) {
if(address.absolute_address == 0)
address.offset += 4;
else
address.absolute_address = (byte*)address.absolute_address + 4;
}
template<>
MemAddress as<float>(MemAddress addr) {
addr.bitMode = sizeof(float) * 8;
addr.Signed = true;
addr.Float = true;
return addr;
}
template<>
MemAddress as<double>(MemAddress addr) {
addr.bitMode = sizeof(double) * 8;
addr.Signed = true;
addr.Float = true;
return addr;
}
struct Argument {
Register* reg;
MemAddress* mem;
unsigned int constant;
Argument(Register* r) : reg(r), mem(0) {}
Argument(MemAddress* m) : reg(0), mem(m) {}
Argument(unsigned int Constant) : reg(0), mem(0), constant(Constant) {}
};
unsigned Processor::pushSize() {
return sizeof(void*);
}
void Processor::call_thiscall_prep(unsigned argBytes) {
#ifndef _MSC_VER
//THISCALL on GCC passes the this pointer on the stack, and is mostly identical to cdecl
call_cdecl_prep(argBytes + 4);
#endif
}
void Processor::call_thiscall_this(MemAddress address) {
#ifdef _MSC_VER
Register(*this,ECX) = as<void*>(address);
#else
push(as<void*>(address));
#endif
}
void Processor::call_thiscall_this(Register& reg) {
#ifdef _MSC_VER
Register(*this,ECX) = reg;
#else
push(reg);
#endif
}
void Processor::call_thiscall_end(unsigned argBytes) {
#ifndef _MSC_VER
//THISCALL callers on GCC pops arguments and pointers
call_cdecl_end(argBytes + 4);
#endif
}
void Processor::call_cdecl_prep(unsigned argBytes) {
#ifndef _MSC_VER
//Align to 16 byte boundary if not on MSVC
// Note: We already have cpu.stackDepth pushed, then we're pushing ebp to keep track of the stack
unsigned stackOffset = (stackDepth + pushSize()) % 16;
Register esp(*this, ESP), ebp(*this, EBP);
push(ebp);
ebp = esp;
if(stackOffset != 0)
esp -= 16 - stackOffset;
#endif
}
void Processor::call_cdecl_end(unsigned argBytes) {
Register esp(*this, ESP);
#ifdef _MSC_VER
esp += argBytes;
#else
Register ebp(*this, EBP);
esp = ebp;
pop(ebp);
#endif
}
void Processor::call_cdecl(void* func, const char* args, ...) {
std::stack<Argument> arg_stack;
unsigned argCount = 0;
if(args && *args != '\0') {
//Read the arguments in...
va_list list; va_start(list,args);
while(*args != '\0') {
++argCount;
if(*args == 'r')
arg_stack.push(va_arg(list,Register*));
else if(*args == 'm')
arg_stack.push(va_arg(list,MemAddress*));
else if(*args == 'c')
arg_stack.push(va_arg(list,unsigned int));
else
throw 0;
++args;
}
va_end(list);
call_cdecl_prep(argCount * 4);
//Then push them in reverse order
while(!arg_stack.empty()) {
auto& arg = arg_stack.top();
if(arg.reg)
push(*arg.reg);
else if(arg.mem)
push(*arg.mem);
else
push(arg.constant);
arg_stack.pop();
}
}
call(func);
call_cdecl_end(argCount * 4);
}
//STDCALL is similar to CDECL, but we don't need the call preperation or end
void Processor::call_stdcall(void* func, const char* args, ...) {
std::stack<Argument> arg_stack;
unsigned argCount = 0;
if(args && *args != '\0') {
//Read the arguments in...
va_list list; va_start(list,args);
while(*args != '\0') {
++argCount;
if(*args == 'r')
arg_stack.push(va_arg(list,Register*));
else if(*args == 'm')
arg_stack.push(va_arg(list,MemAddress*));
else if(*args == 'c')
arg_stack.push(va_arg(list,unsigned int));
else
throw 0;
++args;
}
va_end(list);
//Then push them in reverse order
while(!arg_stack.empty()) {
auto& arg = arg_stack.top();
if(arg.reg)
push(*arg.reg);
else if(arg.mem)
push(*arg.mem);
else
push(arg.constant);
arg_stack.pop();
}
}
call(func);
}
Processor::Processor(CodePage& codePage, unsigned defaultBitMode ) {
op = codePage.getActivePage();
bitMode = defaultBitMode;
lastBitMode = bitMode;
stackDepth = 4;
}
void Processor::migrate(CodePage& prevPage, CodePage& newPage) {
jump(Jump,newPage.getActivePage());
prevPage.markUsedAddress((void*)op);
op = newPage.getActivePage();
}
IndexScale factorToScale(unsigned char scale) {
switch(scale) {
case 1:
return Scale1; break;
case 2:
return Scale2; break;
case 4:
return Scale4; break;
case 8:
return Scale8; break;
default: throw 0;
}
}
template<>
Processor& Processor::operator<<(MemAddress addr) {
if(addr.absolute_address != 0) {
if(addr.scaleFactor == 0)
return *this << mod_rm(addr.other, ADR, ADDR) << addr.absolute_address;
else {
if(addr.scaleReg == ESP)
throw 0;
IndexScale scale = factorToScale(addr.scaleFactor);
return *this << mod_rm(addr.other, ADR, SIB) << sib(addr.scaleReg, scale, EBP) << addr.absolute_address;
}
}
if(addr.scaleFactor != 0) {
IndexScale scale = factorToScale(addr.scaleFactor);
//EBP can't accept a scaled index, and ESP doesn't perform scaling
if(addr.scaleReg == ESP)
throw 0;
if(addr.offset == 0 && addr.code != EBP)
return *this << mod_rm(addr.other, ADR, SIB) << sib(addr.scaleReg, scale, addr.code);
else if(addr.offset >= CHAR_MIN && addr.offset <= CHAR_MAX)
return *this << mod_rm(addr.other, ADR8, SIB) << sib(addr.scaleReg, scale, addr.code) << (char)addr.offset;
else
return *this << mod_rm(addr.other, ADR32, SIB) << sib(addr.scaleReg, scale, addr.code) << addr.offset;
}
if(addr.offset == 0 && addr.code != EBP) { //[EBP] means absolute address, so we use [EBP+0] instead
*this << mod_rm(addr.other, ADR, addr.code);
if(addr.code == ESP)
*this << '\x24'; //SIB byte indicating [ESP]
}
else if(addr.offset >= CHAR_MIN && addr.offset <= CHAR_MAX) {
*this << mod_rm(addr.other, ADR8, addr.code);
if(addr.code == ESP)
*this << '\x24'; //SIB byte indicating [ESP]
*this << (char)addr.offset;
}
else {
*this << mod_rm(addr.other, ADR32, addr.code);
if(addr.code == ESP)
*this << '\x24'; //SIB byte indicating [ESP]
*this << addr.offset;
}
return *this;
}
void Processor::push(Register& reg) {
*this << byte(0x50u+reg.code);
}
void Processor::pop(Register& reg) {
*this << byte(0x58u+reg.code);
}
void Processor::push(MemAddress address) {
address.other = EX_6;
switch(address.bitMode) {
case 8:
case 16:
case 32:
*this << '\xFF' << address; break;
case 64:
MemAddress upper(address); moveToUpperDWORD(upper);
*this << '\xFF' << upper;
*this << '\xFF' << address; break;
}
}
void Processor::pop(MemAddress address) {
address.other = EX_0;
switch(address.bitMode) {
case 8:
case 16:
case 32:
*this << '\x8F' << address; break;
case 64:
*this << '\x8F' << address;
moveToUpperDWORD(address);
*this << '\x8F' << address;
break;
}
}
void Processor::push(size_t value) {
if(value <= CHAR_MAX)
*this << '\x6A' << (byte)value;
else
*this << '\x68' << (unsigned int)value;
}
void Processor::pop(unsigned int count) {
Register esp(*this, ESP);
esp += count * pushSize();
}
void Processor::call(Register& reg) {
*this << '\xFF' << mod_rm(EX_2,REG,reg.code);
}
void Processor::call(void* func) {
int offset = ((byte*)func - op) - 5;
*this << '\xE8' << offset;
}
unsigned char shortJumpCodes[JumpTypeCount] = { 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xEB};
unsigned char longJumpCodes[JumpTypeCount] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0xE9 };
void* Processor::prep_short_jump(JumpType type) {
*this << shortJumpCodes[type];
void* ret = (void*)op;
*this << (char)0;
return ret;
}
void Processor::end_short_jump(void* p) {
volatile byte* jumpFrom = (volatile byte*)p;
int offset = (op - jumpFrom) - 1;
if(offset < CHAR_MIN || offset > CHAR_MAX)
throw 0;
*jumpFrom = (char)offset;
}
void* Processor::prep_long_jump(JumpType type) {
if(type != Jump)
*this << '\x0F';
*this << longJumpCodes[type];
void* ret = (void*)op;
*this << (int)0;
return ret;
}
void Processor::end_long_jump(void* p) {
volatile byte* jumpFrom = (volatile byte*)p;
*(volatile int*)jumpFrom = (op - jumpFrom) - 4;
}
void Processor::jump(JumpType type, volatile byte* dest) {
int offset = (dest - op) - 2;
if(offset >= CHAR_MIN && offset <= CHAR_MAX)
*this << shortJumpCodes[type] << (char)offset;
else if(type == Jump)
*this << longJumpCodes[Jump] << offset-3; //Long jump is 3 bytes larger, jump is from the end of the full opcode
else
*this << '\x0F' << longJumpCodes[type] << offset-4; //Conditional long jump is 4 bytes larger, jump is from the end of the full opcode
}
void Processor::jump(Register& reg) {
*this << '\xFF' << mod_rm(EX_4,REG,reg.code);
}
void Processor::ret() {
*this << '\xC3';
}
void Processor::debug_interrupt() {
*this << '\xCC';
}
MemAddress::MemAddress(Processor& CPU, void* address)
: cpu(CPU), code(ESP), absolute_address(address), other(NONE),
offset(0), bitMode(cpu.bitMode), Signed(false), scaleFactor(0) {}
MemAddress::MemAddress(Processor& CPU, RegCode Code)
: cpu(CPU), code(Code), absolute_address(0), other(NONE),
offset(0), bitMode(cpu.bitMode), Signed(false), scaleFactor(0) {}
MemAddress::MemAddress(Processor& CPU, RegCode Code, int Offset)
: cpu(CPU), code(Code), absolute_address(0), other(NONE),
offset(Offset), bitMode(cpu.bitMode), Signed(false), scaleFactor(0) {}
MemAddress MemAddress::operator+(ScaledIndex scale) {
scaleReg = scale.reg;
scaleFactor = scale.scaleFactor;
return *this;
}
MemAddress MemAddress::operator+(int Offset) {
offset += Offset;
return *this;
}
MemAddress MemAddress::operator-(int Offset) {
offset -= Offset;
return *this;
}
void MemAddress::operator++() {
switch(bitMode) {
case 8:
cpu << '\xFE' << *this; break;
case 16:
cpu << '\x66' << '\xFF' << *this; break;
case 32:
cpu << '\xFF' << *this; break;
case 64:
cpu << '\xFF' << *this;
void* p = cpu.prep_short_jump(NotOverflow);
moveToUpperDWORD(*this);
cpu << '\xFF' << *this;
cpu.end_short_jump(p);
}
}
void MemAddress::operator--() {
other = EX_1;
switch(bitMode) {
case 8:
cpu << '\xFE' << *this; break;
case 16:
cpu << '\x66' << '\xFF' << *this; break;
case 32:
cpu << '\xFF' << *this; break;
case 64:
cpu << '\xFF' << *this;
void* p = cpu.prep_short_jump(NotOverflow);
moveToUpperDWORD(*this);
cpu << '\xFF' << *this;
cpu.end_short_jump(p);
}
}
void MemAddress::operator-() {
other = EX_3;
switch(bitMode) {
case 8:
cpu << '\xF6' << *this; break;
case 16:
cpu << '\x66' << '\xF7' << *this; break;
case 32:
cpu << '\xF7' << *this; break;
case 64:
~MemAddress(*this);
++MemAddress(*this); break;
}
}
void MemAddress::operator~() {
other = EX_2;
switch(bitMode) {
case 8:
cpu << '\xF6' << *this; break;
case 16:
cpu << '\x66' << '\xF7' << *this; break;
case 32:
cpu << '\xF7' << *this; break;
case 64:
cpu << '\xF7' << *this;
moveToUpperDWORD(*this);
cpu << '\xF7' << *this; break;
}
}
void MemAddress::operator+=(unsigned int amount) {
if(amount == 0) return;
if(code == EAX)
cpu << '\x05' << amount;
else if(amount <= CHAR_MAX)
cpu << '\x83' << *this << (byte)amount;
else
cpu << '\x81' << *this << amount;
}
void MemAddress::operator-=(unsigned int amount) {
if(amount == 0) return;
other = (RegCode)EX_5;
if(code == EAX)
cpu << '\x2D' << amount;
else if(amount <= CHAR_MAX)
cpu << '\x83' << *this << (byte)amount;
else
cpu << '\x81' << *this << amount;
}
void MemAddress::operator=(unsigned int value) {
switch(bitMode) {
case 8:
cpu << '\xC6' << *this << (byte)value; break;
case 16:
cpu << '\x66' << '\xC7' << *this << (unsigned short)value; break;
case 32:
cpu << '\xC7' << *this << value; break;
}
}
void MemAddress::operator&=(unsigned int value) {
other = EX_4;
cpu << '\x81' << *this << value;
}
void MemAddress::operator|=(unsigned int value) {
other = EX_7;
switch(bitMode) {
case 8:
cpu << '\x80' << *this << (byte)value; break;
case 16:
cpu << '\x66' << '\x81' << *this << (unsigned short)value; break;
case 32:
cpu << '\x81' << *this << value; break;
}
}
void MemAddress::operator=(void* value) {
cpu << '\xC7' << *this << value;
}
void MemAddress::operator=(Register fromReg) {
other = fromReg.code;
switch(bitMode) {
case 8:
cpu << '\x88' << *this; break;
case 16:
cpu << '\x66' << '\x89' << *this; break;
case 32:
cpu << '\x89' << *this; break;
case 64:
throw 0;
}
}
void MemAddress::direct_copy(MemAddress address, Register& intermediate) {
if(bitMode != address.bitMode)
throw 0;
other = intermediate.code; address.other = other;
switch(bitMode) {
case 8:
case 16:
case 32:
intermediate = address;
*this = intermediate;
break;
case 64:
bitMode = 32; address.bitMode = 32;
intermediate = address;
*this = intermediate;
moveToUpperDWORD(*this); moveToUpperDWORD(address);
intermediate = address;
*this = intermediate;
break;
}
}
Register::Register(Processor& CPU, RegCode Code) : cpu(CPU), code(Code), bitMode(0) {}
Register::Register(Processor& CPU, RegCode Code, unsigned BitModeOverride)
: cpu(CPU), code(Code), bitMode(BitModeOverride) {
}
unsigned Register::getBitMode() const {
if(bitMode)
return bitMode;
else
return cpu.bitMode;
}
unsigned Register::getBitMode(const MemAddress& addr) const {
if(bitMode == 0)
return addr.bitMode;
else if(bitMode <= addr.bitMode)
return bitMode;
else
throw 0;
}
MemAddress Register::operator*() const {
return MemAddress(cpu,code);
}
ScaledIndex Register::operator*(unsigned char scale) const {
return ScaledIndex(code, scale);
}
void Register::swap(MemAddress address) {
address.other = code;
switch(getBitMode(address)) {
case 8:
cpu << '\x86' << address; break;
case 16:
cpu << '\x66' << '\x87' << address; break;
case 32:
cpu << '\x87' << address; break;
case 64:
throw 0;
}
}
void Register::swap(Register& other) {
if(code == other.code)
return;
if(code == EAX)
cpu << byte(0x90+other.code);
else if(other.code == EAX)
cpu << byte(0x90+code);
else
cpu << '\x87' << mod_rm(code,REG,other.code);
}
void Register::copy_address(MemAddress address) {
address.other = code;
cpu << '\x8D' << address;
}
void Register::operator<<=(Register& other) {
if(other.code != ECX)
throw 0;
cpu << '\xD3' << mod_rm(EX_4,REG,code);
}
void Register::operator>>=(Register& other) {
if(other.code != ECX)
throw 0;
cpu << '\xD3' << mod_rm(EX_7,REG,code);
}
void Register::rightshift_logical(Register& other) {
if(other.code != ECX)
throw 0;
cpu << '\xD3' << mod_rm(EX_5,REG,code);
}
void Register::operator+=(unsigned int amount) {
if(amount == 0) return;
if(code == EAX)
cpu << '\x05' << amount;
else if(amount <= CHAR_MAX)
cpu << '\x83' << mod_rm(EX_0,REG,code) << (byte)amount;
else
cpu << '\x81' << mod_rm(EX_0,REG,code) << amount;
}
void Register::operator+=(MemAddress address) {
address.other = code;
cpu << '\x03' << address;
}
void Register::operator+=(Register& other) {
cpu << '\x03' << mod_rm(code,REG,other.code);
}
void Register::operator-=(unsigned int amount) {
if(amount == 0) return;
if(code == EAX)
cpu << '\x2D' << amount;
else if(amount <= CHAR_MAX)
cpu << '\x83' << mod_rm(EX_5,REG,code) << (byte)amount;
else
cpu << '\x81' << mod_rm(EX_5,REG,code) << amount;
}
void Register::operator-=(Register& other) {
cpu << '\x2B' << mod_rm(code,REG,other.code);
}
void Register::operator-=(MemAddress address) {
address.other = code;
cpu << '\x2B' << address;
}
void Register::operator*=(MemAddress address) {
address.other = code;
cpu << '\x0F' << '\xAF' << address;
}
void Register::multiply_signed(MemAddress address, int value) {
address.other = code;
if(cpu.bitMode == 32) {
if(value >= CHAR_MIN && value <= CHAR_MAX)
cpu << '\x6B' << address << (char)value;
else
cpu << '\x69' << address << value;
}
else if(cpu.bitMode == 16) {
if(value >= CHAR_MIN && value <= CHAR_MAX)
cpu << '\x66' << '\x6B' << address << (char)value;
else
cpu << '\x66' << '\x69' << address << (short)value;
}
}
void Register::operator-() {
cpu << '\xF7' << mod_rm(EX_3,REG,code);
}
void Register::operator--() {
switch(getBitMode()) {
case 8:
cpu << '\xFE' << mod_rm(EX_1,REG,code); break;
case 16:
cpu << '\x66' << byte('\x48'+code); break;
case 32:
cpu << byte('\x48'+code); break;
case 64:
throw 0;
}
}
void Register::operator++() {
switch(getBitMode()) {
case 8:
cpu << '\xFE' << mod_rm(EX_0,REG,code); break;
case 16:
cpu << '\x66' << byte('\x40'+code); break;
case 32:
cpu << byte('\x40'+code); break;
case 64:
throw 0;
}
}
void Register::operator~() {
if(getBitMode() == 8) {
cpu << '\xF6' << mod_rm(EX_2,REG,code);
}
else {
cpu << '\xF7' << mod_rm(EX_2,REG,code);
}
}
void Register::operator&=(MemAddress address) {
address.other = code;
cpu << '\x23' << address;
}
void Register::operator&=(unsigned long long mask) {
switch(getBitMode()) {
case 8:
cpu << '\x80' << mod_rm(EX_4,REG,code) << (byte)mask; break;
case 16:
cpu << '\x66' << '\x81' << mod_rm(EX_4,REG,code) << (unsigned short)mask; break;
case 32:
case 64:
if(code == EAX)
cpu << '\x25' << (unsigned)mask;
else
cpu << '\x81' << mod_rm(EX_4,REG,code) << (unsigned)mask;
}
}
void Register::operator&=(Register& other) {
switch(getBitMode()) {
case 8:
cpu << '\x20' << mod_rm(other.code,REG,code); break;
case 16:
cpu << '\x66' << '\x21' << mod_rm(other.code,REG,code); break;
case 32:
case 64:
cpu << '\x21' << mod_rm(other.code,REG,code); break;
}
}
void Register::operator^=(MemAddress address) {
address.other = code;
cpu << '\x33' << address;
}
void Register::operator^=(Register& other) {
cpu << '\x31' << mod_rm(other.code,REG,code);
}
void Register::operator|=(MemAddress address) {
address.other = code;
cpu << '\x0B' << address;
}
void Register::operator|=(unsigned long long mask) {
switch(getBitMode()) {
case 8:
cpu << '\x80' << mod_rm(EX_1,REG,code) << (byte)mask; break;
case 16:
cpu << '\x66' << '\x81' << mod_rm(EX_1,REG,code) << (unsigned short)mask; break;
case 32:
case 64:
if(code == EAX)
cpu << '\x0D' << (unsigned)mask;
else
cpu << '\x81' << mod_rm(EX_1,REG,code) << (unsigned)mask;
}
}
void Register::operator=(void* pointer) {
cpu << (byte)('\xB8'+code) << pointer;
}
void Register::operator=(unsigned long long value) {
switch(getBitMode()) {
case 8:
cpu << (byte)('\xB0'+code) << (byte)value; break;
case 16:
cpu << '\x66' << (byte)('\xB8'+code) << (unsigned short)value; break;
case 32:
cpu << (byte)('\xB8'+code) << (unsigned int)value; break;
case 64:
throw 0;
}
}
void Register::operator=(Register other) {
if(code != other.code)
cpu << '\x89' << mod_rm(other.code,REG,code);
}
void Register::copy_expanding(MemAddress address) {
address.other = code;
switch(getBitMode(address)) {
case 8:
cpu << '\x0F' << '\xBE' << address; break;
case 16:
cpu << '\x0F' << '\xBF' << address; break;
case 32:
*this = address; break;
case 64:
throw 0;
}
}
void Register::operator=(MemAddress addr) {
addr.other = code;
switch(getBitMode(addr)) {
case 8:
cpu << '\x8A' << addr; break;
case 16:
cpu << '\x66' << '\x8B' << addr; break;
case 32:
cpu << '\x8B' << addr; break;
case 64:
throw 0;
}
}
void Register::operator==(Register other) {
switch(getBitMode()) {
case 8:
cpu << '\x3A' << mod_rm(code,REG,other.code); break;
case 16:
cpu << '\x66' << '\x3B' << mod_rm(code,REG,other.code); break;
case 32:
cpu << '\x3B' << mod_rm(code,REG,other.code); break;
case 64:
throw 0;
}
}
void Register::operator==(MemAddress addr) {
addr.other = code;
switch(getBitMode(addr)) {
case 8:
cpu << '\x3A' << addr; break;
case 16:
cpu << '\x66' << '\x3B' << addr; break;
case 32:
cpu << '\x3B' << addr; break;
case 64:
throw 0;
}
}
void Register::operator==(unsigned int test) {
switch(getBitMode()) {
case 8:
cpu << '\x80' << mod_rm(EX_7,REG,code) << (byte)test; break;
case 16:
cpu << '\x66' << '\x80' << mod_rm(EX_7,REG,code) << (unsigned short)test; break;
case 32:
cpu << '\x81' << mod_rm(EX_7,REG,code) << test; break;
case 64:
throw 0;
}
}
unsigned char setConditions[JumpTypeCount-1] = {0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F};
void Register::setIf(JumpType condition) {
if(condition >= Jump)
throw 0;
cpu << '\x0F' << setConditions[condition] << mod_rm(EX_0,REG,code);
}
void Register::divide() {
cpu << '\xF7' << mod_rm(EX_6,REG,code);
}
void Register::divide_signed() {
cpu << '\xF7' << mod_rm(EX_7,REG,code);
}
FloatingPointUnit::FloatingPointUnit(Processor& CPU) : cpu(CPU) {}
void FloatingPointUnit::pop() {
//FSTP ST0
cpu << '\xDD' << '\xD8';
}
void FloatingPointUnit::init() {
cpu << '\xDB' << '\xE3';
}
void FloatingPointUnit::negate() {
cpu << '\xD9' << '\xE0';
}
void FloatingPointUnit::load_const_1() {
cpu << '\xD9' << '\xE8';
}
void FloatingPointUnit::operator-=(FloatReg reg) {
cpu << '\xDC' << mod_rm(EX_4,REG,reg);
}
void FloatingPointUnit::load_double(MemAddress address) {
address.other = EX_0;
cpu << '\xDD' << address;
}
void FloatingPointUnit::add_double(MemAddress address) {
address.other = EX_0;
cpu << '\xDC' << address;
}
void FloatingPointUnit::add_double(FloatReg reg, bool pop) {
if(pop)
cpu << '\xDE' << mod_rm(EX_0,REG,reg);
else
cpu << '\xDC' << mod_rm(EX_0,REG,reg);
}
void FloatingPointUnit::sub_double(MemAddress address, bool reversed) {
address.other = reversed ? EX_5 : EX_4;
cpu << '\xDC' << address;
}
void FloatingPointUnit::sub_double(FloatReg reg, bool reversed, bool pop) {
if(pop)
cpu << '\xDE' << mod_rm(reversed ? EX_5 : EX_4, REG, reg);
else
cpu << '\xDC' << mod_rm(reversed ? EX_5 : EX_4, REG, reg);
}
void FloatingPointUnit::mult_double(MemAddress address) {
address.other = EX_1;
cpu << '\xDC' << address;
}
void FloatingPointUnit::mult_double(FloatReg reg, bool pop) {
if(pop)
cpu << '\xDE' << mod_rm(EX_1,REG,reg);
else
cpu << '\xDC' << mod_rm(EX_1,REG,reg);
}
void FloatingPointUnit::div_double(MemAddress address, bool reversed) {
address.other = reversed ? EX_7 : EX_6;
cpu << '\xDC' << address;
}
void FloatingPointUnit::div_double(FloatReg reg, bool reversed, bool pop) {
if(pop)
cpu << '\xDE' << mod_rm(reversed ? EX_7 : EX_6, REG, reg);
else
cpu << '\xDC' << mod_rm(reversed ? EX_7 : EX_6, REG, reg);
}
void FloatingPointUnit::add_float(MemAddress address) {
address.other = EX_0;
cpu << '\xD8' << address;
}
void FloatingPointUnit::sub_float(MemAddress address) {
address.other = EX_4;
cpu << '\xD8' << address;
}
void FloatingPointUnit::mult_float(MemAddress address) {
address.other = EX_1;
cpu << '\xD8' << address;
}
void FloatingPointUnit::div_float(MemAddress address) {
address.other = EX_6;
cpu << '\xD8' << address;
}
void FloatingPointUnit::store_double(MemAddress address, bool pop) {
address.other = pop ? EX_3 : EX_2;
cpu << '\xDD' << address;
}
void FloatingPointUnit::load_float(MemAddress address) {
address.other = EX_0;
cpu << '\xD9' << address;
}
void FloatingPointUnit::store_float(MemAddress address, bool pop) {
address.other = pop ? EX_3 : EX_2;
cpu << '\xD9' << address;
}
void FloatingPointUnit::load_dword(MemAddress address) {
address.other = EX_0;
cpu << '\xDB' << address;
}
void FloatingPointUnit::store_dword(MemAddress address, bool pop) {
address.other = pop ? EX_3 : EX_2;
cpu << '\xDB' << address;
}
void FloatingPointUnit::load_qword(MemAddress address) {
address.other = EX_5;
cpu << '\xDF' << address;
}
void FloatingPointUnit::compare_toCPU(FloatReg floatReg, bool pop) {
if(pop)
cpu << '\xDF' << mod_rm(EX_5,REG,floatReg);
else
cpu << '\xDB' << mod_rm(EX_5,REG,floatReg);
}
void FloatingPointUnit::store_control_word(MemAddress address) {
address.other = EX_7;
cpu << '\xD9' << address;
}
void FloatingPointUnit::load_control_word(MemAddress address) {
address.other = EX_5;
cpu << '\xD9' << address;
}
};
Jump to Line
Something went wrong with that request. Please try again.