From 347f6b268d50eeecc75c72a6a476f0be0d45e16c Mon Sep 17 00:00:00 2001 From: panzone <150828896+panzone91@users.noreply.github.com> Date: Tue, 25 Feb 2025 21:58:44 +0100 Subject: [PATCH] libkernel: improve module finding in sceKernelLoadStartModule --- src/core/libraries/kernel/process.cpp | 94 ++++++++++++++++++++------- src/core/linker.cpp | 29 +++++++++ src/core/linker.h | 2 + 3 files changed, 100 insertions(+), 25 deletions(-) diff --git a/src/core/libraries/kernel/process.cpp b/src/core/libraries/kernel/process.cpp index 58628867a..21eefb44c 100644 --- a/src/core/libraries/kernel/process.cpp +++ b/src/core/libraries/kernel/process.cpp @@ -40,36 +40,80 @@ s32 PS4_SYSV_ABI sceKernelLoadStartModule(const char* moduleFileName, size_t arg return ORBIS_KERNEL_ERROR_EINVAL; } + std::string guest_path(moduleFileName); auto* mnt = Common::Singleton::Instance(); - const auto path = mnt->GetHostPath(moduleFileName); - - // Load PRX module and relocate any modules that import it. auto* linker = Common::Singleton::Instance(); - u32 handle = linker->FindByName(path); - if (handle != -1) { - return handle; - } - handle = linker->LoadModule(path, true); - if (handle == -1) { - return ORBIS_KERNEL_ERROR_ESRCH; - } - auto* module = linker->GetModule(handle); - linker->RelocateAnyImports(module); + std::filesystem::path path; + s32 handle; - // If the new module has a TLS image, trigger its load when TlsGetAddr is called. - if (module->tls.image_size != 0) { - linker->AdvanceGenerationCounter(); - } + if(guest_path[0] == '/') { + path = mnt->GetHostPath("/system/common/lib" + guest_path); + handle = linker->LoadAndStartModule(path, args, argp, pRes); + if (handle != -1) { + return handle; + } - // Retrieve and verify proc param according to libkernel. - u64* param = module->GetProcParam(); - ASSERT_MSG(!param || param[0] >= 0x18, "Invalid module param size: {}", param[0]); - s32 ret = module->Start(args, argp, param); - if (pRes) { - *pRes = ret; - } + path = mnt->GetHostPath("/system/priv/lib" + guest_path); + handle = linker->LoadAndStartModule(path, args, argp, pRes); + if (handle != -1) { + return handle; + } - return handle; + path = mnt->GetHostPath(guest_path); + handle = linker->LoadAndStartModule(path, args, argp, pRes); + if (handle != -1) { + return handle; + } + } else { + auto* process_params = linker->GetProcParam(); + if (process_params->sdk_version > 0x3ffffff) { + if (process_params->process_name != nullptr && + strstr(process_params->process_name, "web_core.elf")) { + if (guest_path.contains("libScePigletv2VSH") || + guest_path.contains("libSceSysCore") || + guest_path.contains("libSceVideoCoreServerInterface")) { + path = mnt->GetHostPath(guest_path); + handle = linker->LoadAndStartModule(path, args, argp, pRes); + if (handle != -1) { + return handle; + } + } else { + // loading prohibited + return ORBIS_KERNEL_ERROR_ENOENT; + } + } else { + // loading prohibited + return ORBIS_KERNEL_ERROR_ENOENT; + } + } + if (!guest_path.contains('/')) { + path = mnt->GetHostPath("/app0/" + guest_path); + handle = linker->LoadAndStartModule(path, args, argp, pRes); + if (handle != -1) { + return handle; + } + if ((flags & 0x10000) != 0) { + path = mnt->GetHostPath("/system/priv/lib/" + guest_path); + handle = linker->LoadAndStartModule(path, args, argp, pRes); + if (handle != -1) { + return handle; + } + + path = mnt->GetHostPath("/system/common/lib" + guest_path); + handle = linker->LoadAndStartModule(path, args, argp, pRes); + if (handle != -1) { + return handle; + } + } + } else { + path = mnt->GetHostPath(guest_path); + handle = linker->LoadAndStartModule(path, args, argp, pRes); + if (handle != -1) { + return handle; + } + } + } + return ORBIS_KERNEL_ERROR_ENOENT; } s32 PS4_SYSV_ABI sceKernelDlsym(s32 handle, const char* symbol, void** addrp) { diff --git a/src/core/linker.cpp b/src/core/linker.cpp index 2461edcb2..b9a04fad9 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -139,6 +139,35 @@ s32 Linker::LoadModule(const std::filesystem::path& elf_name, bool is_dynamic) { return m_modules.size() - 1; } +s32 Linker::LoadAndStartModule(const std::filesystem::path& path, size_t args, const void* argp, + int* pRes) { + u32 handle = FindByName(path); + if (handle != -1) { + return handle; + } + handle = LoadModule(path, true); + if (handle == -1) { + return -1; + } + auto* module = GetModule(handle); + RelocateAnyImports(module); + + // If the new module has a TLS image, trigger its load when TlsGetAddr is called. + if (module->tls.image_size != 0) { + AdvanceGenerationCounter(); + } + + // Retrieve and verify proc param according to libkernel. + u64* param = module->GetProcParam(); + ASSERT_MSG(!param || param[0] >= 0x18, "Invalid module param size: {}", param[0]); + s32 ret = module->Start(args, argp, param); + if (pRes) { + *pRes = ret; + } + + return handle; +} + Module* Linker::FindByAddress(VAddr address) { for (auto& module : m_modules) { const VAddr base = module->GetBaseAddress(); diff --git a/src/core/linker.h b/src/core/linker.h index 9c07400c4..516179087 100644 --- a/src/core/linker.h +++ b/src/core/linker.h @@ -144,6 +144,8 @@ public: void FreeTlsForNonPrimaryThread(void* pointer); s32 LoadModule(const std::filesystem::path& elf_name, bool is_dynamic = false); + s32 LoadAndStartModule(const std::filesystem::path& path, size_t args, const void* argp, + int* pRes); Module* FindByAddress(VAddr address); void Relocate(Module* module);