mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
cross-vendor TLS fix: 0x66 prefixes are forced into 64bit call on AMD
This commit is contained in:
+7
-6
@@ -69,21 +69,22 @@ struct Call9 {
|
|||||||
template <class Handler>
|
template <class Handler>
|
||||||
void SetFunc(Handler func) {
|
void SetFunc(Handler func) {
|
||||||
auto func_addr = reinterpret_cast<int64_t>(reinterpret_cast<void*>(func));
|
auto func_addr = reinterpret_cast<int64_t>(reinterpret_cast<void*>(func));
|
||||||
auto rip_addr = reinterpret_cast<int64_t>(&code[5]);
|
auto rip_addr = reinterpret_cast<int64_t>(&code[6]);
|
||||||
auto offset64 = func_addr - rip_addr;
|
auto offset64 = func_addr - rip_addr;
|
||||||
auto offset32 = static_cast<uint32_t>(static_cast<uint64_t>(offset64) & 0xffffffffu);
|
auto offset32 = static_cast<uint32_t>(static_cast<uint64_t>(offset64) & 0xffffffffu);
|
||||||
|
|
||||||
*reinterpret_cast<uint32_t*>(&code[1]) = offset32;
|
*reinterpret_cast<uint32_t*>(&code[2]) = offset32;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetOutputReg(uint8_t reg) { code[7] = 0xc0u | (reg & 7u); }
|
void SetOutputReg(uint8_t reg) { code[8] = 0xc0u | (reg & 7u); }
|
||||||
|
|
||||||
static uint64_t GetSize() { return 9; }
|
static uint64_t GetSize() { return 9; }
|
||||||
|
|
||||||
// call func
|
// rex.w; call func
|
||||||
// mov rax,rax
|
// mov rax,rax
|
||||||
// nop
|
// REX.W is required because AMD processors honor a retained 0x66 operand-size
|
||||||
uint8_t code[9] = {0xE8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x89, 0xC0, 0x90};
|
// prefix on a near call and would otherwise execute callw.
|
||||||
|
uint8_t code[9] = {0x48, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x89, 0xC0};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TlsRegStub {
|
struct TlsRegStub {
|
||||||
|
|||||||
@@ -1143,7 +1143,8 @@ static void PatchProgram(Program* program, uint64_t address, uint64_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!program->elf->IsShared() && program->tls.handler_vaddr != 0) {
|
if (!program->elf->IsShared() && program->tls.handler_vaddr != 0 &&
|
||||||
|
size >= Jit::Call9::GetSize()) {
|
||||||
// Replace:
|
// Replace:
|
||||||
// 66 66 66
|
// 66 66 66
|
||||||
// mov <reg>, qword ptr fs:[0x00]
|
// mov <reg>, qword ptr fs:[0x00]
|
||||||
@@ -1152,6 +1153,7 @@ static void PatchProgram(Program* program, uint64_t address, uint64_t size) {
|
|||||||
// mov <reg>,rax
|
// mov <reg>,rax
|
||||||
// nop ...
|
// nop ...
|
||||||
const uint8_t tls_pattern[5] = {0x64, 0x48, 0x8B, 0x00, 0x25};
|
const uint8_t tls_pattern[5] = {0x64, 0x48, 0x8B, 0x00, 0x25};
|
||||||
|
const uint8_t zero_displacement[4] = {};
|
||||||
|
|
||||||
EXIT_IF(Jit::Call9::GetSize() != 9);
|
EXIT_IF(Jit::Call9::GetSize() != 9);
|
||||||
|
|
||||||
@@ -1173,14 +1175,15 @@ static void PatchProgram(Program* program, uint64_t address, uint64_t size) {
|
|||||||
const uint8_t modrm = inst_ptr[3];
|
const uint8_t modrm = inst_ptr[3];
|
||||||
if (memcmp(inst_ptr, tls_pattern, 3) == 0 && (modrm & 0xc7u) == 0x04u &&
|
if (memcmp(inst_ptr, tls_pattern, 3) == 0 && (modrm & 0xc7u) == 0x04u &&
|
||||||
inst_ptr[4] == tls_pattern[4] &&
|
inst_ptr[4] == tls_pattern[4] &&
|
||||||
*reinterpret_cast<const uint32_t*>(inst_ptr + 5) == 0) {
|
memcmp(inst_ptr + 5, zero_displacement, sizeof(zero_displacement)) == 0) {
|
||||||
LOGF("Patch tls at addr: [%016" PRIx64 "]\n",
|
LOGF("Patch tls at addr: [%016" PRIx64 "]\n", reinterpret_cast<uint64_t>(inst_ptr));
|
||||||
reinterpret_cast<uint64_t>(inst_ptr));
|
|
||||||
|
|
||||||
const auto reg = (modrm >> 3u) & 7u;
|
const auto reg = (modrm >> 3u) & 7u;
|
||||||
EXIT_NOT_IMPLEMENTED(reg == 4u);
|
EXIT_NOT_IMPLEMENTED(reg == 4u);
|
||||||
|
|
||||||
// A raw scan can encounter a 0x66 in the preceding instruction.
|
// A raw scan can encounter a 0x66 in the preceding instruction, so do not
|
||||||
|
// overwrite it. Call9 starts with REX.W to neutralize genuine 0x66
|
||||||
|
// prefixes on AMD processors (before it could turn E8 into callw 16bit).
|
||||||
auto* code = new (inst_ptr) Jit::Call9;
|
auto* code = new (inst_ptr) Jit::Call9;
|
||||||
code->SetFunc(reg == 0
|
code->SetFunc(reg == 0
|
||||||
? program->tls.handler_vaddr
|
? program->tls.handler_vaddr
|
||||||
|
|||||||
Reference in New Issue
Block a user