mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-07 15:31:26 +12:00
PPU: HACK instruction removed
Breakpoints fixed
This commit is contained in:
parent
ddd6ebc58d
commit
3bfe17a14f
20 changed files with 155 additions and 379 deletions
|
@ -13,7 +13,8 @@
|
|||
|
||||
#include "Emu/Cell/lv2/sys_prx.h"
|
||||
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
|
@ -118,6 +119,7 @@ cfg::set_entry g_cfg_load_libs(cfg::root.core, "Load libraries");
|
|||
extern std::string ppu_get_function_name(const std::string& module, u32 fnid);
|
||||
extern std::string ppu_get_variable_name(const std::string& module, u32 vnid);
|
||||
extern void ppu_register_range(u32 addr, u32 size);
|
||||
extern void ppu_register_function_at(u32 addr, u32 size, ppu_function_t ptr);
|
||||
extern void ppu_initialize(const ppu_module& info);
|
||||
extern void ppu_initialize();
|
||||
|
||||
|
@ -125,53 +127,6 @@ extern void sys_initialize_tls(ppu_thread&, u64, u32, u32, u32);
|
|||
|
||||
extern u32 g_ps3_sdk_version;
|
||||
|
||||
// Function lookup table. Not supposed to grow after emulation start.
|
||||
std::vector<ppu_function_t> g_ppu_function_cache;
|
||||
|
||||
// Function name cache in format %s.%s (module name, function name)
|
||||
std::vector<std::string> g_ppu_function_names;
|
||||
|
||||
// Function NID cache for autopause. Autopause tool should probably be rewritten.
|
||||
std::vector<u32> g_ppu_fnid_cache;
|
||||
|
||||
extern std::string ppu_get_module_function_name(u32 index)
|
||||
{
|
||||
if (index < g_ppu_function_names.size())
|
||||
{
|
||||
return g_ppu_function_names[index];
|
||||
}
|
||||
|
||||
return fmt::format(".%u", index);
|
||||
}
|
||||
|
||||
extern void ppu_execute_function(ppu_thread& ppu, u32 index)
|
||||
{
|
||||
if (index < g_ppu_function_cache.size())
|
||||
{
|
||||
// If autopause occures, check_status() will hold the thread until unpaused
|
||||
if (debug::autopause::pause_function(g_ppu_fnid_cache[index])) ppu.test_state();
|
||||
|
||||
if (const auto func = g_ppu_function_cache[index])
|
||||
{
|
||||
func(ppu);
|
||||
LOG_TRACE(HLE, "'%s' finished, r3=0x%llx", ppu_get_module_function_name(index), ppu.gpr[3]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fmt::throw_exception("Function not registered (index %u)" HERE, index);
|
||||
}
|
||||
|
||||
extern ppu_function_t ppu_get_function(u32 index)
|
||||
{
|
||||
if (index < g_ppu_function_cache.size())
|
||||
{
|
||||
return g_ppu_function_cache[index];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern u32 ppu_generate_id(const char* name)
|
||||
{
|
||||
// Symbol name suffix
|
||||
|
@ -224,6 +179,26 @@ const ppu_static_module* ppu_module_manager::get_module(const std::string& name)
|
|||
return found != map.end() ? found->second : nullptr;
|
||||
}
|
||||
|
||||
// Global linkage information
|
||||
struct ppu_linkage_info
|
||||
{
|
||||
struct module
|
||||
{
|
||||
struct info
|
||||
{
|
||||
u32 export_addr = 0;
|
||||
std::set<u32> imports;
|
||||
};
|
||||
|
||||
// FNID -> (export; [imports...])
|
||||
std::map<u32, info> functions;
|
||||
std::map<u32, info> variables;
|
||||
};
|
||||
|
||||
// Module map
|
||||
std::unordered_map<std::string, module> modules;
|
||||
};
|
||||
|
||||
// Initialize static modules.
|
||||
static void ppu_initialize_modules()
|
||||
{
|
||||
|
@ -323,13 +298,6 @@ static void ppu_initialize_modules()
|
|||
&ppu_module_manager::sys_lv2dbg,
|
||||
};
|
||||
|
||||
// Reinitialize function cache
|
||||
g_ppu_function_cache = ppu_function_manager::get();
|
||||
g_ppu_function_names.clear();
|
||||
g_ppu_function_names.resize(g_ppu_function_cache.size());
|
||||
g_ppu_fnid_cache.clear();
|
||||
g_ppu_fnid_cache.resize(g_ppu_function_cache.size());
|
||||
|
||||
// "Use" all the modules for correct linkage
|
||||
for (auto& module : registered)
|
||||
{
|
||||
|
@ -338,8 +306,6 @@ static void ppu_initialize_modules()
|
|||
for (auto& function : module->functions)
|
||||
{
|
||||
LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name);
|
||||
g_ppu_function_names.at(function.second.index) = fmt::format("%s.%s", module->name, function.second.name);
|
||||
g_ppu_fnid_cache.at(function.second.index) = function.first;
|
||||
}
|
||||
|
||||
for (auto& variable : module->variables)
|
||||
|
@ -348,152 +314,31 @@ static void ppu_initialize_modules()
|
|||
variable.second.var->set(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize double-purpose fake OPD array for HLE functions
|
||||
const auto& hle_funcs = ppu_function_manager::get();
|
||||
|
||||
// Allocate memory for the array (must be called after fixed allocations)
|
||||
ppu_function_manager::addr = vm::alloc(::size32(hle_funcs) * 8, vm::main);
|
||||
|
||||
// Initialize as PPU executable code
|
||||
ppu_register_range(ppu_function_manager::addr, ::size32(hle_funcs) * 8);
|
||||
|
||||
// Fill the array (visible data: self address and function index)
|
||||
for (u32 addr = ppu_function_manager::addr, index = 0; index < hle_funcs.size(); addr += 8, index++)
|
||||
{
|
||||
// Function address = current address, RTOC = BLR instruction for the interpreter
|
||||
vm::ps3::write32(addr + 0, addr);
|
||||
vm::ps3::write32(addr + 4, ppu_instructions::BLR());
|
||||
|
||||
// Register the HLE function directly
|
||||
ppu_register_function_at(addr + 0, 4, hle_funcs[index]);
|
||||
}
|
||||
|
||||
// Set memory protection to read-only
|
||||
vm::page_protect(ppu_function_manager::addr, ::align(::size32(hle_funcs) * 8, 0x1000), 0, 0, vm::page_writable);
|
||||
}
|
||||
|
||||
// Detect import stub at specified address and inject HACK instruction with index immediate.
|
||||
static bool ppu_patch_import_stub(u32 addr, u32 index)
|
||||
{
|
||||
const auto data = vm::_ptr<u32>(addr);
|
||||
|
||||
using namespace ppu_instructions;
|
||||
|
||||
// Check various patterns:
|
||||
|
||||
if (vm::check_addr(addr, 32) &&
|
||||
(data[0] & 0xffff0000) == LI(r12, 0) &&
|
||||
(data[1] & 0xffff0000) == ORIS(r12, r12, 0) &&
|
||||
(data[2] & 0xffff0000) == LWZ(r12, r12, 0) &&
|
||||
data[3] == STD(r2, r1, 0x28) &&
|
||||
data[4] == LWZ(r0, r12, 0) &&
|
||||
data[5] == LWZ(r2, r12, 4) &&
|
||||
data[6] == MTCTR(r0) &&
|
||||
data[7] == BCTR())
|
||||
{
|
||||
data[0] = STD(r2, r1, 0x28); // Save RTOC
|
||||
data[1] = HACK(index);
|
||||
data[2] = BLR();
|
||||
std::fill(data + 3, data + 8, NOP());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (vm::check_addr(addr, 12) &&
|
||||
(data[0] & 0xffff0000) == LI(r0, 0) &&
|
||||
(data[1] & 0xffff0000) == ORIS(r0, r0, 0) &&
|
||||
(data[2] & 0xfc000003) == B(0, 0, 0))
|
||||
{
|
||||
const auto sub = vm::cptr<u32>::make(addr + 8 + ((s32)data[2] << 6 >> 8 << 2));
|
||||
|
||||
if (vm::check_addr(sub.addr(), 60) &&
|
||||
sub[0x0] == STDU(r1, r1, -0x80) &&
|
||||
sub[0x1] == STD(r2, r1, 0x70) &&
|
||||
sub[0x2] == MR(r2, r0) &&
|
||||
sub[0x3] == MFLR(r0) &&
|
||||
sub[0x4] == STD(r0, r1, 0x90) &&
|
||||
sub[0x5] == LWZ(r2, r2, 0) &&
|
||||
sub[0x6] == LWZ(r0, r2, 0) &&
|
||||
sub[0x7] == LWZ(r2, r2, 4) &&
|
||||
sub[0x8] == MTCTR(r0) &&
|
||||
sub[0x9] == BCTRL() &&
|
||||
sub[0xa] == LD(r2, r1, 0x70) &&
|
||||
sub[0xb] == ADDI(r1, r1, 0x80) &&
|
||||
sub[0xc] == LD(r0, r1, 0x10) &&
|
||||
sub[0xd] == MTLR(r0) &&
|
||||
sub[0xe] == BLR())
|
||||
{
|
||||
data[0] = HACK(index);
|
||||
data[1] = BLR();
|
||||
data[2] = NOP();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (vm::check_addr(addr, 64) &&
|
||||
data[0x0] == MFLR(r0) &&
|
||||
data[0x1] == STD(r0, r1, 0x10) &&
|
||||
data[0x2] == STDU(r1, r1, -0x80) &&
|
||||
data[0x3] == STD(r2, r1, 0x70) &&
|
||||
(data[0x4] & 0xffff0000) == LI(r2, 0) &&
|
||||
(data[0x5] & 0xffff0000) == ORIS(r2, r2, 0) &&
|
||||
data[0x6] == LWZ(r2, r2, 0) &&
|
||||
data[0x7] == LWZ(r0, r2, 0) &&
|
||||
data[0x8] == LWZ(r2, r2, 4) &&
|
||||
data[0x9] == MTCTR(r0) &&
|
||||
data[0xa] == BCTRL() &&
|
||||
data[0xb] == LD(r2, r1, 0x70) &&
|
||||
data[0xc] == ADDI(r1, r1, 0x80) &&
|
||||
data[0xd] == LD(r0, r1, 0x10) &&
|
||||
data[0xe] == MTLR(r0) &&
|
||||
data[0xf] == BLR())
|
||||
{
|
||||
data[0] = HACK(index);
|
||||
data[1] = BLR();
|
||||
std::fill(data + 2, data + 16, NOP());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (vm::check_addr(addr, 60) &&
|
||||
data[0x0] == MFLR(r0) &&
|
||||
data[0x1] == STD(r0, r1, 0x10) &&
|
||||
data[0x2] == STDU(r1, r1, -0x80) &&
|
||||
data[0x3] == STD(r2, r1, 0x70) &&
|
||||
(data[0x4] & 0xffff0000) == LIS(r12, 0) &&
|
||||
(data[0x5] & 0xffff0000) == LWZ(r12, r12, 0) &&
|
||||
data[0x6] == LWZ(r0, r12, 0) &&
|
||||
data[0x7] == LWZ(r2, r12, 4) &&
|
||||
data[0x8] == MTCTR(r0) &&
|
||||
data[0x9] == BCTRL() &&
|
||||
data[0xa] == LD(r2, r1, 0x70) &&
|
||||
data[0xb] == ADDI(r1, r1, 0x80) &&
|
||||
data[0xc] == LD(r0, r1, 0x10) &&
|
||||
data[0xd] == MTLR(r0) &&
|
||||
data[0xe] == BLR())
|
||||
{
|
||||
data[0] = HACK(index);
|
||||
data[1] = BLR();
|
||||
std::fill(data + 2, data + 15, NOP());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (vm::check_addr(addr, 56) &&
|
||||
(data[0x0] & 0xffff0000) == LI(r12, 0) &&
|
||||
(data[0x1] & 0xffff0000) == ORIS(r12, r12, 0) &&
|
||||
(data[0x2] & 0xffff0000) == LWZ(r12, r12, 0) &&
|
||||
data[0x3] == STD(r2, r1, 0x28) &&
|
||||
data[0x4] == MFLR(r0) &&
|
||||
data[0x5] == STD(r0, r1, 0x20) &&
|
||||
data[0x6] == LWZ(r0, r12, 0) &&
|
||||
data[0x7] == LWZ(r2, r12, 4) &&
|
||||
data[0x8] == MTCTR(r0) &&
|
||||
data[0x9] == BCTRL() &&
|
||||
data[0xa] == LD(r0, r1, 0x20) &&
|
||||
data[0xb] == MTLR(r0) &&
|
||||
data[0xc] == LD(r2, r1, 0x28) &&
|
||||
data[0xd] == BLR())
|
||||
{
|
||||
data[0] = HACK(index);
|
||||
data[1] = BLR();
|
||||
std::fill(data + 2, data + 14, NOP());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Global linkage information
|
||||
struct ppu_linkage_info
|
||||
{
|
||||
struct module
|
||||
{
|
||||
using info_t = std::unordered_map<u32, std::pair<u32, std::unordered_set<u32>>>;
|
||||
|
||||
info_t functions;
|
||||
info_t variables;
|
||||
};
|
||||
|
||||
// Module -> (NID -> (export; [imports...]))
|
||||
std::unordered_map<std::string, module> modules;
|
||||
};
|
||||
|
||||
// Link variable
|
||||
static void ppu_patch_variable_refs(u32 vref, u32 vaddr)
|
||||
{
|
||||
|
@ -605,7 +450,7 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
|||
// Function linkage info
|
||||
auto& flink = link->modules[module_name].functions[fnid];
|
||||
|
||||
if (flink.first)
|
||||
if (flink.export_addr)
|
||||
{
|
||||
LOG_FATAL(LOADER, "Already linked function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name);
|
||||
}
|
||||
|
@ -616,18 +461,32 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
|||
|
||||
if (_sf && (_sf->flags & MFF_FORCED_HLE))
|
||||
{
|
||||
// Inject HACK instruction (TODO: guess function size and analyse B instruction, or reimplement BLR flag for HACK instruction)
|
||||
const auto code = vm::ptr<u32>::make(vm::read32(faddr));
|
||||
code[0] = ppu_instructions::HACK(_sf->index);
|
||||
code[1] = ppu_instructions::BLR();
|
||||
// Inject a branch to the HLE implementation
|
||||
const u32 _entry = vm::read32(faddr);
|
||||
const u32 target = ppu_function_manager::addr + 8 * _sf->index;
|
||||
|
||||
if ((target <= _entry && _entry - target <= 0x2000000) || (target > _entry && target - _entry < 0x2000000))
|
||||
{
|
||||
// Use relative branch
|
||||
vm::write32(_entry, ppu_instructions::B(target - _entry));
|
||||
}
|
||||
else if (target < 0x2000000)
|
||||
{
|
||||
// Use absolute branch if possible
|
||||
vm::write32(_entry, ppu_instructions::B(target, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_FATAL(LOADER, "Failed to patch function at 0x%x (0x%x)", _entry, target);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set exported function
|
||||
flink.first = faddr;
|
||||
flink.export_addr = faddr;
|
||||
|
||||
// Fix imports
|
||||
for (const auto addr : flink.second)
|
||||
for (const u32 addr : flink.imports)
|
||||
{
|
||||
vm::write32(addr, faddr);
|
||||
//LOG_WARNING(LOADER, "Exported function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name);
|
||||
|
@ -649,17 +508,17 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
|||
// Variable linkage info
|
||||
auto& vlink = link->modules[module_name].variables[vnid];
|
||||
|
||||
if (vlink.first)
|
||||
if (vlink.export_addr)
|
||||
{
|
||||
LOG_FATAL(LOADER, "Already linked variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set exported variable
|
||||
vlink.first = vaddr;
|
||||
vlink.export_addr = vaddr;
|
||||
|
||||
// Fix imports
|
||||
for (const auto vref : vlink.second)
|
||||
for (const auto vref : vlink.imports)
|
||||
{
|
||||
ppu_patch_variable_refs(vref, vaddr);
|
||||
//LOG_WARNING(LOADER, "Exported variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name);
|
||||
|
@ -705,10 +564,13 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
|||
auto& flink = link->modules[module_name].functions[fnid];
|
||||
|
||||
// Add new import
|
||||
flink.second.emplace(faddr);
|
||||
flink.imports.emplace(faddr);
|
||||
|
||||
// Link if available
|
||||
if (flink.first) vm::write32(faddr, flink.first);
|
||||
if (flink.export_addr)
|
||||
{
|
||||
vm::write32(faddr, flink.export_addr);
|
||||
}
|
||||
|
||||
//LOG_WARNING(LOADER, "Imported function '%s' in module '%s' (0x%x)", ppu_get_function_name(module_name, fnid), module_name, faddr);
|
||||
}
|
||||
|
@ -726,10 +588,13 @@ static void ppu_load_imports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
|||
auto& vlink = link->modules[module_name].variables[vnid];
|
||||
|
||||
// Add new import
|
||||
vlink.second.emplace(vref);
|
||||
vlink.imports.emplace(vref);
|
||||
|
||||
// Link if available
|
||||
if (vlink.first) ppu_patch_variable_refs(vref, vlink.first);
|
||||
if (vlink.export_addr)
|
||||
{
|
||||
ppu_patch_variable_refs(vref, vlink.export_addr);
|
||||
}
|
||||
|
||||
//LOG_WARNING(LOADER, "Imported variable '%s' in module '%s' (0x%x)", ppu_get_variable_name(module_name, vnid), module_name, vlink.first);
|
||||
}
|
||||
|
@ -940,8 +805,6 @@ std::shared_ptr<lv2_prx> ppu_load_prx(const ppu_prx_object& elf, const std::stri
|
|||
|
||||
void ppu_load_exec(const ppu_exec_object& elf)
|
||||
{
|
||||
ppu_initialize_modules();
|
||||
|
||||
if (g_cfg_hook_ppu_funcs)
|
||||
{
|
||||
LOG_TODO(LOADER, "'Hook static functions' option deactivated");
|
||||
|
@ -996,6 +859,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
|||
}
|
||||
}
|
||||
|
||||
// Load section list, used by the analyser
|
||||
for (const auto& s : elf.shdrs)
|
||||
{
|
||||
LOG_NOTICE(LOADER, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", s.sh_type, s.sh_addr, s.sh_size, s.sh_flags);
|
||||
|
@ -1009,6 +873,9 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
|||
}
|
||||
}
|
||||
|
||||
// Initialize HLE modules
|
||||
ppu_initialize_modules();
|
||||
|
||||
// Load other programs
|
||||
for (auto& prog : elf.progs)
|
||||
{
|
||||
|
@ -1296,55 +1163,31 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
|||
for (auto& entry : module.second.functions)
|
||||
{
|
||||
const u32 fnid = entry.first;
|
||||
const u32 faddr = entry.second.first;
|
||||
const u32 faddr = entry.second.export_addr;
|
||||
|
||||
if (faddr == 0)
|
||||
{
|
||||
const std::string fname = ppu_get_function_name(module.first, fnid);
|
||||
|
||||
// Link HLE implementation if available
|
||||
if (const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr)
|
||||
{
|
||||
// Static function
|
||||
for (auto& import : entry.second.second)
|
||||
{
|
||||
const u32 stub = vm::read32(import);
|
||||
LOG_NOTICE(LOADER, "Linking HLE function '%s' in module '%s' (index %u)", fname, module.first, _sf->index);
|
||||
|
||||
if (!ppu_patch_import_stub(stub, _sf->index))
|
||||
{
|
||||
LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", _sf->name, module.first, stub);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", _sf->name, module.first, stub);
|
||||
}
|
||||
for (const u32 import : entry.second.imports)
|
||||
{
|
||||
LOG_TRACE(LOADER, "** Linked at *0x%x (0x%x)", import, vm::read32(import));
|
||||
vm::write32(import, ppu_function_manager::addr + 8 * _sf->index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
const u32 index = ::size32(g_ppu_function_cache);
|
||||
const std::string& fname = ppu_get_function_name(module.first, fnid);
|
||||
g_ppu_function_cache.emplace_back();
|
||||
g_ppu_function_names.emplace_back(fmt::format("%s.%s", module.first, fname));
|
||||
g_ppu_fnid_cache.emplace_back(fnid);
|
||||
LOG_ERROR(LOADER, "Unknown function '%s' in module '%s'", fname, module.first);
|
||||
|
||||
LOG_ERROR(LOADER, "Unknown function '%s' in module '%s' (index %u)", fname, module.first, index);
|
||||
|
||||
for (auto& import : entry.second.second)
|
||||
for (const u32 import : entry.second.imports)
|
||||
{
|
||||
if (_sm)
|
||||
{
|
||||
const u32 stub = vm::read32(import);
|
||||
|
||||
if (!ppu_patch_import_stub(stub, index))
|
||||
{
|
||||
LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", fname, module.first, stub);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", fname, module.first, stub);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_WARNING(LOADER, "** Not linked at *0x%x", import);
|
||||
LOG_WARNING(LOADER, "** Not linked at *0x%x (0x%x)", import, vm::read32(import));
|
||||
vm::write32(import, ppu_function_manager::addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1353,16 +1196,18 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
|||
for (auto& entry : module.second.variables)
|
||||
{
|
||||
const u32 vnid = entry.first;
|
||||
const u32 vaddr = entry.second.first;
|
||||
const u32 vaddr = entry.second.export_addr;
|
||||
|
||||
if (vaddr == 0)
|
||||
{
|
||||
// Static variable
|
||||
const std::string vname = ppu_get_variable_name(module.first, vnid);
|
||||
|
||||
// Link HLE variable if available
|
||||
if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr)
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Linking HLE variable '%s' in module '%s' (*0x%x):", ppu_get_variable_name(module.first, vnid), module.first, _sv->var->addr());
|
||||
LOG_NOTICE(LOADER, "Linking HLE variable '%s' in module '%s' (*0x%x):", vname, module.first, _sv->var->addr());
|
||||
|
||||
for (auto& ref : entry.second.second)
|
||||
for (const u32 ref : entry.second.imports)
|
||||
{
|
||||
ppu_patch_variable_refs(ref, _sv->var->addr());
|
||||
LOG_NOTICE(LOADER, "** Linked at ref=*0x%x", ref);
|
||||
|
@ -1370,9 +1215,9 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
|||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(LOADER, "Unknown variable '%s' in module '%s'", ppu_get_variable_name(module.first, vnid), module.first);
|
||||
LOG_ERROR(LOADER, "Unknown variable '%s' in module '%s'", vname, module.first);
|
||||
|
||||
for (auto& ref : entry.second.second)
|
||||
for (const u32 ref : entry.second.imports)
|
||||
{
|
||||
LOG_WARNING(LOADER, "** Not linked at ref=*0x%x", ref);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue