From 7eb16e13bbfb4036bd9f5b4fd218dda2af90bdd0 Mon Sep 17 00:00:00 2001 From: Eladash Date: Mon, 14 Dec 2020 08:03:49 +0200 Subject: [PATCH] PRX loader: Fix libfs_155.sprx loading Fix relocations' segments referencing when there are "empty" (memsize=0) LOAD segments. --- rpcs3/Emu/Cell/PPUAnalyser.cpp | 6 ++++++ rpcs3/Emu/Cell/PPUModule.cpp | 22 +++++++++++++++++----- rpcs3/Emu/Cell/PPUThread.cpp | 6 ++++-- rpcs3/Emu/Cell/PPUTranslator.cpp | 1 + rpcs3/Emu/Cell/lv2/sys_prx.cpp | 1 + rpcs3/Emu/System.cpp | 5 ----- 6 files changed, 29 insertions(+), 12 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUAnalyser.cpp b/rpcs3/Emu/Cell/PPUAnalyser.cpp index 3f61973d9e..905f21dd4d 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -593,6 +593,8 @@ void ppu_module::analyse(u32 lib_toc, u32 entry) // Grope for OPD section (TODO: optimization, better constraints) for (const auto& seg : segs) { + if (!seg.addr) continue; + for (vm::cptr ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++) { if (ptr[0] >= start && ptr[0] < end && ptr[0] % 4 == 0 && ptr[1] == toc) @@ -616,6 +618,8 @@ void ppu_module::analyse(u32 lib_toc, u32 entry) // Find references indiscriminately for (const auto& seg : segs) { + if (!seg.addr) continue; + for (vm::cptr ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++) { const u32 value = *ptr; @@ -627,6 +631,8 @@ void ppu_module::analyse(u32 lib_toc, u32 entry) for (const auto& _seg : segs) { + if (!_seg.addr) continue; + if (value >= _seg.addr && value < _seg.addr + _seg.size) { addr_heap.emplace(value); diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp index 1c0ad56a8b..50e22cf8bf 100644 --- a/rpcs3/Emu/Cell/PPUModule.cpp +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -811,6 +811,10 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, const std::stri { case 0x1: // LOAD { + auto& _seg = prx->segs.emplace_back(); + _seg.flags = prog.p_flags; + _seg.type = p_type; + if (prog.p_memsz) { const u32 mem_size = ::narrow(prog.p_memsz); @@ -840,13 +844,9 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, const std::stri ppu_register_range(addr, mem_size); } - ppu_segment _seg; _seg.addr = addr; _seg.size = mem_size; _seg.filesz = file_size; - _seg.type = p_type; - _seg.flags = prog.p_flags; - prx->segs.emplace_back(_seg); } break; @@ -908,10 +908,22 @@ std::shared_ptr ppu_load_prx(const ppu_prx_object& elf, const std::stri { const auto& rel = reinterpret_cast(prog.bin[i]); + if (rel.offset >= prx->segs.at(rel.index_addr).size) + { + fmt::throw_exception("Relocation offset out of segment memory! (offset=0x%x, index_addr=%u)", rel.offset, rel.index_addr); + } + + const u32 data_base = rel.index_value == 0xFF ? 0 : prx->segs.at(rel.index_value).addr; + + if (rel.index_value != 0xFF && !data_base) + { + fmt::throw_exception("Empty segment has been referenced for relocation data! (reloc_offset=0x%x, index_value=%u)", i, rel.index_value); + } + ppu_reloc _rel; const u32 raddr = _rel.addr = vm::cast(prx->segs.at(rel.index_addr).addr + rel.offset); const u32 rtype = _rel.type = rel.type; - const u64 rdata = _rel.data = rel.index_value == 0xFF ? rel.ptr.addr().value() : prx->segs.at(rel.index_value).addr + rel.ptr.addr(); + const u64 rdata = _rel.data = data_base + rel.ptr.addr(); prx->relocs.emplace_back(_rel); switch (rtype) diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 98b4de0ca5..fae3aeca38 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -2324,9 +2324,10 @@ extern void ppu_initialize(const ppu_module& info) globals.emplace_back(fmt::format("__cptr%x", suffix), reinterpret_cast(vm::g_exec_addr)); // Initialize segments for relocations - for (u32 i = 0; i < info.segs.size(); i++) + for (u32 i = 0, num = 0; i < info.segs.size(); i++) { - globals.emplace_back(fmt::format("__seg%u_%x", i, suffix), info.segs[i].addr); + if (!info.segs[i].addr) continue; + globals.emplace_back(fmt::format("__seg%u_%x", num++, suffix), info.segs[i].addr); } link_workload.emplace_back(obj_name, false); @@ -2490,6 +2491,7 @@ extern void ppu_initialize(const ppu_module& info) for (const auto& seg : info.segs) { + if (!seg.addr) continue; *jit_mod.vars[index++] = seg.addr; } } diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index 3576418ab0..a05b9331dd 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -70,6 +70,7 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* _module, const ppu_mo // Create segment variables for (const auto& seg : m_info.segs) { + if (!seg.addr) continue; auto gv = new GlobalVariable(*_module, GetType(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__seg%u_%x", m_segs.size(), gsuffix)); gv->setInitializer(ConstantInt::get(GetType(), seg.addr)); gv->setExternallyInitialized(true); diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index 8f87f85f6a..146feb15aa 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -750,6 +750,7 @@ error_code _sys_prx_get_module_info(ppu_thread& ppu, u32 id, u64 flags, vm::ptr< u32 i = 0; for (; i < prx->segs.size() && i < pOpt->info->segments_num; i++) { + if (!prx->segs[i].addr) continue; // TODO: Check this pOpt->info->segments[i].index = i; pOpt->info->segments[i].base = prx->segs[i].addr; pOpt->info->segments[i].filesz = prx->segs[i].filesz; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 916f4a4f15..e0ff7af729 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1150,11 +1150,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool // Check .sprx filename if (fmt::to_upper(entry.name).ends_with(".SPRX")) { - if (entry.name == "libfs_155.sprx") - { - continue; - } - // Get full path file_queue.emplace_back(dir_queue[i] + entry.name, 0); g_progr_ftotal++;