mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 21:57:57 +03:00
1246 lines
21 KiB
C++
1246 lines
21 KiB
C++
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include "PtrMacro.h"
|
|
#include "CacheBlock.h"
|
|
#include "MIPS.h"
|
|
|
|
#ifdef AMD64
|
|
|
|
#include <windows.h>
|
|
|
|
extern "C" RET_CODE _CCacheBlock_Execute(void*, void*);
|
|
|
|
#endif
|
|
|
|
#define GROWSIZE (0x40000)
|
|
|
|
CCacheBlock::CCacheBlock(uint32 nStart, uint32 nEnd)
|
|
{
|
|
m_nStart = nStart;
|
|
m_nEnd = nEnd;
|
|
|
|
m_pData = (uint8*)malloc(0);
|
|
m_nSize = 0;
|
|
m_nPtr = 0;
|
|
|
|
m_pReloc = (uint32*)malloc((nEnd - nStart));
|
|
|
|
m_nValid = false;
|
|
m_nCheckDelayedJump = false;
|
|
}
|
|
|
|
CCacheBlock::~CCacheBlock()
|
|
{
|
|
DELETEPTR(m_pData);
|
|
DELETEPTR(m_pReloc);
|
|
}
|
|
|
|
RET_CODE CCacheBlock::Execute(CMIPS* pCtx)
|
|
{
|
|
void* pEntry;
|
|
RET_CODE nRet;
|
|
uint32 nAddress;
|
|
|
|
if(!m_nValid)
|
|
{
|
|
Compile(pCtx);
|
|
|
|
#ifdef AMD64
|
|
|
|
DWORD nOldProtect;
|
|
VirtualProtect(m_pData, m_nSize, PAGE_EXECUTE_READWRITE, &nOldProtect);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
nAddress = pCtx->m_pAddrTranslator(pCtx, 0x00000000, pCtx->m_State.nPC);
|
|
|
|
pEntry = (uint8*)m_pData + m_pReloc[(nAddress - m_nStart) / 4];
|
|
|
|
#ifdef AMD64
|
|
|
|
nRet = _CCacheBlock_Execute(pEntry, pCtx);
|
|
|
|
#else
|
|
|
|
__asm
|
|
{
|
|
push ebx
|
|
push esi
|
|
push edi
|
|
push ebp
|
|
|
|
mov eax, [pEntry];
|
|
mov ebp, [pCtx];
|
|
call eax
|
|
|
|
pop ebp
|
|
pop edi
|
|
pop esi
|
|
pop ebx
|
|
|
|
mov [nRet], eax;
|
|
}
|
|
|
|
#endif
|
|
|
|
return nRet;
|
|
}
|
|
|
|
void CCacheBlock::Compile(CMIPS* pCtx)
|
|
{
|
|
uint32 i;
|
|
bool nJump;
|
|
|
|
m_nCheckDelayedJump = pCtx->IsBranch(m_nStart - 4);
|
|
|
|
//Check if there's a jump instruction before this one
|
|
for(i = m_nStart; i < m_nEnd; i += 4)
|
|
{
|
|
m_pReloc[(i - m_nStart) / 4] = m_nPtr;
|
|
|
|
m_nProgramCounterChanged = false;
|
|
nJump = m_nCheckDelayedJump;
|
|
|
|
InsertProlog(pCtx);
|
|
pCtx->m_pArch->CompileInstruction(i, this, pCtx, true);
|
|
InsertEpilog(pCtx, nJump);
|
|
|
|
}
|
|
//Check jump out of the block
|
|
Ret(RET_CODE_INTERBLOCKJUMP);
|
|
m_nValid = true;
|
|
printf("CacheBlock: Compiled block [0x%0.8X, 0x%0.8X]. %i byte(s) allocated.\r\n", m_nStart, m_nEnd, m_nSize);
|
|
}
|
|
|
|
void CCacheBlock::InsertProlog(CMIPS* pCtx)
|
|
{
|
|
//add [pCtx->m_State.nPC], 4
|
|
StreamWrite(4, 0x83, (0x01 << 6) | (0x00 << 3) | (0x05), offsetof(CMIPS, m_State.nPC), 4);
|
|
}
|
|
|
|
void CCacheBlock::InsertEpilog(CMIPS* pCtx, bool nDelayJump)
|
|
{
|
|
//Check delay slot (we truly need to do something better about this...)
|
|
if(nDelayJump)
|
|
{
|
|
m_nCheckDelayedJump = false;
|
|
|
|
//mov eax, dword ptr[nDelayedJumpAddr]
|
|
StreamWrite(3, 0x8B, (0x01 << 6) | (0x00 << 3) | (0x05), offsetof(CMIPS, m_State.nDelayedJumpAddr));
|
|
|
|
//cmp eax, 1
|
|
StreamWrite(1, 0x3D);
|
|
StreamWriteWord(MIPS_INVALID_PC);
|
|
|
|
//je +0B
|
|
StreamWrite(2, 0x74, 0x0B);
|
|
|
|
//mov dword ptr[nPC], eax
|
|
StreamWrite(3, 0x89, (0x01 << 6) | (0x00 << 3) | (0x05), offsetof(CMIPS, m_State.nPC));
|
|
|
|
//mov eax, 1
|
|
StreamWrite(1, 0xB8);
|
|
StreamWriteWord(MIPS_INVALID_PC);
|
|
|
|
//mov dword ptr[nDelayedJumpAddr], eax
|
|
StreamWrite(3, 0x89, (0x01 << 6) | (0x00 << 3) | (0x05), offsetof(CMIPS, m_State.nDelayedJumpAddr));
|
|
|
|
//PC Changed
|
|
SetProgramCounterChanged();
|
|
}
|
|
|
|
if(pCtx->m_pTickFunction != NULL)
|
|
{
|
|
//Call the tick function (push a different value than 1 if there's a dead loop in there)
|
|
|
|
#ifdef AMD64
|
|
|
|
//mov ecx, 1
|
|
StreamWrite(1, 0xB9);
|
|
StreamWriteWord(1);
|
|
|
|
//sub esp, 0x08
|
|
StreamWrite(3, 0x83, 0xC0 | (0x05 << 3) | (0x04), 0x08);
|
|
|
|
#else
|
|
|
|
//push 1
|
|
StreamWrite(2, 0x6A, 0x01);
|
|
|
|
#endif
|
|
|
|
//call [TickFunction]
|
|
StreamWrite(2, 0xFF, (0x02 << 6) | (0x02 << 3) | (0x05));
|
|
StreamWriteWord(offsetof(CMIPS, m_pTickFunction));
|
|
|
|
#ifdef AMD64
|
|
|
|
//add esp, 0x08
|
|
StreamWrite(3, 0x83, 0xC0 | (0x00 << 3) | (0x04), 0x08);
|
|
|
|
#else
|
|
|
|
//add esp, 4
|
|
StreamWrite(3, 0x83, 0xC4, 0x04);
|
|
|
|
#endif
|
|
|
|
//test eax, eax
|
|
StreamWrite(2, 0x85, 0xC0);
|
|
|
|
//je +0x06
|
|
StreamWrite(2, 0x74, 0x06);
|
|
|
|
//mov eax, RET_CODE_BREAKPOINT
|
|
StreamWrite(1, 0xB8);
|
|
StreamWriteWord(RET_CODE_BREAKPOINT);
|
|
|
|
//ret
|
|
StreamWrite(1, 0xC3);
|
|
}
|
|
|
|
//////////////////////////////
|
|
//Decrement quota
|
|
|
|
//sub [Quota], 1
|
|
StreamWrite(2, 0x83, (0x02 << 6) | (0x05 << 3) | (0x05));
|
|
StreamWriteWord(offsetof(CMIPS, m_nQuota));
|
|
StreamWriteByte(1);
|
|
|
|
//jne $notdone
|
|
StreamWriteByte(0x75);
|
|
StreamWriteByte(0x06);
|
|
|
|
//mov eax, nCode
|
|
StreamWriteByte(0xB8);
|
|
StreamWriteWord(RET_CODE_QUOTADONE);
|
|
|
|
//ret (stack unwinding?)
|
|
StreamWriteByte(0xC3);
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
//Take the jump
|
|
if(m_nProgramCounterChanged)
|
|
{
|
|
SynchornizePC(pCtx);
|
|
}
|
|
|
|
}
|
|
|
|
void CCacheBlock::SynchornizePC(CMIPS* pCtx)
|
|
{
|
|
//mov eax, dword ptr[nPC]
|
|
StreamWrite(3, 0x8B, (0x01 << 6) | (0x00 << 3) | (0x05), offsetof(CMIPS, m_State.nPC));
|
|
|
|
//sub eax, m_nStart
|
|
StreamWrite(1, 0x2D);
|
|
StreamWriteWord(m_nStart);
|
|
|
|
//jns +0x06
|
|
StreamWrite(2, 0x79, 0x06);
|
|
|
|
//mov eax, RET_CODE_INTERBLOCKJUMP
|
|
StreamWrite(1, 0xB8);
|
|
StreamWriteWord(RET_CODE_INTERBLOCKJUMP);
|
|
|
|
//ret
|
|
StreamWrite(1, 0xC3);
|
|
|
|
//cmp eax, m_nSize
|
|
StreamWrite(1, 0x3D);
|
|
StreamWriteWord(m_nEnd - m_nStart);
|
|
|
|
//jb +0x06
|
|
StreamWrite(2, 0x72, 0x06);
|
|
|
|
//mov eax, RET_CODE_INTERBLOCKJUMP
|
|
StreamWrite(1, 0xB8);
|
|
StreamWriteWord(RET_CODE_INTERBLOCKJUMP);
|
|
|
|
//ret
|
|
StreamWrite(1, 0xC3);
|
|
|
|
//mov ebx, m_nReloc (64-BITS : Potentially dangerous!)
|
|
StreamWrite(1, 0xBB);
|
|
StreamWriteWord((uint32)((uint8*)(m_pReloc) - (uint8*)0));
|
|
|
|
//mov eax, [ebx + eax]
|
|
StreamWrite(3, 0x8B, 0x00 | (0x00 << 3) | (0x04), 0x03);
|
|
|
|
//add eax, m_pData (64-BITS : Potentially dangerous!)
|
|
StreamWrite(1, 0x05);
|
|
StreamWriteWord((uint32)((uint8*)(m_pData) - (uint8*)0));
|
|
|
|
//jmp eax
|
|
StreamWrite(2, 0xFF, 0xE0);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//Stream Fonction Implementation
|
|
///////////////////////////////////////////////////////////
|
|
|
|
void CCacheBlock::StreamWriteByte(uint8 nByte)
|
|
{
|
|
if(m_nPtr == m_nSize)
|
|
{
|
|
m_nSize += GROWSIZE;
|
|
m_pData = (uint8*)realloc(m_pData, m_nSize);
|
|
}
|
|
m_pData[m_nPtr] = nByte;
|
|
m_nPtr++;
|
|
}
|
|
|
|
void CCacheBlock::StreamWriteWord(uint32 nWord)
|
|
{
|
|
unsigned int i;
|
|
for(i = 0; i < 4; i++)
|
|
{
|
|
StreamWriteByte(((uint8*)&nWord)[i]);
|
|
}
|
|
}
|
|
|
|
void CCacheBlock::StreamWrite(unsigned int nCount, ...)
|
|
{
|
|
va_list args;
|
|
uint8 nValue;
|
|
unsigned int i;
|
|
|
|
va_start(args, nCount);
|
|
|
|
for(i = 0; i < nCount; i++)
|
|
{
|
|
nValue = va_arg(args, uint8);
|
|
StreamWriteByte(nValue);
|
|
}
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
unsigned int CCacheBlock::StreamGetSize()
|
|
{
|
|
return m_nPtr;
|
|
}
|
|
|
|
void CCacheBlock::StreamWriteAt(unsigned int nPosition, uint8 nValue)
|
|
{
|
|
m_pData[nPosition] = nValue;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//Intermediate Language Implementation
|
|
///////////////////////////////////////////////////////////
|
|
|
|
void CCacheBlock::PushAddr(void* pAddr)
|
|
{
|
|
//push [pAddr]
|
|
StreamWriteByte(0xFF);
|
|
StreamWriteByte(0x35);
|
|
StreamWriteWord((uint32)((uint8*)pAddr - (uint8*)0));
|
|
}
|
|
|
|
void CCacheBlock::PullAddr(void* pAddr)
|
|
{
|
|
//pop [pAddr]
|
|
StreamWriteByte(0x8F);
|
|
StreamWriteByte(0x05);
|
|
StreamWriteWord((uint32)((uint8*)pAddr - (uint8*)0));
|
|
}
|
|
|
|
void CCacheBlock::PushImm(uint32 nValue)
|
|
{
|
|
//push nValue
|
|
StreamWriteByte(0x68);
|
|
StreamWriteWord(nValue);
|
|
}
|
|
|
|
void CCacheBlock::PushRef(void* pRef)
|
|
{
|
|
PushImm((uint32)((uint8*)pRef - (uint8*)0));
|
|
}
|
|
|
|
void CCacheBlock::SeX8()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//movsx eax, al
|
|
StreamWriteByte(0x0F);
|
|
StreamWriteByte(0xBE);
|
|
StreamWriteByte(0xC0);
|
|
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
}
|
|
|
|
void CCacheBlock::SeX16()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//cwde
|
|
StreamWriteByte(0x98);
|
|
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
}
|
|
|
|
void CCacheBlock::SeX32()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//cdq
|
|
StreamWriteByte(0x99);
|
|
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
|
|
//push edx
|
|
StreamWriteByte(0x52);
|
|
}
|
|
|
|
void CCacheBlock::PullTop()
|
|
{
|
|
Free(1);
|
|
}
|
|
|
|
void CCacheBlock::Free(unsigned int nAmount)
|
|
{
|
|
nAmount *= 4;
|
|
|
|
assert(nAmount < 128);
|
|
|
|
//add esp, 4
|
|
StreamWriteByte(0x83);
|
|
StreamWriteByte(0xC4);
|
|
StreamWriteByte((uint8)nAmount);
|
|
}
|
|
|
|
void CCacheBlock::PushTop()
|
|
{
|
|
//push [esp]
|
|
StreamWriteByte(0xFF);
|
|
StreamWriteByte(0x34);
|
|
StreamWriteByte(0x24);
|
|
}
|
|
|
|
void CCacheBlock::PushValueAt(unsigned int nAddress)
|
|
{
|
|
nAddress *= 4;
|
|
|
|
assert(nAddress < 128);
|
|
|
|
//push [esp + nAddress];
|
|
StreamWriteByte(0xFF);
|
|
StreamWriteByte(0x74);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte((uint8)nAddress);
|
|
}
|
|
|
|
void CCacheBlock::Lookup(uint32* pTable)
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//mov ebx, $pTable
|
|
StreamWriteByte(0xBB);
|
|
StreamWriteWord((uint32)((uint8*)pTable - (uint8*)0));
|
|
|
|
//mov eax, [eax * 4 + ebx]
|
|
StreamWriteByte(0x8B);
|
|
StreamWriteByte(0x04);
|
|
StreamWriteByte(0x83);
|
|
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
}
|
|
|
|
void CCacheBlock::Exchange(unsigned int nA1, unsigned int nA2)
|
|
{
|
|
nA1 *= 4;
|
|
nA2 *= 4;
|
|
|
|
assert(nA1 < 128);
|
|
assert(nA2 < 128);
|
|
|
|
//mov eax, [esp + nA1]
|
|
StreamWriteByte(0x8B);
|
|
StreamWriteByte(0x44);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte((uint8)nA1);
|
|
|
|
//xchg eax, [esp + nA2]
|
|
StreamWriteByte(0x87);
|
|
StreamWriteByte(0x44);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte((uint8)nA2);
|
|
|
|
//mov [esp + nA1], eax
|
|
StreamWriteByte(0x89);
|
|
StreamWriteByte(0x44);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte((uint8)nA1);
|
|
}
|
|
|
|
void CCacheBlock::Swap()
|
|
{
|
|
Exchange(0, 1);
|
|
}
|
|
|
|
void CCacheBlock::And()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//and [esp], eax
|
|
StreamWriteByte(0x21);
|
|
StreamWriteByte(0x04);
|
|
StreamWriteByte(0x24);
|
|
}
|
|
|
|
void CCacheBlock::AndImm(uint32 nValue)
|
|
{
|
|
//and [esp], nValue
|
|
StreamWriteByte(0x81);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteWord(nValue);
|
|
}
|
|
|
|
void CCacheBlock::Add()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//add [esp], eax
|
|
StreamWriteByte(0x01);
|
|
StreamWriteByte(0x04);
|
|
StreamWriteByte(0x24);
|
|
}
|
|
|
|
void CCacheBlock::AddC()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//pop ebx
|
|
StreamWriteByte(0x5B);
|
|
|
|
//push 0
|
|
StreamWriteByte(0x6A);
|
|
StreamWriteByte(0x00);
|
|
|
|
//add ebx, eax
|
|
StreamWriteByte(0x03);
|
|
StreamWriteByte(0xD8);
|
|
|
|
//adc [esp], 0
|
|
StreamWriteByte(0x80);
|
|
StreamWriteByte(0x14);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte(0x00);
|
|
|
|
//push ebx
|
|
StreamWriteByte(0x53);
|
|
}
|
|
|
|
void CCacheBlock::AddImm(uint32 nValue)
|
|
{
|
|
if(nValue == 0) return;
|
|
|
|
//add [esp], nValue
|
|
StreamWriteByte(0x81);
|
|
StreamWriteByte(0x04);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteWord(nValue);
|
|
}
|
|
|
|
void CCacheBlock::Sub()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//sub [esp], eax
|
|
StreamWriteByte(0x29);
|
|
StreamWriteByte(0x04);
|
|
StreamWriteByte(0x24);
|
|
}
|
|
|
|
void CCacheBlock::SubImm(uint32 nValue)
|
|
{
|
|
//sub [esp], nValue
|
|
StreamWriteByte(0x81);
|
|
StreamWriteByte(0x2C);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteWord(nValue);
|
|
}
|
|
|
|
void CCacheBlock::SubC()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//pop ebx
|
|
StreamWriteByte(0x5B);
|
|
|
|
//push 0
|
|
StreamWriteByte(0x6A);
|
|
StreamWriteByte(0x00);
|
|
|
|
//sub ebx, eax
|
|
StreamWriteByte(0x2B);
|
|
StreamWriteByte(0xD8);
|
|
|
|
//adc [esp], 0
|
|
StreamWriteByte(0x80);
|
|
StreamWriteByte(0x14);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte(0x00);
|
|
|
|
//push ebx
|
|
StreamWriteByte(0x53);
|
|
}
|
|
|
|
void CCacheBlock::PushConditionBit(JCC_CONDITION nCond)
|
|
{
|
|
switch(nCond)
|
|
{
|
|
case JCC_CONDITION_EQ:
|
|
//je
|
|
StreamWriteByte(0x74);
|
|
break;
|
|
case JCC_CONDITION_NE:
|
|
//jne
|
|
StreamWriteByte(0x75);
|
|
break;
|
|
case JCC_CONDITION_BL:
|
|
//jb
|
|
StreamWriteByte(0x72);
|
|
break;
|
|
case JCC_CONDITION_BE:
|
|
//jbe
|
|
StreamWriteByte(0x76);
|
|
break;
|
|
case JCC_CONDITION_LT:
|
|
//jl
|
|
StreamWriteByte(0x7C);
|
|
break;
|
|
case JCC_CONDITION_LE:
|
|
//jle
|
|
StreamWriteByte(0x7E);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
|
|
//$04 (label for previous jump)
|
|
StreamWriteByte(0x04);
|
|
|
|
//push 0
|
|
StreamWriteByte(0x6A);
|
|
StreamWriteByte(0x00);
|
|
|
|
//jmp $02
|
|
StreamWriteByte(0xEB);
|
|
StreamWriteByte(0x02);
|
|
|
|
//push 1
|
|
StreamWriteByte(0x6A);
|
|
StreamWriteByte(0x01);
|
|
}
|
|
|
|
void CCacheBlock::Cmp(JCC_CONDITION nCond)
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//cmp [esp], eax
|
|
StreamWriteByte(0x39);
|
|
StreamWriteByte(0x04);
|
|
StreamWriteByte(0x24);
|
|
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
PushConditionBit(nCond);
|
|
}
|
|
|
|
void CCacheBlock::Call(void* pFunc, unsigned int nParams, bool nSaveRes)
|
|
{
|
|
/*
|
|
//call [pFunc]
|
|
StreamWrite(2, 0xFF, 0x00 | (0x02 << 3) | (0x05));
|
|
StreamWriteWord((uint32)((uint8*)(pFunc) - (uint8*)0));
|
|
*/
|
|
//mov eax, pFunc
|
|
StreamWriteByte(0xB8);
|
|
StreamWriteWord((uint32)((uint8*)pFunc - (uint8*)0));
|
|
|
|
//call eax
|
|
StreamWriteByte(0xFF);
|
|
StreamWriteByte(0xD0);
|
|
|
|
if(nParams != 0)
|
|
{
|
|
//add esp, [nParams * 4];
|
|
StreamWriteByte(0x83);
|
|
StreamWriteByte(0xC4);
|
|
StreamWriteByte(nParams * 4);
|
|
}
|
|
|
|
if(nSaveRes)
|
|
{
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
}
|
|
}
|
|
|
|
void CCacheBlock::BeginJcc(bool nCond)
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//test eax, eax
|
|
StreamWriteByte(0x85);
|
|
StreamWriteByte(0xC0);
|
|
|
|
if(!nCond)
|
|
{
|
|
//jne $l
|
|
StreamWriteByte(0x75);
|
|
}
|
|
else
|
|
{
|
|
//je $l
|
|
StreamWriteByte(0x74);
|
|
}
|
|
|
|
m_nJccPos = m_nPtr;
|
|
StreamWriteByte(0x00);
|
|
}
|
|
|
|
void CCacheBlock::EndJcc()
|
|
{
|
|
uint8 nDist;
|
|
nDist = (uint8)(m_nPtr - (m_nJccPos + 1));
|
|
m_pData[m_nJccPos] = nDist;
|
|
}
|
|
|
|
void CCacheBlock::Ret(RET_CODE nCode)
|
|
{
|
|
//mov eax, nCode
|
|
StreamWriteByte(0xB8);
|
|
StreamWriteWord(nCode);
|
|
|
|
//ret (stack unwinding?)
|
|
StreamWriteByte(0xC3);
|
|
}
|
|
|
|
void CCacheBlock::Mult()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//pop ebx
|
|
StreamWriteByte(0x5B);
|
|
|
|
//mul ebx
|
|
StreamWriteByte(0xF7);
|
|
StreamWriteByte(0xE3);
|
|
|
|
//push edx
|
|
StreamWriteByte(0x52);
|
|
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
}
|
|
|
|
void CCacheBlock::MultS()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//pop ebx
|
|
StreamWriteByte(0x5B);
|
|
|
|
//imul ebx
|
|
StreamWriteByte(0xF7);
|
|
StreamWriteByte(0xEB);
|
|
|
|
//push edx
|
|
StreamWriteByte(0x52);
|
|
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
}
|
|
|
|
void CCacheBlock::Div()
|
|
{
|
|
//pop ebx
|
|
StreamWriteByte(0x5B);
|
|
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//xor edx, edx
|
|
StreamWriteByte(0x33);
|
|
StreamWriteByte(0xD2);
|
|
|
|
//div ebx
|
|
StreamWriteByte(0xF7);
|
|
StreamWriteByte(0xF3);
|
|
|
|
//push edx
|
|
StreamWriteByte(0x52);
|
|
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
}
|
|
|
|
void CCacheBlock::DivS()
|
|
{
|
|
//pop ebx
|
|
StreamWriteByte(0x5B);
|
|
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//cdq
|
|
StreamWriteByte(0x99);
|
|
|
|
//idiv ebx
|
|
StreamWriteByte(0xF7);
|
|
StreamWriteByte(0xFB);
|
|
|
|
//push edx
|
|
StreamWriteByte(0x52);
|
|
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
}
|
|
|
|
void CCacheBlock::Or()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//or [esp], eax
|
|
StreamWriteByte(0x09);
|
|
StreamWriteByte(0x04);
|
|
StreamWriteByte(0x24);
|
|
}
|
|
|
|
void CCacheBlock::OrImm(uint32 nValue)
|
|
{
|
|
//or [esp], nValue
|
|
StreamWriteByte(0x81);
|
|
StreamWriteByte(0x0C);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteWord(nValue);
|
|
}
|
|
|
|
void CCacheBlock::Xor()
|
|
{
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//xor [esp], eax
|
|
StreamWriteByte(0x31);
|
|
StreamWriteByte(0x04);
|
|
StreamWriteByte(0x24);
|
|
}
|
|
|
|
void CCacheBlock::Not()
|
|
{
|
|
//not [esp]
|
|
StreamWriteByte(0xF7);
|
|
StreamWriteByte(0x14);
|
|
StreamWriteByte(0x24);
|
|
}
|
|
|
|
void CCacheBlock::Sll()
|
|
{
|
|
//pop ecx
|
|
StreamWriteByte(0x59);
|
|
|
|
//shl [esp], cl
|
|
StreamWriteByte(0xD3);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte(0x24);
|
|
}
|
|
|
|
void CCacheBlock::SllImm(uint8 nAmount)
|
|
{
|
|
//shl [esp], nAmount
|
|
StreamWriteByte(0xC1);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte(nAmount);
|
|
}
|
|
|
|
void CCacheBlock::Sll64()
|
|
{
|
|
//pop ecx
|
|
StreamWriteByte(0x59);
|
|
|
|
//pop edx
|
|
StreamWriteByte(0x5A);
|
|
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//test cl, cl
|
|
StreamWriteByte(0x84);
|
|
StreamWriteByte(0xC9);
|
|
|
|
//je $done
|
|
StreamWriteByte(0x74);
|
|
StreamWriteByte(0x20);
|
|
|
|
//cmp cl, 0x40
|
|
StreamWriteByte(0x80);
|
|
StreamWriteByte(0xF9);
|
|
StreamWriteByte(0x40);
|
|
|
|
//jae $zero
|
|
StreamWriteByte(0x73);
|
|
StreamWriteByte(0x17);
|
|
|
|
//cmp cl, 0x20
|
|
StreamWriteByte(0x80);
|
|
StreamWriteByte(0xF9);
|
|
StreamWriteByte(0x20);
|
|
|
|
//jae $more32
|
|
StreamWriteByte(0x73);
|
|
StreamWriteByte(0x07);
|
|
|
|
//shld edx, eax, cl
|
|
StreamWriteByte(0x0F);
|
|
StreamWriteByte(0xA5);
|
|
StreamWriteByte(0xC2);
|
|
|
|
//shl eax, cl
|
|
StreamWriteByte(0xD3);
|
|
StreamWriteByte(0xE0);
|
|
|
|
//jmp $done
|
|
StreamWriteByte(0xEB);
|
|
StreamWriteByte(0x0F);
|
|
|
|
//$more32
|
|
|
|
//mov edx, eax
|
|
StreamWriteByte(0x8B);
|
|
StreamWriteByte(0xD0);
|
|
|
|
//xor eax, eax
|
|
StreamWriteByte(0x33);
|
|
StreamWriteByte(0xC0);
|
|
|
|
//and cl, 0x1F
|
|
StreamWriteByte(0x80);
|
|
StreamWriteByte(0xE1);
|
|
StreamWriteByte(0x1F);
|
|
|
|
//shl edx, cl
|
|
StreamWriteByte(0xD3);
|
|
StreamWriteByte(0xE2);
|
|
|
|
//jmp $done
|
|
StreamWriteByte(0xEB);
|
|
StreamWriteByte(0x04);
|
|
|
|
//$zero
|
|
|
|
//xor eax, eax
|
|
StreamWriteByte(0x33);
|
|
StreamWriteByte(0xC0);
|
|
|
|
//xor edx, edx
|
|
StreamWriteByte(0x33);
|
|
StreamWriteByte(0xD2);
|
|
|
|
//$done
|
|
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
|
|
//push edx
|
|
StreamWriteByte(0x52);
|
|
}
|
|
|
|
void CCacheBlock::Srl()
|
|
{
|
|
//pop ecx
|
|
StreamWriteByte(0x59);
|
|
|
|
//shr [esp], cl
|
|
StreamWriteByte(0xD3);
|
|
StreamWriteByte(0x2C);
|
|
StreamWriteByte(0x24);
|
|
}
|
|
|
|
void CCacheBlock::SrlImm(uint8 nAmount)
|
|
{
|
|
//shr [esp], nAmount
|
|
StreamWriteByte(0xC1);
|
|
StreamWriteByte(0x2C);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte(nAmount);
|
|
}
|
|
|
|
void CCacheBlock::Srl64()
|
|
{
|
|
//pop ecx
|
|
StreamWriteByte(0x59);
|
|
|
|
//pop edx
|
|
StreamWriteByte(0x5A);
|
|
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//test cl, cl
|
|
StreamWriteByte(0x84);
|
|
StreamWriteByte(0xC9);
|
|
|
|
//je $done
|
|
StreamWriteByte(0x74);
|
|
StreamWriteByte(0x20);
|
|
|
|
//cmp cl, 0x40
|
|
StreamWriteByte(0x80);
|
|
StreamWriteByte(0xF9);
|
|
StreamWriteByte(0x40);
|
|
|
|
//jae $zero
|
|
StreamWriteByte(0x73);
|
|
StreamWriteByte(0x17);
|
|
|
|
//cmp cl, 0x20
|
|
StreamWriteByte(0x80);
|
|
StreamWriteByte(0xF9);
|
|
StreamWriteByte(0x20);
|
|
|
|
//jae $more32
|
|
StreamWriteByte(0x73);
|
|
StreamWriteByte(0x07);
|
|
|
|
//shrd eax, edx, cl
|
|
StreamWriteByte(0x0F);
|
|
StreamWriteByte(0xAD);
|
|
StreamWriteByte(0xD0);
|
|
|
|
//shr edx, cl
|
|
StreamWriteByte(0xD3);
|
|
StreamWriteByte(0xEA);
|
|
|
|
//jmp $done
|
|
StreamWriteByte(0xEB);
|
|
StreamWriteByte(0x0F);
|
|
|
|
//$more32
|
|
|
|
//mov eax, edx
|
|
StreamWriteByte(0x8B);
|
|
StreamWriteByte(0xC2);
|
|
|
|
//xor edx, edx
|
|
StreamWriteByte(0x33);
|
|
StreamWriteByte(0xD2);
|
|
|
|
//and cl, 0x1F
|
|
StreamWriteByte(0x80);
|
|
StreamWriteByte(0xE1);
|
|
StreamWriteByte(0x1F);
|
|
|
|
//shr eax, cl
|
|
StreamWriteByte(0xD3);
|
|
StreamWriteByte(0xE8);
|
|
|
|
//jmp $done
|
|
StreamWriteByte(0xEB);
|
|
StreamWriteByte(0x04);
|
|
|
|
//$zero
|
|
|
|
//xor eax, eax
|
|
StreamWriteByte(0x33);
|
|
StreamWriteByte(0xC0);
|
|
|
|
//xor edx, edx
|
|
StreamWriteByte(0x33);
|
|
StreamWriteByte(0xD2);
|
|
|
|
//$done
|
|
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
|
|
//push edx
|
|
StreamWriteByte(0x52);
|
|
|
|
}
|
|
|
|
void CCacheBlock::Sra()
|
|
{
|
|
//pop ecx
|
|
StreamWriteByte(0x59);
|
|
|
|
//sar [esp], cl
|
|
StreamWriteByte(0xD3);
|
|
StreamWriteByte(0x3C);
|
|
StreamWriteByte(0x24);
|
|
}
|
|
|
|
void CCacheBlock::SraImm(uint8 nAmount)
|
|
{
|
|
//sar [esp], nAmount
|
|
StreamWriteByte(0xC1);
|
|
StreamWriteByte(0x3C);
|
|
StreamWriteByte(0x24);
|
|
StreamWriteByte(nAmount);
|
|
}
|
|
|
|
void CCacheBlock::Sra64()
|
|
{
|
|
//pop ecx
|
|
StreamWriteByte(0x59);
|
|
|
|
//pop edx
|
|
StreamWriteByte(0x5A);
|
|
|
|
//pop eax
|
|
StreamWriteByte(0x58);
|
|
|
|
//cmp cl, 0x40
|
|
StreamWrite(3, 0x80, 0xF9, 0x40);
|
|
|
|
//jae $more64
|
|
StreamWrite(2, 0x73, 0x18);
|
|
|
|
//cmp cl, 0x40
|
|
StreamWrite(3, 0x80, 0xF9, 0x20);
|
|
|
|
//jae $more32
|
|
StreamWrite(2, 0x73, 0x07);
|
|
|
|
//shrd eax, edx, cl
|
|
StreamWrite(3, 0x0F, 0xAD, 0xD0);
|
|
|
|
//sar edx, cl
|
|
StreamWrite(2, 0xD3, 0xFA);
|
|
|
|
//jmp $done
|
|
StreamWrite(2, 0xEB, 0x11);
|
|
|
|
//more32:
|
|
|
|
//mov eax, edx
|
|
StreamWrite(2, 0x8B, 0xC2);
|
|
|
|
//sar edx, 0x1F
|
|
StreamWrite(3, 0xC1, 0xFA, 0x1F);
|
|
|
|
//and cl, 0x1F
|
|
StreamWrite(3, 0x80, 0xE1, 0x1F);
|
|
|
|
//sar eax, cl
|
|
StreamWrite(2, 0xD3, 0xF8);
|
|
|
|
//jmp $done
|
|
StreamWrite(2, 0xEB, 0x05);
|
|
|
|
//more64:
|
|
|
|
//sar edx, 0x1F
|
|
StreamWrite(3, 0xC1, 0xFA, 0x1F);
|
|
|
|
//mov eax, edx
|
|
StreamWrite(2, 0x8B, 0xC2);
|
|
/*
|
|
__asm
|
|
{
|
|
cmp cl,64
|
|
jae more64
|
|
|
|
cmp cl, 32
|
|
jae more32
|
|
|
|
shrd eax,edx,cl
|
|
sar edx,cl
|
|
|
|
jmp done
|
|
|
|
more32:
|
|
mov eax,edx
|
|
sar edx,31
|
|
and cl,31
|
|
sar eax,cl
|
|
|
|
jmp done
|
|
|
|
more64:
|
|
sar edx,31
|
|
mov eax,edx
|
|
|
|
done:
|
|
}
|
|
*/
|
|
//push eax
|
|
StreamWriteByte(0x50);
|
|
|
|
//push edx
|
|
StreamWriteByte(0x52);
|
|
}
|
|
|
|
void CCacheBlock::SetDelayedJumpCheck()
|
|
{
|
|
m_nCheckDelayedJump = true;
|
|
}
|
|
|
|
void CCacheBlock::SetProgramCounterChanged()
|
|
{
|
|
m_nProgramCounterChanged = true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//Proxies Implementations
|
|
///////////////////////////////////////////////////////////
|
|
|
|
uint32 CCacheBlock::GetByteProxy(CMIPS* pCtx, uint32 nAddress)
|
|
{
|
|
return (uint32)pCtx->m_pMemoryMap->GetByte(nAddress);
|
|
}
|
|
|
|
uint32 CCacheBlock::GetHalfProxy(CMIPS* pCtx, uint32 nAddress)
|
|
{
|
|
return (uint32)pCtx->m_pMemoryMap->GetHalf(nAddress);
|
|
}
|
|
|
|
uint32 CCacheBlock::GetWordProxy(CMIPS* pCtx, uint32 nAddress)
|
|
{
|
|
return pCtx->m_pMemoryMap->GetWord(nAddress);
|
|
}
|
|
|
|
void CCacheBlock::SetByteProxy(CMIPS* pCtx, uint32 nValue, uint32 nAddress)
|
|
{
|
|
pCtx->m_pMemoryMap->SetByte(nAddress, (uint8)(nValue & 0xFF));
|
|
}
|
|
|
|
void CCacheBlock::SetHalfProxy(CMIPS* pCtx, uint32 nValue, uint32 nAddress)
|
|
{
|
|
pCtx->m_pMemoryMap->SetHalf(nAddress, (uint16)(nValue & 0xFFFF));
|
|
}
|
|
|
|
void CCacheBlock::SetWordProxy(CMIPS* pCtx, uint32 nValue, uint32 nAddress)
|
|
{
|
|
pCtx->m_pMemoryMap->SetWord(nAddress, nValue);
|
|
}
|