JIT: Fix the return pointer for backpatch trampolines.

The key change is that for stores less than 5 bytes, the correct
place for the trampoline to return is immediately after the backpatched jump,
not somewhere inside it.
This commit is contained in:
magumagu 2015-01-15 18:25:53 -08:00
parent 7105e5a8f0
commit c09e41d652
1 changed files with 43 additions and 34 deletions

View File

@ -81,6 +81,10 @@ bool Jitx86Base::BackPatch(u32 emAddress, SContext* ctx)
exceptionHandler = it2->second; exceptionHandler = it2->second;
} }
// Compute the start and length of the memory operation, including
// any byteswapping.
int totalSize;
u8 *start = codePtr;
if (!info.isMemoryWrite) if (!info.isMemoryWrite)
{ {
int bswapNopCount; int bswapNopCount;
@ -92,7 +96,7 @@ bool Jitx86Base::BackPatch(u32 emAddress, SContext* ctx)
else else
bswapNopCount = 2; bswapNopCount = 2;
int totalSize = info.instructionSize + bswapNopCount; totalSize = info.instructionSize + bswapNopCount;
if (info.operandSize == 2 && !info.byteSwap) if (info.operandSize == 2 && !info.byteSwap)
{ {
if ((codePtr[totalSize] & 0xF0) == 0x40) if ((codePtr[totalSize] & 0xF0) == 0x40)
@ -107,35 +111,13 @@ bool Jitx86Base::BackPatch(u32 emAddress, SContext* ctx)
info.signExtend = (codePtr[totalSize + 1] & 0x10) != 0; info.signExtend = (codePtr[totalSize + 1] & 0x10) != 0;
totalSize += 3; totalSize += 3;
} }
XEmitter emitter(codePtr);
int padding = totalSize - BACKPATCH_SIZE;
u8* returnPtr = codePtr + 5 + padding;
const u8* trampoline = trampolines.GenerateReadTrampoline(info, registersInUse, exceptionHandler, returnPtr);
emitter.JMP(trampoline, true);
if (padding > 0)
{
emitter.NOP(padding);
}
ctx->CTX_PC = (u64)codePtr;
} }
else else
{ {
// TODO: special case FIFO writes. Also, support 32-bit mode.
auto it3 = pcAtLoc.find(codePtr);
if (it3 == pcAtLoc.end())
{
PanicAlert("BackPatch: no pc entry for address %p", codePtr);
return nullptr;
}
u32 pc = it3->second;
u8 *start;
if (info.byteSwap || info.hasImmediate) if (info.byteSwap || info.hasImmediate)
{ {
// The instruction is a MOVBE but it failed so the value is still in little-endian byte order. // The instruction is a MOVBE but it failed so the value is still in little-endian byte order.
start = codePtr; totalSize = info.instructionSize;
} }
else else
{ {
@ -161,18 +143,45 @@ bool Jitx86Base::BackPatch(u32 emAddress, SContext* ctx)
break; break;
} }
start = codePtr - bswapSize; start = codePtr - bswapSize;
totalSize = info.instructionSize + bswapSize;
} }
XEmitter emitter(start);
ptrdiff_t padding = (codePtr - (start + 5)) + info.instructionSize;
u8* returnPtr = start + 5 + padding;
const u8* trampoline = trampolines.GenerateWriteTrampoline(info, registersInUse, exceptionHandler, returnPtr, pc);
emitter.JMP(trampoline, true);
if (padding > 0)
{
emitter.NOP(padding);
}
ctx->CTX_PC = (u64)start;
} }
// In the trampoline code, we jump back into the block at the beginning
// of the next instruction. The next instruction comes immediately
// after the backpatched operation, or BACKPATCH_SIZE bytes after the start
// of the backpatched operation, whichever comes last. (The JIT inserts NOPs
// into the original code if necessary to ensure there is enough space
// to insert the backpatch jump.)
int padding = totalSize > BACKPATCH_SIZE ? totalSize - BACKPATCH_SIZE : 0;
u8* returnPtr = start + 5 + padding;
// Generate the trampoline.
const u8* trampoline;
if (info.isMemoryWrite)
{
// TODO: special case FIFO writes.
auto it3 = pcAtLoc.find(codePtr);
if (it3 == pcAtLoc.end())
{
PanicAlert("BackPatch: no pc entry for address %p", codePtr);
return nullptr;
}
u32 pc = it3->second;
trampoline = trampolines.GenerateWriteTrampoline(info, registersInUse, exceptionHandler, returnPtr, pc);
}
else
{
trampoline = trampolines.GenerateReadTrampoline(info, registersInUse, exceptionHandler, returnPtr);
}
// Patch the original memory operation.
XEmitter emitter(start);
emitter.JMP(trampoline, true);
for (int i = 0; i < padding; ++i)
emitter.INT3();
ctx->CTX_PC = (u64)start;
return true; return true;
} }