Replacing the Console's System Surface

The converted title now has a loader-visible path into native PRX libraries, but a symbol address is only useful if the function behind it behaves closely enough to the PS5-facing contract. This chapter examines AnyPS5's native system surface: how its PRX libraries are built and exposed, what they preserve for title code, and why unsupported states usually fail explicitly. The key judgment is whether an API is implemented, merely lifecycle-compatible, deliberately limited, or outside the supported boundary.

A native PRX is a behavioral boundary

AnyPS5's PRX tree is organized around responsibilities that title code expects from the console: libc and libkernel services, threading, files, memory, dialogs, networking, audio, media, input, graphics, and other system-facing libraries. The build system links most libraries to libkernel and libc, builds them as shared libraries with the target platform's toolchain, and then produces patched .prx outputs whose exports are renamed into the NID contract. This creates the native provider that the title's converted import metadata can reach.

The important word is “provider.” A PRX is not just a bag of export names. It owns state, validates arguments, maps host operations to the expected guest-visible behavior, and decides what happens when the host cannot supply the requested service. A title may rely on initialization order, handle lifetimes, return codes, callbacks, or the contents of an output structure. The native implementation has to preserve the parts of that behavior that the title observes, even when the underlying host mechanism is different.

The build graph makes the ownership relationship explicit. libc supplies a common base; libkernel depends on it and implements kernel-facing behavior; most other system libraries depend on both. The patched-library target is separate from the ordinary compilation target, so a successful C++ build and a successful NID export rewrite are two different facts. The final library that a converted title loads is the target-specific, NID-patched artifact, not merely the unpatched shared object produced halfway through the build.

That distinction matters when a title is built for more than one host. The source implementation is compiled against the project's common library relationships, but the produced .prx must be appropriate for the target operating system and toolchain. The custom libs target exists because the PRX directories are excluded from the ordinary default build; a successful top-level build does not necessarily mean that the refreshed patched system libraries have been produced. The runtime therefore depends on a deliberate second boundary: build the native library, patch its exports, and place the patched target artifact where the converted title's loader path expects it.

The build graph also prevents a title-owned module from being treated as a system replacement. The CMake logic gives libkernel a relationship to libc and links most other PRX libraries to both. That is an implementation dependency among native providers. It is different from the guest-module graph under app0/, where the title's own modules depend on one another. Keeping those graphs separate lets a failure say whether a title module is missing or a native system provider is unavailable.

stateDiagram-v2 [*] --> ImportAvailable ImportAvailable --> LifecycleSupported: call enters PRX ImportAvailable --> ExplicitFailure: export absent or stubbed LifecycleSupported --> Completed: supported operation LifecycleSupported --> OfflineOrInvisible: narrow host path LifecycleSupported --> ExplicitFailure: unsupported state OfflineOrInvisible --> Completed: title needs lifecycle only OfflineOrInvisible --> ExplicitFailure: title needs omitted service Completed --> [*] ExplicitFailure --> [*]

This state model is not a claim that every library follows the same internal state machine. It is a way to distinguish the outcomes that matter at the native boundary. An import can be available while a particular state is unsupported. A narrow no-device or invisible-UI path can be sufficient for one title and inadequate for another.