What Is Aerolib and How It Enables Symbol Resolution in SharpEmu

Aerolib is SharpEmu's built-in singleton symbol catalog that maps PlayStation 5 kernel NIDs (numeric identifiers) to human-readable export names by loading an embedded binary resource at startup.

Aerolib sits at the core of the par274/sharpemu PlayStation 5 emulator, providing the essential translation layer between the console's opaque numeric identifiers and the symbolic names required for host-side syscall implementation. This component enables the emulator to resolve import tables in ELF binaries and JIT-compiled code without hardcoding thousands of string comparisons.

How Aerolib Works in SharpEmu

The Singleton Pattern and Thread Safety

Aerolib implements a thread-safe singleton pattern accessible via Aerolib.Instance. The class implements the ISymbolCatalog interface defined in src/SharpEmu.HLE/ISymbolCatalog.cs, ensuring consistent behavior across the emulator's high-level emulation layer. According to the source code in src/SharpEmu.HLE/Aerolib/Aerolib.cs (lines 10-12), the singleton guarantees that all components share the same immutable symbol table throughout the runtime lifecycle.

Embedded Binary Loading (aerolib.bin)

At construction, Aerolib loads a pre-generated binary resource named aerolib.bin containing all known NID-to-export-name pairs. The LoadFromEmbeddedBinary() method in Aerolib.cs (lines 103-151) parses this binary format and populates two concurrent dictionaries:

  • _byNid – Maps a NID string to a SysAbiSymbol object
  • _byExportName – Maps an export name to the same SysAbiSymbol instance

This dual-index approach enables bidirectional lookups in constant time.

Aerolib Symbol Resolution API

The catalog exposes three primary resolution methods in Aerolib.cs (lines 91-103):

// Lookup by NID (e.g., "Zxa0VhQVTsk")
public bool TryGetByNid(string nid, out SysAbiSymbol symbol)

// Reverse lookup by export name
public bool TryGetByExportName(string exportName, out SysAbiSymbol symbol)

// Convenience method returning the name or original NID if unknown
public string GetName(string nid)

Resolving a Symbol by NID

When the emulator encounters an opaque kernel identifier, it resolves the human-readable name for debugging and implementation dispatch:

if (Aerolib.Instance.TryGetByNid("Zxa0VhQVTsk", out var symbol))
{
    Console.WriteLine($"NID → Export: {symbol.ExportName}"); // Outputs: sceKernelWaitSema
}

Resolving a Symbol by Export Name

For reverse lookups needed by certain loaders or debugging tools:

if (Aerolib.Instance.TryGetByExportName("sceKernelWaitSema", out var symbol))
{
    Console.WriteLine($"Export → NID: {symbol.Nid}"); // Outputs: Zxa0VhQVTsk
}

Bulk Symbol Access

Custom loaders can enumerate the entire catalog:

var nidNames = Aerolib.Instance.GetAllNidNames();
foreach (var kvp in nidNames)
{
    Console.WriteLine($"{kvp.Key} => {kvp.Value}");
}

Integration Points in the SharpEmu Architecture

Aerolib integrates at multiple critical points throughout the emulator's execution pipeline, ensuring symbol resolution is available during runtime initialization, binary loading, and native code execution.

Runtime Initialization (SharpEmuRuntime)

The SharpEmuRuntime class receives a symbol catalog via its constructor. If none is supplied, it falls back to Aerolib.Empty as implemented in src/SharpEmu.Core/Runtime/SharpEmuRuntime.cs (lines 64-66). This dependency injection pattern allows test environments to substitute mock catalogs while production builds use the singleton instance:

var runtime = new SharpEmuRuntime(
    symbolCatalog: Aerolib.Instance,   // Inject the catalog
    // … other dependencies …
);

ELF Loading (SelfLoader)

During the loading of PlayStation 5 ELF binaries (SELF files), the SelfLoader class queries Aerolib for all NID-name pairs to resolve imported symbols. In src/SharpEmu.Core/Loader/SelfLoader.cs (lines 728-730), the loader iterates through the import table and uses the catalog to translate NIDs into callable host functions.

Native Execution Backend (DirectExecutionBackend)

When JIT-compiled imports execute, the native execution backend must resolve symbolic names before invoking host implementations. The DirectExecutionBackend class in src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.cs (lines 1526-1528) and the companion DirectExecutionBackend.Imports.cs (lines 2120-2122) query Aerolib to map runtime NIDs to their corresponding high-level emulation handlers.

Summary

  • Aerolib is a thread-safe singleton implementing ISymbolCatalog that provides bidirectional mapping between PlayStation 5 NIDs and export names.
  • It loads an embedded aerolib.bin resource at startup to populate immutable lookup tables for constant-time resolution.
  • The resolution API includes TryGetByNid, TryGetByExportName, and GetName methods defined in Aerolib.cs.
  • Integration spans SharpEmuRuntime initialization, SelfLoader ELF parsing, and DirectExecutionBackend JIT execution.
  • Unit tests in AerolibCatalogTests.cs validate that known symbols like sceKernelWaitSema (NID: Zxa0VhQVTsk) resolve correctly in both directions.

Frequently Asked Questions

What is a NID in PlayStation 5 development?

A NID (Numeric IDentifier) is a hashed string representation used by the PlayStation 5 system ABI to identify exported kernel functions and libraries. Since the actual export names are not stored in retail binaries, emulators like SharpEmu require a catalog like Aerolib to translate these opaque identifiers (e.g., Zxa0VhQVTsk) into human-readable names (e.g., sceKernelWaitSema) for implementation and debugging.

How does Aerolib handle unknown symbols?

When a NID is not found in the embedded aerolib.bin, the GetName method returns the original NID string as a fallback, while TryGetByNid returns false and sets the out parameter to null. This allows the emulator to continue execution with opaque identifiers rather than crashing, while clearly marking unresolved symbols in logs.

Is Aerolib replaceable with a custom symbol catalog?

Yes. Because SharpEmuRuntime accepts any ISymbolCatalog implementation through its constructor, developers can inject alternative catalogs for specific firmware versions or testing scenarios. The Aerolib.Empty static instance provides a minimal fallback when no catalog is required, though most production use cases require the full singleton instance.

What format does the aerolib.bin file use?

The aerolib.bin file is a pre-compiled binary blob containing serialized NID-string pairs. The LoadFromEmbeddedBinary() method in Aerolib.cs (lines 103-151) implements a custom binary reader that deserializes this data into the concurrent dictionaries at initialization, optimizing for memory efficiency and lookup speed rather than human readability.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →