From ff4485d8ae6515105dfb6e1ff9c38e326372b5ec Mon Sep 17 00:00:00 2001 From: Eladash Date: Mon, 4 Sep 2023 22:20:23 +0300 Subject: [PATCH] PPU LLVM: Patch unregistered BLRs Fixes "Unregistered PPU Function" in "Jak and Daxter Collection" --- rpcs3/Emu/Cell/PPUThread.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index deba0ece06d9..8f04a4bff1ae 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -4662,6 +4662,9 @@ bool ppu_initialize(const ppu_module& info, bool check_only) #ifdef __APPLE__ pthread_jit_write_protect_np(false); #endif + // Try to patch all single and unregistered BLRs with the same function (TODO: Maybe generalize it into PIC code detection and patching) + ppu_intrp_func_t BLR_func = nullptr; + if (jit && !jit_mod.init) { jit->fin(); @@ -4675,6 +4678,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only) const auto addr = ensure(reinterpret_cast(jit->get(name))); jit_mod.funcs.emplace_back(addr); + if (func.size == 4 & !BLR_func && *info.get_ptr(func.addr) == ppu_instructions::BLR()) + { + BLR_func = addr; + } + ppu_register_function_at(func.addr, 4, addr); if (g_cfg.core.ppu_debug) @@ -4694,6 +4702,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only) const u64 addr = reinterpret_cast(ensure(jit_mod.funcs[index++])); + if (func.size == 4 & !BLR_func && *info.get_ptr(func.addr) == ppu_instructions::BLR()) + { + BLR_func = reinterpret_cast(addr); + } + ppu_register_function_at(func.addr, 4, addr); if (g_cfg.core.ppu_debug) @@ -4703,6 +4716,19 @@ bool ppu_initialize(const ppu_module& info, bool check_only) index = 0; } + if (BLR_func) + { + auto inst_ptr = info.get_ptr(info.segs[0].addr); + + for (u32 addr = info.segs[0].addr; addr < info.segs[0].addr + info.segs[0].size; addr += 4, inst_ptr++) + { + if (*inst_ptr == ppu_instructions::BLR() && (reinterpret_cast(ppu_ref(addr)) << 16 >> 16) == reinterpret_cast(ppu_recompiler_fallback_ghc)) + { + ppu_register_function_at(addr, 4, BLR_func); + } + } + } + return compiled_new; #else fmt::throw_exception("LLVM is not available in this build.");