From d1ddaf9681cf1692cefb16be7e3f13013d847676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 21 Oct 2026 07:58:18 +0200 Subject: [PATCH] Loader: Refuse a PRX cut off before its relocations if it exports a library PMDVIS ships a kcall.prx that ends where its relocation sections begin. On a PSP-1000 (6.61) such a module loads unrelocated if syslib is its only export library, but with another library the load hangs the PSP (pspautotests modules/cutrel and modules/cutrel/kernel, which leave that case out). We loaded it unrelocated, and PMDVIS then crashed on its garbage export table. Now the load fails with 80020148, the error PSPLink's modload gave for that file, and PMDVIS carries on without the ME. Also ModuleMgrForKernel's 6.61 NID for sceKernelUnloadModule, which the kernel test uses. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/ELF/ElfReader.cpp | 17 +++++++++++++++++ Core/HLE/sceKernelModule.cpp | 1 + pspautotests | 2 +- test.py | 2 ++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Core/ELF/ElfReader.cpp b/Core/ELF/ElfReader.cpp index 2fbf5be361..380941562a 100644 --- a/Core/ELF/ElfReader.cpp +++ b/Core/ELF/ElfReader.cpp @@ -585,6 +585,23 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) { bool kernelModule = modInfo ? (modInfo->moduleAttrs & 0x1000) != 0 : false; + // A PRX cut off where its relocation sections start, like PMDVIS's kcall.prx. On a PSP-1000 + // (6.61) it loads unrelocated if syslib is its only export library, from user or kernel mode, but + // with another library the load never returns and the PSP hangs (pspautotests modules/cutrel and + // modules/cutrel/kernel, which leave that case out). Refuse that one instead, with the error + // PSPLink's modload gave for PMDVIS's file, so the program can carry on without it. + const bool exportsLibraries = modInfo && modInfo->libentend - modInfo->libent > 16; // One entry is syslib's. + if (bRelocate && exportsLibraries) { + for (int i = 0; i < GetNumSections(); i++) { + const Elf32_Shdr *s = §ions[i]; + if (s->sh_type == SHT_PSPREL && s->sh_size != 0 && s->sh_offset >= size_) { + loadError_ = StringFromFormat("Relocation section %d starts at %d, past the end of the file (%d bytes)", i, (int)s->sh_offset, (int)size_); + ERROR_LOG(Log::Loader, "%s", loadError_.c_str()); + return SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE; + } + } + } + std::string modName = "ELF"; if (modInfo) { size_t n = strnlen(modInfo->name, 28); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index c87bec6599..52efc6ad8b 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -3749,6 +3749,7 @@ const HLEFunction ModuleMgrForKernel[] = { // 6.60 NIDs. {0x939E4270, &WrapU_CUU, "sceKernelLoadModuleForKernel", 'x', "sxx", HLE_KERNEL_SYSCALL }, {0x3FF74DF1, &WrapU_UUUUU, "sceKernelStartModule", 'v', "xxxxx", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED | HLE_KERNEL_SYSCALL }, + {0x387E3CA9, &WrapU_U, "sceKernelUnloadModule", 'x', "x" , HLE_KERNEL_SYSCALL }, }; void Register_ModuleMgrForUser() { diff --git a/pspautotests b/pspautotests index 66e63ea71c..2bed6f5c3a 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 66e63ea71cb2589cc15435e5949a075cf81e4961 +Subproject commit 2bed6f5c3a62e9e6c704c2697b1b2c986aafe367 diff --git a/test.py b/test.py index fc9e598576..e816220c14 100755 --- a/test.py +++ b/test.py @@ -344,6 +344,8 @@ tests_good = [ "malloc/malloc", "misc/dcache", "misc/deadbeef", + "modules/cutrel/cutrel", + "modules/cutrel/kernel/cutrel", "modules/loadrace/loadrace", "modules/startoptions/startoptions", "modules/unresolved/unresolved",