PSP PRX Relocation and GP/Import/Export Identity
Type: REFERENCE Status: MAINTAINED Scope: PRX segments, PSPREL/PSPREL2 relocation layers, module metadata, GP-relative state, NID stubs, and address identity. Last reviewed: 2026-08-11
PRX translation is a provenance problem before it is a code-generation problem. One value can be a file offset, a segment-relative virtual address, a relocated guest address, a module-relative identity, or a final host pointer. Losing those distinctions makes imports, callbacks, and relocation diagnostics impossible to audit.
Public PRX structure
The PSP Developer Wiki PRX File Format documents the PSP-specific PT_SCE_PSPREL and PT_SCE_PSPREL2 segments, module header fields, segment addresses/sizes, entry and module-info offsets, and BSS size. It explicitly notes that PSPREL2 is compressed and that the page documents the first revision only; that limitation matters for a fail-closed parser.
The PSPDEV PRX module guide provides the exact public build-side relationship between export tables, NIDs, resident data, import stubs, module_start/module_stop, and psp-fixup-imports. The surviving YAPSPD documentation is useful historical context for ELF/PRX sections, but should not override a current source or a contradicted field description.
file bytes -> ELF/PRX segments -> module-relative identity<br> |<br>relocations: HI16/LO16, jump/data, GP-relative, import stubs<br> |<br>relocated guest address -> canonical (module, offset) -> host target
Module info, GP, and NID tables
Keep module info, segment bases, GP value, import/export bounds, and BSS as structured metadata. A .lib.stub record couples a library name, flags/count, entry size, NID table address, and stub code/table address; NID entries and stubs are positional only after the spans and entry sizes pass checked validation. Exports are evidence of an interface, not automatically clean function starts.
$gp is PSP small-data state. It is not the host compiler’s global pointer. A module transition, callback, thread entry, or import call can require a different GP context. Preserve module ownership through the call boundary.
Fail-closed relocation handling
Parse with checked arithmetic: segment index, record count, compressed-stream limits, patch width, target range, HI16/LO16 pairing, and import/export span must all be validated before a write. Keep raw encoded value, relocated guest target, canonical module identity, and host target as separate fields. A malformed or ambiguous record should remain visible as a diagnostic, not be guessed into a function.
Nakagawa’s current importer and code-generation implementation are anchored in tools/imports.py and tools/codegen.py. These commit-pinned links are implementation citations, not claims that every PRX feature is supported by the runtime.
Safe parser tests
Start with synthetic ELF/PRX records: one valid HI16/LO16 pair, one jump relocation, one GP-relative relocation, one import table with a mismatched span, one BSS overflow, and one compressed stream that ends mid-record. Assert rejection before mutation and preserve a diagnostic that names the module-relative identity. Keep retail modules and decrypted bytes out of public artifacts.