diff options
| author | magumagu <magumagu9@gmail.com> | 2015-01-15 18:25:53 -0800 |
|---|---|---|
| committer | magumagu <magumagu9@gmail.com> | 2015-01-15 19:30:59 -0800 |
| commit | c09e41d652ff954e155e2c956ced01b167d4bdc5 (patch) | |
| tree | 1035b1d1026df1c70fc149becac7aa64bd7448ad /Source/Core | |
| parent | 7105e5a8f01120f459300a81841e287fa6bbeec2 (diff) | |
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.
Diffstat (limited to 'Source/Core')
| -rw-r--r-- | Source/Core/Core/PowerPC/JitCommon/JitBackpatch.cpp | 73 |
1 files changed, 41 insertions, 32 deletions
diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.cpp b/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.cpp index 566ce38109..eac028922e 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitBackpatch.cpp @@ -81,6 +81,10 @@ bool Jitx86Base::BackPatch(u32 emAddress, SContext* ctx) exceptionHandler = it2->second; } + // Compute the start and length of the memory operation, including + // any byteswapping. + int totalSize; + u8 *start = codePtr; if (!info.isMemoryWrite) { int bswapNopCount; @@ -92,7 +96,7 @@ bool Jitx86Base::BackPatch(u32 emAddress, SContext* ctx) else bswapNopCount = 2; - int totalSize = info.instructionSize + bswapNopCount; + totalSize = info.instructionSize + bswapNopCount; if (info.operandSize == 2 && !info.byteSwap) { if ((codePtr[totalSize] & 0xF0) == 0x40) @@ -107,35 +111,13 @@ bool Jitx86Base::BackPatch(u32 emAddress, SContext* ctx) info.signExtend = (codePtr[totalSize + 1] & 0x10) != 0; 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 { - // 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) { // The instruction is a MOVBE but it failed so the value is still in little-endian byte order. - start = codePtr; + totalSize = info.instructionSize; } else { @@ -161,18 +143,45 @@ bool Jitx86Base::BackPatch(u32 emAddress, SContext* ctx) break; } 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) + } + + // 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()) { - emitter.NOP(padding); + PanicAlert("BackPatch: no pc entry for address %p", codePtr); + return nullptr; } - ctx->CTX_PC = (u64)start; + + 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; } |
