PRX loader: Fix libfs_155.sprx loading

Fix relocations' segments referencing when there are "empty" (memsize=0) LOAD segments.
This commit is contained in:
Eladash 2020-12-14 08:03:49 +02:00 committed by Ivan
parent 03ad5c6830
commit 7eb16e13bb
6 changed files with 29 additions and 12 deletions

View file

@ -593,6 +593,8 @@ void ppu_module::analyse(u32 lib_toc, u32 entry)
// Grope for OPD section (TODO: optimization, better constraints) // Grope for OPD section (TODO: optimization, better constraints)
for (const auto& seg : segs) for (const auto& seg : segs)
{ {
if (!seg.addr) continue;
for (vm::cptr<u32> ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++) for (vm::cptr<u32> 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) 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 // Find references indiscriminately
for (const auto& seg : segs) for (const auto& seg : segs)
{ {
if (!seg.addr) continue;
for (vm::cptr<u32> ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++) for (vm::cptr<u32> ptr = vm::cast(seg.addr); ptr.addr() < seg.addr + seg.size; ptr++)
{ {
const u32 value = *ptr; const u32 value = *ptr;
@ -627,6 +631,8 @@ void ppu_module::analyse(u32 lib_toc, u32 entry)
for (const auto& _seg : segs) for (const auto& _seg : segs)
{ {
if (!_seg.addr) continue;
if (value >= _seg.addr && value < _seg.addr + _seg.size) if (value >= _seg.addr && value < _seg.addr + _seg.size)
{ {
addr_heap.emplace(value); addr_heap.emplace(value);

View file

@ -811,6 +811,10 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
{ {
case 0x1: // LOAD case 0x1: // LOAD
{ {
auto& _seg = prx->segs.emplace_back();
_seg.flags = prog.p_flags;
_seg.type = p_type;
if (prog.p_memsz) if (prog.p_memsz)
{ {
const u32 mem_size = ::narrow<u32>(prog.p_memsz); const u32 mem_size = ::narrow<u32>(prog.p_memsz);
@ -840,13 +844,9 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
ppu_register_range(addr, mem_size); ppu_register_range(addr, mem_size);
} }
ppu_segment _seg;
_seg.addr = addr; _seg.addr = addr;
_seg.size = mem_size; _seg.size = mem_size;
_seg.filesz = file_size; _seg.filesz = file_size;
_seg.type = p_type;
_seg.flags = prog.p_flags;
prx->segs.emplace_back(_seg);
} }
break; break;
@ -908,10 +908,22 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
{ {
const auto& rel = reinterpret_cast<const ppu_prx_relocation_info&>(prog.bin[i]); const auto& rel = reinterpret_cast<const ppu_prx_relocation_info&>(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; ppu_reloc _rel;
const u32 raddr = _rel.addr = vm::cast(prx->segs.at(rel.index_addr).addr + rel.offset); const u32 raddr = _rel.addr = vm::cast(prx->segs.at(rel.index_addr).addr + rel.offset);
const u32 rtype = _rel.type = rel.type; 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); prx->relocs.emplace_back(_rel);
switch (rtype) switch (rtype)

View file

@ -2324,9 +2324,10 @@ extern void ppu_initialize(const ppu_module& info)
globals.emplace_back(fmt::format("__cptr%x", suffix), reinterpret_cast<u64>(vm::g_exec_addr)); globals.emplace_back(fmt::format("__cptr%x", suffix), reinterpret_cast<u64>(vm::g_exec_addr));
// Initialize segments for relocations // 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); 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) for (const auto& seg : info.segs)
{ {
if (!seg.addr) continue;
*jit_mod.vars[index++] = seg.addr; *jit_mod.vars[index++] = seg.addr;
} }
} }

View file

@ -70,6 +70,7 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* _module, const ppu_mo
// Create segment variables // Create segment variables
for (const auto& seg : m_info.segs) for (const auto& seg : m_info.segs)
{ {
if (!seg.addr) continue;
auto gv = new GlobalVariable(*_module, GetType<u64>(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__seg%u_%x", m_segs.size(), gsuffix)); auto gv = new GlobalVariable(*_module, GetType<u64>(), true, GlobalValue::ExternalLinkage, 0, fmt::format("__seg%u_%x", m_segs.size(), gsuffix));
gv->setInitializer(ConstantInt::get(GetType<u64>(), seg.addr)); gv->setInitializer(ConstantInt::get(GetType<u64>(), seg.addr));
gv->setExternallyInitialized(true); gv->setExternallyInitialized(true);

View file

@ -750,6 +750,7 @@ error_code _sys_prx_get_module_info(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<
u32 i = 0; u32 i = 0;
for (; i < prx->segs.size() && i < pOpt->info->segments_num; i++) 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].index = i;
pOpt->info->segments[i].base = prx->segs[i].addr; pOpt->info->segments[i].base = prx->segs[i].addr;
pOpt->info->segments[i].filesz = prx->segs[i].filesz; pOpt->info->segments[i].filesz = prx->segs[i].filesz;

View file

@ -1150,11 +1150,6 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
// Check .sprx filename // Check .sprx filename
if (fmt::to_upper(entry.name).ends_with(".SPRX")) if (fmt::to_upper(entry.name).ends_with(".SPRX"))
{ {
if (entry.name == "libfs_155.sprx")
{
continue;
}
// Get full path // Get full path
file_queue.emplace_back(dir_queue[i] + entry.name, 0); file_queue.emplace_back(dir_queue[i] + entry.name, 0);
g_progr_ftotal++; g_progr_ftotal++;