D492 -
Retail title modules do not export module_start
measured - 2026-09-03 (three modules, a validated hasher, no match)
D491 left the question of what fills a module's globals. The obvious
remaining answer was the platform's own start convention, and obSCEne
records it as "the strongest remaining hypothesis" in
docs/MODULE-FORMAT.md:
A module for the hardware exports
module_startand a loader calls that, rather than jumping to the ELF entry point.
None of PPSA02664's three shipped modules exports it.
What was checked
orbistoun-cli had no way to hash a name, so this added
one - the hash is this project's own (orbistoun-nid) and
the suffix is a run input rather than a constant (principle 5), so doing
it by hand is not available.
0xcf833c78728aa305 module_start
0x74b7eff1accc902a module_stop
0x2d68465e7b96e57d module_prolog
None of the three appears among the exports of
Il2CppUserAssemblies.prx (247 symbols),
PS5Util.prx, or sce_module/libc.prx.
Which is only worth anything because the tool was checked first
A negative result from an unvalidated tool is not a result. So the hasher was pointed at a name the answer is known for:
memcpy -> 0x7b50e125c4417543
libc.prx exports: 0x7b50e125c4417543 +0x3890 Q3VBxCXhUHs#D#A
It agrees, on a vendor-encoded export, end to end. The negatives above are therefore negatives rather than a spelling mistake.
What it means for the sibling project
obSCEne's hypothesis was formed from two emulators mapping its
module, reporting an entry point, and declining to execute it - which is
exactly what a missing start convention would look like. This does not
disprove it for obSCEne's module, but it removes the
reason to believe it: three retail modules that the platform's own
loader does start carry no such export, so exporting
module_start is not what makes a module startable.
Recorded here and noted in MODULE-FORMAT.md, because it
is evidence obSCEne would otherwise spend a hardware session
collecting.
What is left
The module runs - PPSA02664 executes its code (D489) - so something
reaches it. The candidate this leaves is the executable itself: it calls
Il2CppUserAssemblies' own exported resolver
0x6f8b9da539afc9af 222 times, with names
like il2cpp_init and il2cpp_init_utf16 as the
first argument. That is a module being driven by its caller rather than
started by a loader, and the null at [0x480001f0c330 + 8]
sits inside that path.
Not concluded: nothing here establishes that the resolver is what should have filled the global, only that it is the mechanism actually in use and the one the fault is inside.