From 2344d701470e45e75054cc203a46384d2142004d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 21 Oct 2026 08:31:39 +0200 Subject: [PATCH] Loader: Skip the exports of a module whose export table isn't in memory A module cut off before its relocations still has link-time addresses in its module info. Reading its export table through them raised a memory exception, which stops the interpreter (the JITs carry on), so modules/cutrel failed with --cpu=interpreter. Check the range first, as the import side already does for libstub. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/HLE/sceKernelModule.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 52efc6ad8b..14054404d3 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -2050,8 +2050,16 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load module->nm.stub_top = modinfo->libstub; module->nm.stub_size = modinfo->libstubend - modinfo->libstub; - const u32_le *entPos = (u32_le *)Memory::GetPointerOrException(modinfo->libent); - const u32_le *entEnd = (u32_le *)Memory::GetPointerOrException(modinfo->libentend); + const u32_le *entPos = nullptr; + const u32_le *entEnd = nullptr; + // A module that wasn't relocated (cut off before its relocations, see LoadInto) still has + // link-time addresses here. + if (Memory::IsValidRange(modinfo->libent, modinfo->libentend - modinfo->libent)) { + entPos = (const u32_le *)Memory::GetPointerUnchecked(modinfo->libent); + entEnd = (const u32_le *)Memory::GetPointerUnchecked(modinfo->libentend); + } else { + WARN_LOG(Log::Loader, "Garbage libent address %08x or end %08x, no exports", modinfo->libent, modinfo->libentend); + } for (int m = 0; entPos < entEnd; ++m) { const PspLibEntEntry *ent = (const PspLibEntEntry *)entPos;