From 1d55e8396571e1daa2dbb83407cfe70fdb5396a7 Mon Sep 17 00:00:00 2001 From: DH Date: Wed, 19 Jul 2023 01:42:23 +0300 Subject: [PATCH] [rpcsx-os] linker: fix module load order --- rpcsx-os/linker.cpp | 7 +- rpcsx-os/linker.hpp | 2 +- rpcsx-os/main.cpp | 10 ++- rpcsx-os/ops.cpp | 196 +++++++++++++++++++++++++++++--------------- 4 files changed, 144 insertions(+), 71 deletions(-) diff --git a/rpcsx-os/linker.cpp b/rpcsx-os/linker.cpp index 8299a1c0d..500008dde 100644 --- a/rpcsx-os/linker.cpp +++ b/rpcsx-os/linker.cpp @@ -798,7 +798,6 @@ Ref rx::linker::loadModule(std::span image, rx::vm::protect(seg.addr, seg.size, rx::vm::kMapProtCpuAll); } - result->id = process->modulesMap.insert(result); result->proc = process; std::printf("Loaded module '%s' from object '%s', id: %u, address: %p - %p\n", @@ -812,8 +811,12 @@ Ref rx::linker::loadModule(std::span image, return result; } -Ref rx::linker::loadModuleFile(const char *path, +Ref rx::linker::loadModuleFile(std::string_view path, orbis::Process *process) { + if (!path.contains('/')) { + return loadModuleByName(path, process); + } + orbis::Ref instance; if (vfs::open(path, kOpenFlagReadOnly, 0, &instance).isError()) { return {}; diff --git a/rpcsx-os/linker.hpp b/rpcsx-os/linker.hpp index 5f6fcaa52..a051008fc 100644 --- a/rpcsx-os/linker.hpp +++ b/rpcsx-os/linker.hpp @@ -77,7 +77,7 @@ void override(std::string originalModuleName, std::filesystem::path replacedModulePath); orbis::Ref loadModule(std::span image, orbis::Process *process); -orbis::Ref loadModuleFile(const char *path, +orbis::Ref loadModuleFile(std::string_view path, orbis::Process *process); orbis::Ref loadModuleByName(std::string_view name, orbis::Process *process); diff --git a/rpcsx-os/main.cpp b/rpcsx-os/main.cpp index 2254e200e..ce91e8c64 100644 --- a/rpcsx-os/main.cpp +++ b/rpcsx-os/main.cpp @@ -278,6 +278,13 @@ static int ps4Exec(orbis::Process *mainProcess, auto libkernel = rx::linker::loadModuleFile( "/system/common/lib/libkernel_sys.sprx", mainProcess); + if (libkernel == nullptr) { + std::fprintf(stderr, "libkernel not found\n"); + return 1; + } + + libkernel->id = mainProcess->modulesMap.insert(libkernel); + // *reinterpret_cast( // reinterpret_cast(libkernel->base) + 0x6c2e4) = ~0; @@ -502,6 +509,7 @@ int main(int argc, const char *argv[]) { std::abort(); } + executableModule->id = initProcess->modulesMap.insert(executableModule); initProcess->processParam = executableModule->processParam; initProcess->processParamSize = executableModule->processParamSize; @@ -517,8 +525,6 @@ int main(int argc, const char *argv[]) { status = 1; } - // entryPoint(); - // rx::vm::printHostStats(); rx::vm::deinitialize(); rx::thread::deinitialize(); diff --git a/rpcsx-os/ops.cpp b/rpcsx-os/ops.cpp index de5baf240..d12fd4796 100644 --- a/rpcsx-os/ops.cpp +++ b/rpcsx-os/ops.cpp @@ -26,6 +26,94 @@ using namespace orbis; extern "C" void __register_frame(const void *); namespace { +static std::pair> +loadPrx(orbis::Thread *thread, std::string_view name, bool relocate, + std::map> &loadedObjects, + std::map> &loadedModules, + std::string_view expectedName) { + if (auto it = loadedObjects.find(name); it != loadedObjects.end()) { + return {{}, it->second}; + } + + auto module = rx::linker::loadModuleFile(name, thread->tproc); + + if (module == nullptr) { + if (!expectedName.empty()) { + loadedObjects[std::string(expectedName)] = nullptr; + } + + return {ErrorCode::NOENT, {}}; + } + + if (!expectedName.empty() && expectedName != module->soName) { + if (module->soName[0] != '\0') { + std::fprintf(stderr, + "Module name mismatch, expected '%s', loaded '%s' (%s)\n", + std::string(expectedName).c_str(), module->soName, + module->moduleName); + // std::abort(); + } + + std::strncpy(module->soName, std::string(expectedName).c_str(), + sizeof(module->soName)); + if (module->soName[sizeof(module->soName) - 1] != '\0') { + std::fprintf(stderr, "Too big needed name\n"); + std::abort(); + } + } + + std::printf("Loaded '%s'\n", module->soName); + + loadedObjects[module->soName] = module.get(); + loadedModules[module->moduleName] = module.get(); + + for (auto &needed : module->needed) { + auto [result, neededModule] = + loadPrx(thread, needed, relocate, loadedObjects, loadedModules, needed); + + if (result.isError() || neededModule == nullptr) { + std::fprintf(stderr, "Needed '%s' not found\n", needed.c_str()); + } + } + + module->importedModules.reserve(module->neededModules.size()); + + for (auto mod : module->neededModules) { + if (auto it = loadedModules.find(std::string_view(mod.name)); + it != loadedModules.end()) { + module->importedModules.emplace_back(it->second); + continue; + } + + std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n", + mod.name.c_str(), module->soName); + module->importedModules.push_back({}); + } + + if (relocate) { + auto result = module->relocate(thread->tproc); + if (result.isError()) { + return {result, module}; + } + } + + module->id = thread->tproc->modulesMap.insert(module); + return {{}, module}; +} + +static std::pair> +loadPrx(orbis::Thread *thread, std::string_view name, bool relocate) { + std::map> loadedObjects; + std::map> loadedModules; + + for (auto [id, module] : thread->tproc->modulesMap) { + loadedObjects[module->soName] = module; + loadedModules[module->moduleName] = module; + } + + return loadPrx(thread, name, relocate, loadedObjects, loadedModules, {}); +}; + orbis::SysResult mmap(orbis::Thread *thread, orbis::caddr_t addr, orbis::size_t len, orbis::sint prot, orbis::sint flags, orbis::sint fd, orbis::off_t pos) { @@ -378,6 +466,7 @@ orbis::SysResult dynlib_get_obj_member(orbis::Thread *thread, orbis::ModuleHandle handle, orbis::uint64_t index, orbis::ptr> addrp) { + std::lock_guard lock(thread->tproc->mtx); auto module = thread->tproc->modulesMap.get(handle); if (module == nullptr) { @@ -411,6 +500,7 @@ orbis::SysResult dynlib_dlsym(orbis::Thread *thread, orbis::ModuleHandle handle, orbis::ptr symbol, orbis::ptr> addrp) { std::printf("sys_dynlib_dlsym(%u, '%s')\n", (unsigned)handle, symbol); + std::lock_guard lock(thread->tproc->mtx); auto module = thread->tproc->modulesMap.get(handle); if (module == nullptr) { @@ -444,17 +534,24 @@ orbis::SysResult dynlib_do_copy_relocations(orbis::Thread *thread) { // TODO return {}; } + orbis::SysResult dynlib_load_prx(orbis::Thread *thread, orbis::ptr name, orbis::uint64_t arg1, orbis::ptr pHandle, orbis::uint64_t arg3) { std::printf("sys_dynlib_load_prx: %s\n", name); - auto module = rx::linker::loadModuleFile(name, thread->tproc); - thread->tproc->ops->processNeeded(thread); - auto result = module->relocate(thread->tproc); + + std::lock_guard lock(thread->tproc->mtx); + + char _name[256]; + auto errorCode = ureadString(_name, sizeof(_name), name); + if (errorCode != ErrorCode{}) { + return errorCode; + } + + auto [result, module] = loadPrx(thread, _name, true); if (result.isError()) { - thread->tproc->modulesMap.close(module->id); return result; } @@ -583,77 +680,44 @@ orbis::SysResult exit(orbis::Thread *thread, orbis::sint status) { } SysResult processNeeded(Thread *thread) { - while (true) { - std::set> allNeededObjects; - auto proc = thread->tproc; - std::map> loadedModules; - std::map> loadedObjects; + std::map> loadedObjects; + std::map> loadedModules; + std::set allNeeded; - for (auto [id, module] : proc->modulesMap) { - for (const auto &object : module->needed) { - allNeededObjects.emplace(object.begin(), object.end()); - } - - loadedModules[module->moduleName] = module; - loadedObjects[module->soName] = module; + for (auto [id, module] : thread->tproc->modulesMap) { + loadedObjects[module->soName] = module; + loadedModules[module->moduleName] = module; + for (auto &needed : module->needed) { + allNeeded.insert(std::string(needed)); } + } - bool hasLoadedNeeded = false; + for (auto needed : allNeeded) { + auto [result, neededModule] = + loadPrx(thread, needed, false, loadedObjects, loadedModules, needed); - for (auto &needed : allNeededObjects) { - if (auto it = loadedObjects.find(needed); it != loadedObjects.end()) { + if (result.isError() || neededModule == nullptr) { + std::fprintf(stderr, "Needed '%s' not found\n", needed.c_str()); + continue; + } + } + + for (auto [id, module] : thread->tproc->modulesMap) { + module->importedModules.reserve(module->neededModules.size()); + + for (auto mod : module->neededModules) { + if (auto it = loadedModules.find(std::string_view(mod.name)); + it != loadedModules.end()) { + module->importedModules.emplace_back(it->second); continue; } - auto neededModule = rx::linker::loadModuleByName(needed, proc); - - if (neededModule == nullptr) { - std::fprintf(stderr, "Needed '%s' not found\n", needed.c_str()); - continue; - } - - if (neededModule->soName != needed) { - if (neededModule->soName[0] != '\0') { - std::fprintf( - stderr, "Module name mismatch, expected '%s', loaded '%s' (%s)\n", - needed.c_str(), neededModule->soName, neededModule->moduleName); - // std::abort(); - } - - std::strncpy(neededModule->soName, needed.c_str(), - sizeof(neededModule->soName)); - if (neededModule->soName[sizeof(neededModule->soName) - 1] != '\0') { - std::fprintf(stderr, "Too big needed name\n"); - std::abort(); - } - } - - hasLoadedNeeded = true; + std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n", + mod.name.c_str(), module->soName); + module->importedModules.push_back({}); } - if (!hasLoadedNeeded) { - thread->tproc->modulesMap.walk([&loadedModules](ModuleHandle modId, - Module *module) { - // std::printf("Module '%s' has id %u\n", module->name, - // (unsigned)modId); - - module->importedModules.clear(); - module->importedModules.reserve(module->neededModules.size()); - for (auto mod : module->neededModules) { - if (auto it = loadedModules.find(std::string_view(mod.name)); - it != loadedModules.end()) { - module->importedModules.emplace_back(it->second); - continue; - } - - std::fprintf(stderr, "Not found needed module '%s' for object '%s'\n", - mod.name.c_str(), module->soName); - module->importedModules.push_back({}); - } - }); - - break; - } + module->relocate(thread->tproc); } return {};