PPU Loader: Fix imports/exports in virtual mode

This commit is contained in:
Eladash 2023-08-06 19:47:23 +03:00 committed by Elad Ashkenazi
parent c96f3a877f
commit 506ec0f947
2 changed files with 60 additions and 45 deletions

View File

@ -168,19 +168,19 @@ struct ppu_module
}
template <typename T, typename U> requires requires (const U& obj) { +obj.size() * 0; }
to_be_t<T>& get_ref(U&& addr,
to_be_t<T>& get_ref(U&& addr, u32 index = 0,
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const
{
constexpr usz size_element = std::is_void_v<T> ? 0 : sizeof(std::conditional_t<std::is_void_v<T>, char, T>);
if (auto ptr = get_ptr<T>(addr.addr(), u32{size_element}))
if (auto ptr = get_ptr<T>((addr + index).addr(), u32{size_element}))
{
return *ptr;
}
fmt::throw_exception("get_ref(): Failure! (addr=0x%x)%s", addr.addr(), src_loc{line, col, file, func});
fmt::throw_exception("get_ref(): Failure! (addr=0x%x)%s", (addr + index).addr(), src_loc{line, col, file, func});
return *std::add_pointer_t<to_be_t<T>>{};
}
};

View File

@ -552,7 +552,7 @@ extern const std::unordered_map<u32, std::string_view>& get_exported_function_na
}
// Resolve relocations for variable/function linkage.
static void ppu_patch_refs(std::vector<ppu_reloc>* out_relocs, u32 fref, u32 faddr)
static void ppu_patch_refs(const ppu_module& _module, std::vector<ppu_reloc>* out_relocs, u32 fref, u32 faddr)
{
struct ref_t
{
@ -561,7 +561,7 @@ static void ppu_patch_refs(std::vector<ppu_reloc>* out_relocs, u32 fref, u32 fad
be_t<u32> addend; // Note: Treating it as addend seems to be correct for now, but still unknown if theres more in this variable
};
for (auto ref = vm::ptr<ref_t>::make(fref); ref->type; ref++)
for (const ref_t* ref = &_module.get_ref<ref_t>(fref); ref->type; fref += sizeof(ref_t), ref = &_module.get_ref<ref_t>(fref))
{
if (ref->addend) ppu_loader.warning("**** REF(%u): Addend value(0x%x, 0x%x)", ref->type, ref->addr, ref->addend);
@ -584,28 +584,28 @@ static void ppu_patch_refs(std::vector<ppu_reloc>* out_relocs, u32 fref, u32 fad
{
case 1:
{
const u32 value = vm::_ref<u32>(ref->addr) = rdata;
const u32 value = _module.get_ref<u32>(ref->addr) = rdata;
ppu_loader.trace("**** REF(1): 0x%x <- 0x%x", ref->addr, value);
break;
}
case 4:
{
const u16 value = vm::_ref<u16>(ref->addr) = static_cast<u16>(rdata);
const u16 value = _module.get_ref<u16>(ref->addr) = static_cast<u16>(rdata);
ppu_loader.trace("**** REF(4): 0x%x <- 0x%04x (0x%llx)", ref->addr, value, faddr);
break;
}
case 6:
{
const u16 value = vm::_ref<u16>(ref->addr) = static_cast<u16>(rdata >> 16) + (rdata & 0x8000 ? 1 : 0);
const u16 value = _module.get_ref<u16>(ref->addr) = static_cast<u16>(rdata >> 16) + (rdata & 0x8000 ? 1 : 0);
ppu_loader.trace("**** REF(6): 0x%x <- 0x%04x (0x%llx)", ref->addr, value, faddr);
break;
}
case 57:
{
const u16 value = vm::_ref<ppu_bf_t<be_t<u16>, 0, 14>>(ref->addr) = static_cast<u16>(rdata) >> 2;
const u16 value = _module.get_ref<ppu_bf_t<be_t<u16>, 0, 14>>(ref->addr) = static_cast<u16>(rdata) >> 2;
ppu_loader.trace("**** REF(57): 0x%x <- 0x%04x (0x%llx)", ref->addr, value, faddr);
break;
}
@ -680,7 +680,7 @@ extern bool ppu_register_library_lock(std::string_view libname, bool lock_lib)
}
// Load and register exports; return special exports found (nameless module)
static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 exports_end, bool for_observing_callbacks = false, std::basic_string<bool>* loaded_flags = nullptr)
static auto ppu_load_exports(const ppu_module& _module, ppu_linkage_info* link, u32 exports_start, u32 exports_end, bool for_observing_callbacks = false, std::basic_string<bool>* loaded_flags = nullptr)
{
std::unordered_map<u32, u32> result;
@ -694,7 +694,7 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
for (u32 addr = exports_start; addr < exports_end; unload_index++, addr += lib.size ? lib.size : sizeof(ppu_prx_module_info))
{
std::memcpy(&lib, vm::base(addr), sizeof(lib));
std::memcpy(&lib, &_module.get_ref<ppu_prx_module_info>(addr), sizeof(lib));
const bool is_library = !!(lib.attributes & PRX_EXPORT_LIBRARY_FLAG);
const bool is_management = !is_library && !!(lib.attributes & PRX_EXPORT_PRX_MANAGEMENT_FUNCTIONS_FLAG);
@ -709,12 +709,12 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
// Set special exports
for (u32 i = 0, end = lib.num_func + lib.num_var; i < end; i++)
{
const u32 nid = lib.nids[i];
const u32 addr = lib.addrs[i];
const u32 nid = _module.get_ref<u32>(lib.nids, i);
const u32 addr = _module.get_ref<u32>(lib.addrs, i);
if (i < lib.num_func)
{
ppu_loader.notice("** Special: [%s] at 0x%x [0x%x, 0x%x]", ppu_get_function_name({}, nid), addr, vm::_ref<u32>(addr), vm::_ref<u32>(addr + 4));
ppu_loader.notice("** Special: [%s] at 0x%x [0x%x, 0x%x]", ppu_get_function_name({}, nid), addr, _module.get_ref<u32>(addr), _module.get_ref<u32>(addr + 4));
}
else
{
@ -738,7 +738,7 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
continue;
}
const std::string module_name(lib.name.get_ptr());
const std::string module_name(&_module.get_ref<const char>(lib.name));
if (unload_exports)
{
@ -782,9 +782,9 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
// Get functions
for (u32 i = 0, end = lib.num_func; i < end; i++)
{
const u32 fnid = fnids[i];
const u32 faddr = faddrs[i];
ppu_loader.notice("**** %s export: [%s] (0x%08x) at 0x%x [at:0x%x]", module_name, ppu_get_function_name(module_name, fnid), fnid, faddr, vm::read32(faddr));
const u32 fnid = _module.get_ref<u32>(fnids, i);
const u32 faddr = _module.get_ref<u32>(faddrs, i);
ppu_loader.notice("**** %s export: [%s] (0x%08x) at 0x%x [at:0x%x]", module_name, ppu_get_function_name(module_name, fnid), fnid, faddr, _module.get_ref<u32>(faddr));
// Function linkage info
auto& flink = mlink.functions[fnid];
@ -811,7 +811,10 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
// Set exported function
flink.export_addr = target - 4;
ppu_form_branch_to_code(vm::read32(faddr), target);
if (auto ptr = _module.get_ptr<u32>(faddr); vm::try_get_addr(ptr).first)
{
ppu_form_branch_to_code(*ptr, target);
}
}
else
{
@ -821,13 +824,13 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
// Fix imports
for (const u32 addr : flink.imports)
{
vm::write32(addr, faddr);
_module.get_ref<u32>(addr) = faddr;
//ppu_loader.warning("Exported function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name);
}
for (const u32 fref : flink.frefss)
{
ppu_patch_refs(nullptr, fref, faddr);
ppu_patch_refs(_module, nullptr, fref, faddr);
}
}
}
@ -839,8 +842,8 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
// Get variables
for (u32 i = 0, end = lib.num_var; i < end; i++)
{
const u32 vnid = vnids[i];
const u32 vaddr = vaddrs[i];
const u32 vnid = _module.get_ref<u32>(vnids, i);
const u32 vaddr = _module.get_ref<u32>(vaddrs, i);
ppu_loader.notice("**** %s export: &[%s] at 0x%x", module_name, ppu_get_variable_name(module_name, vnid), vaddr);
// Variable linkage info
@ -863,7 +866,7 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
// Fix imports
for (const auto vref : vlink.imports)
{
ppu_patch_refs(nullptr, vref, vaddr);
ppu_patch_refs(_module, nullptr, vref, vaddr);
//ppu_loader.warning("Exported variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name);
}
}
@ -873,17 +876,17 @@ static auto ppu_load_exports(ppu_linkage_info* link, u32 exports_start, u32 expo
return result;
}
static auto ppu_load_imports(std::vector<ppu_reloc>& relocs, ppu_linkage_info* link, u32 imports_start, u32 imports_end)
static auto ppu_load_imports(const ppu_module& _module, std::vector<ppu_reloc>& relocs, ppu_linkage_info* link, u32 imports_start, u32 imports_end)
{
std::unordered_map<u32, void*> result;
reader_lock lock(link->mutex);
std::lock_guard lock(link->mutex);
for (u32 addr = imports_start; addr < imports_end;)
{
const auto& lib = vm::_ref<const ppu_prx_module_info>(addr);
const auto& lib = _module.get_ref<const ppu_prx_module_info>(addr);
const std::string module_name(lib.name.get_ptr());
const std::string module_name(&_module.get_ref<const char>(lib.name));
ppu_loader.notice("** Imported module '%s' (ver=0x%x, attr=0x%x, 0x%x, 0x%x) [0x%x]", module_name, lib.version, lib.attributes, lib.unk4, lib.unk5, addr);
@ -903,8 +906,8 @@ static auto ppu_load_imports(std::vector<ppu_reloc>& relocs, ppu_linkage_info* l
for (u32 i = 0, end = lib.num_func; i < end; i++)
{
const u32 fnid = fnids[i];
const u32 fstub = faddrs[i];
const u32 fnid = _module.get_ref<u32>(fnids, i);
const u32 fstub = _module.get_ref<u32>(faddrs, i);
const u32 faddr = (faddrs + i).addr();
ppu_loader.notice("**** %s import: [%s] (0x%08x) -> 0x%x", module_name, ppu_get_function_name(module_name, fnid), fnid, fstub);
@ -920,14 +923,14 @@ static auto ppu_load_imports(std::vector<ppu_reloc>& relocs, ppu_linkage_info* l
const u32 link_addr = flink.export_addr ? flink.export_addr : g_fxo->get<ppu_function_manager>().addr;
// Write import table
vm::write32(faddr, link_addr);
_module.get_ref<u32>(faddr) = link_addr;
// Patch refs if necessary (0x2000 seems to be correct flag indicating the presence of additional info)
if (const u32 frefs = (lib.attributes & 0x2000) ? +fnids[i + lib.num_func] : 0)
if (const u32 frefs = (lib.attributes & 0x2000) ? +_module.get_ref<u32>(fnids, i + lib.num_func) : 0)
{
result.emplace(frefs, &flink);
flink.frefss.emplace(frefs);
ppu_patch_refs(&relocs, frefs, link_addr);
ppu_patch_refs(_module, &relocs, frefs, link_addr);
}
//ppu_loader.warning("Imported function '%s' in module '%s' (0x%x)", ppu_get_function_name(module_name, fnid), module_name, faddr);
@ -938,8 +941,8 @@ static auto ppu_load_imports(std::vector<ppu_reloc>& relocs, ppu_linkage_info* l
for (u32 i = 0, end = lib.num_var; i < end; i++)
{
const u32 vnid = vnids[i];
const u32 vref = vstubs[i];
const u32 vnid = _module.get_ref<u32>(vnids, i);
const u32 vref = _module.get_ref<u32>(vstubs, i);
ppu_loader.notice("**** %s import: &[%s] (ref=*0x%x)", module_name, ppu_get_variable_name(module_name, vnid), vref);
// Variable linkage info
@ -951,7 +954,7 @@ static auto ppu_load_imports(std::vector<ppu_reloc>& relocs, ppu_linkage_info* l
mlink.imported = true;
// Link if available
ppu_patch_refs(&relocs, vref, vlink.export_addr);
ppu_patch_refs(_module, &relocs, vref, vlink.export_addr);
//ppu_loader.warning("Imported variable '%s' in module '%s' (0x%x)", ppu_get_variable_name(module_name, vnid), module_name, vlink.first);
}
@ -968,14 +971,18 @@ void ppu_manual_load_imports_exports(u32 imports_start, u32 imports_size, u32 ex
auto& _main = g_fxo->get<main_ppu_module>();
auto& link = g_fxo->get<ppu_linkage_info>();
ppu_load_exports(&link, exports_start, exports_start + exports_size, false, &loaded_flags);
ppu_module vm_all_fake_module{};
vm_all_fake_module.segs.emplace_back(ppu_segment{0x10000, -0x10000u, 1 /*LOAD*/, 0, -0x1000u, vm::base(0x10000)});
vm_all_fake_module.addr_to_seg_index.emplace(0x10000, 0);
ppu_load_exports(vm_all_fake_module, &link, exports_start, exports_start + exports_size, false, &loaded_flags);
if (!imports_size)
{
return;
}
ppu_load_imports(_main.relocs, &link, imports_start, imports_start + imports_size);
ppu_load_imports(vm_all_fake_module, _main.relocs, &link, imports_start, imports_start + imports_size);
}
// For savestates
@ -1569,10 +1576,14 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, bool virtual_lo
ppu_loader.warning("Library %s (rtoc=0x%x):", lib_name, lib_info->toc);
if (!virtual_load)
ppu_linkage_info dummy{};
prx->specials = ppu_load_exports(*prx, virtual_load ? &dummy : &link, prx->exports_start, prx->exports_end, true);
prx->imports = ppu_load_imports(*prx, prx->relocs, virtual_load ? &dummy : &link, lib_info->imports_start, lib_info->imports_end);
if (virtual_load)
{
prx->specials = ppu_load_exports(&link, prx->exports_start, prx->exports_end, true);
prx->imports = ppu_load_imports(prx->relocs, &link, lib_info->imports_start, lib_info->imports_end);
prx->imports.clear();
}
std::stable_sort(prx->relocs.begin(), prx->relocs.end());
@ -2105,10 +2116,12 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str
return false;
}
ppu_linkage_info dummy{};
if (!virtual_load)
{
ppu_load_exports(&link, proc_prx_param.libent_start, proc_prx_param.libent_end);
ppu_load_imports(_main.relocs, &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
ppu_load_exports(_main, virtual_load ? &dummy : &link, proc_prx_param.libent_start, proc_prx_param.libent_end);
ppu_load_imports(_main, _main.relocs, virtual_load ? &dummy : &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
}
std::stable_sort(_main.relocs.begin(), _main.relocs.end());
@ -2667,10 +2680,12 @@ std::pair<std::shared_ptr<lv2_overlay>, CellError> ppu_load_overlay(const ppu_ex
fmt::throw_exception("Bad magic! (0x%x)", proc_prx_param.magic);
}
ppu_linkage_info dummy{};
if (!virtual_load)
{
ppu_load_exports(&link, proc_prx_param.libent_start, proc_prx_param.libent_end);
ppu_load_imports(ovlm->relocs, &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
ppu_load_exports(*ovlm, virtual_load ? &dummy : &link, proc_prx_param.libent_start, proc_prx_param.libent_end);
ppu_load_imports(*ovlm, ovlm->relocs, virtual_load ? &dummy : &link, proc_prx_param.libstub_start, proc_prx_param.libstub_end);
}
}
break;