mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-23 09:03:22 -05:00
sceKernelLoadStartModule discarded its arguments, and the relinker's Linux guest writer synthesized an initialisation trampoline that also cleared the argument registers before jumping to the module entry point, so a converted module always reached its own start-up code with args = 0 and argp = NULL. On PPSA28997 two of the title's own modules validate that parameter block as their first act and dereference it unconditionally: SaveData faults on `mov (%rsi),%eax` with rsi = 0 beside its `cmp $0x10` size checks, and PSN faults the same way at PSN+0x3ee7 with rbx = 0. The Windows branch delivers the block, so identical code reports its parameter-version error and continues instead of faulting. sceKernelLoadStartModule now records the pair before dlopen and clears it afterwards, and the emitted DT_INIT stub reads it through two accessors exported by libkernel. The initialiser is called rather than tail-jumped so its return value can be reported through *res as the PS5 API specifies. The state is thread_local, which makes the handoff per-call: ld.so runs a module's initialiser on the thread that called dlopen. DT_FINI keeps a plain call-through, so unloading neither reads stale arguments nor reports a result. The accessor names use the _nid_no_patch suffix so the NID resolver leaves them alone and a guest import can name them exactly.