SPRX declarations

A payload reaches system libraries through their SPRX modules. The default set covers most needs; anything beyond it is declared per project. This page covers the two project properties, the default set, the interaction with the resolver, and the common overrides.

The two properties

<PropertyGroup>
  <ProsperoKernelSprx>libkernel_sys.sprx</ProsperoKernelSprx>
</PropertyGroup>

<ItemGroup>
  <ProsperoSprx Include="libSceRandom.sprx" />
  <ProsperoSprx Include="libSceUserService.sprx" />
</ItemGroup>
Property What it does
<ProsperoSprx Include="..." /> Adds one SPRX to the payload’s DT_NEEDED list. The RTLD init loads the module and probes it during GOT walking, so a LibraryImport from managed code binds against it at bring-up.
<ProsperoKernelSprx> Replaces the default kernel SPRX (libkernel_web.sprx) with the named one. Only one kernel SPRX at a time; the resolver’s handle 0x2001 always refers to it.

The default set

Every payload gets three SPRXes in DT_NEEDED, in this order:

Slot Module What it publishes
1 libkernel_web.sprx (or libkernel_sys.sprx when overridden) Kernel services: sceKernel*, kernel-side pthread, sysarch, mprotect, notification requests, module loading.
2 libSceLibcInternal.sprx C library: puts, snprintf, memcpy, malloc, POSIX pthread.
3 libSceNet.sprx Socket API: socket, bind, listen, accept, send, recv.

A <ProsperoSprx> entry that names one of the defaults is not duplicated — the item appears once in DT_NEEDED, at the position ProsperoSprx places it. Extras always precede defaults, so an override that changes an SPRX’s order is possible without editing the defaults.

When to override the kernel SPRX

The default libkernel_web.sprx is the browser-context kernel build. Some payload tasks need the system-context build libkernel_sys.sprx instead:

  • Hardware information reads (getModelName, getSerialNumber, temperature sensors) are only in the sys build.
  • getmntinfo — used by a mount-info payload — is only in the sys build.
  • Some sysctl paths are only in the sys build.

Set <ProsperoKernelSprx>libkernel_sys.sprx</ProsperoKernelSprx> in the project. The kernel-side pthread and every sceKernel* still resolves through the same handle; the change is the SPRX file the handle refers to.

When to add an extra SPRX

Add one when the payload’s managed code contains a LibraryImport for a symbol none of the defaults publish:

Extra SPRX Names it publishes
libSceRandom.sprx sceRandomGetRandomNumber.
libScePad.sprx scePadOpen, scePadReadState, scePadReadCurrent.
libSceUserService.sprx sceUserServiceInitialize, sceUserServiceGetInitialUser.
libSceSystemService.sprx sceSystemServiceLaunchWebBrowser, sceSystemServiceLoadExec.
libSceHttp2.sprx sceHttp2* — the HTTP/2 client surface.
libSceSsl.sprx sceSsl* — TLS on top of the HTTP/2 stack.
libSceNotification.sprx sceNotificationSend, sceNotificationSendById — user-visible toasts.

Every one of these is a common pairing with a SharpProspero.Payload.* wrapper class. Check the wrapper’s source or its [LibraryImport] attribute to see the module it targets, and add the matching <ProsperoSprx> entry.

What the linker emits

The linker adds one DT_NEEDED entry per extra plus one per default (deduplicated). The RTLD init in the CRT walks the entries in order, calls sceKernelLoadStartModule on each, and stores the returned handle in a BSS slot for the GOT walk. Handles 0x1 (the payload itself), 0x2 (libSceLibcInternal), and 0x2001 (the kernel SPRX) are populated during bring-up; other extras receive slot indices starting at 0x2002.

A LibraryImport from managed code binds against the extras through the same GLOB_DAT walk. The order does not matter for correctness, only for the resolver cascade shadowing described in Resolver cascade.

Rebuilding after a declaration change

Adding a <ProsperoSprx> or changing <ProsperoKernelSprx> changes DT_NEEDED, which changes the RTLD init sequence, which changes the CRT breadcrumbs. Rebuild:

pwsh build/build-app.ps1 -ProjectPath samples/<sample>/SampleApp.csproj -Payload -Output Folder

Verify with the elf command:

dotnet run --project tools/SharpProspero.Bindings.Generator -- elf --file out/SampleApp.elf --sizes

The dynamic section lists every DT_NEEDED entry the linker emitted.


Copyright © SvenGDK 2026. Distributed under the GPL-3.0-or-later license.

This site uses Just the Docs, a documentation theme for Jekyll.