# How SysAbi Exports Are Managed in SharpEmu: A Complete Technical Guide

> Learn how SharpEmu manages SysAbi exports using c# reflection and ModuleManager for efficient PS5 kernel function dispatch. Explore exported function wrappers and metadata.

- Repository: [Berk/sharpemu](https://github.com/par274/sharpemu)
- Tags: deep-dive
- Published: 2026-07-13

---

**SharpEmu manages SysAbi exports through a reflection-based pipeline that uses `SysAbiExportAttribute` to mark C# methods as native PS5 kernel functions, `ModuleManager` to scan assemblies and build concurrent dispatch tables, and `ExportedFunction` wrappers to handle invocation with full metadata.**

SharpEmu is an open-source PlayStation 5 emulator that leverages High-Level Emulation (HLE) to intercept and service system calls from the guest firmware. The project implements a lightweight, attribute-driven architecture to expose native kernel routines to the emulated environment, allowing managed C# code to serve as drop-in replacements for low-level PS5 syscalls.

## The Three Core Components of SysAbi Export Management

### SysAbiExportAttribute: Declaring Native Exports

The foundation of the export system lives in [`src/SharpEmu.HLE/SysAbiExportAttribute.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/SysAbiExportAttribute.cs). This attribute decorates methods that should be exposed to the guest as kernel functions. It captures four critical pieces of metadata: the target library (defaulting to `libKernel`), the function's **NID** (Numeric ID), a human-readable export name, and the **PS5 generation** (Gen4 or Gen5) the export supports.

When applied to a method, the attribute signals that this C# implementation should handle calls to the corresponding native syscall. The method must conform to the delegate signature defined in [`SysAbiFunction.cs`](https://github.com/par274/sharpemu/blob/main/SysAbiFunction.cs): returning `int` and accepting either zero parameters or a single `CpuContext` parameter.

### ModuleManager: Scanning and Registration

The `ModuleManager` class in [`src/SharpEmu.HLE/ModuleManager.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/ModuleManager.cs) acts as the central registry and factory for all exported functions. It performs assembly scanning, signature validation, and dispatch table construction through the following internal workflow:

- **Assembly Scanning**: The `RegisterFromAssembly()` method iterates over every type in a provided assembly, identifying methods bearing `SysAbiExportAttribute`.
- **Metadata Resolution**: For each discovered method, `ResolveExportInfo()` fills in missing NID or export name values from an optional `ISymbolCatalog`. If both identifiers remain unresolved, registration throws a clear exception to prevent ambiguous exports.
- **Signature Validation**: The `ValidateSignature()` method enforces that the method returns `int` and matches the expected parameter layout for the `SysAbiFunction` delegate.
- **Delegate Construction**: Valid methods are wrapped in `SysAbiFunction` delegates and stored in two concurrent dictionaries:
  - `_dispatchTable`: Maps raw NID integers directly to delegates for fast syscall dispatch.
  - `_exportTable`: Maps NIDs to `ExportedFunction` instances containing metadata for debugging and name-based lookups.

### ExportedFunction: The Runtime Wrapper

Defined in [`src/SharpEmu.HLE/ExportedFunction.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/ExportedFunction.cs), this wrapper aggregates the library name, NID, export name, target generation flags, and the underlying delegate. It enables the HLE layer to invoke kernel functions by NID while preserving the contextual metadata needed for logging, debugging, and generation-specific behavior.

## The Registration Pipeline: From Attribute to Dispatch Table

The export registration process follows a strict five-step workflow that transforms attributed C# methods into callable native exports:

1. **Attribute Declaration**: Developers apply `SysAbiExportAttribute` to static methods, specifying the library, NID, and generation. The method signature must match `int MethodName(CpuContext)` or `int MethodName()`.

2. **Assembly Registration**: At emulator startup, the core creates a `ModuleManager` instance and calls `RegisterFromAssembly()` for each HLE module (kernel, graphics, system libraries), passing the target generation to filter conditional exports.

3. **Export Resolution**: The manager calls `ResolveExportInfo()` to populate missing metadata from symbol catalogs, ensuring every export maintains a unique addressable identity.

4. **Dispatch Table Population**: After validation, the system creates a `SysAbiFunction` delegate and populates both `_dispatchTable` (for raw speed) and `_exportTable` (for rich metadata).

5. **Freezing and Pre-compilation**: Once all modules are registered, `Freeze()` locks the manager, runs static constructors, and pre-JIT-compiles every exported method. This prevents CLR fail-fast errors when the guest thread's stack is hijacked during syscall execution.

## Generation Targeting and Conditional Exports

SharpEmu supports multiple PS5 hardware revisions through conditional exports. The `Generation` enum in [`src/SharpEmu.HLE/Generation.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/Generation.cs) defines `Gen4` and `Gen5` as bitflags.

When `RegisterFromAssembly()` processes an assembly, it filters methods based on the `Target` property of the export attribute. A method marked with `Target = Generation.Gen5` will only be registered when initializing for a Gen5 console, allowing the same codebase to support different firmware behaviors without conditional compilation or code duplication.

## Practical Implementation Example

The following example demonstrates declaring a kernel export and registering it with the module manager:

```csharp
using SharpEmu.HLE;

// Declare a kernel export with full metadata
[SysAbiExport(
    LibraryName = "libKernel",
    Nid = "0x2A6F0A0A",
    ExportName = "sceKernelGetProcessId",
    Target = Generation.Gen5)]
public static int GetProcessId(CpuContext ctx)
{
    // Access emulated process state through the CPU context
    int pid = ctx.CurrentProcess.Id;
    ctx.WriteInt32(/* out pointer */, pid);
    return 0; // Syscall success code
}

// Register the containing assembly at emulator startup
var moduleMgr = new ModuleManager();
moduleMgr.RegisterFromAssembly(typeof(GetProcessId).Assembly, Generation.Gen5);

// Invoke from the HLE layer when the guest executes a syscall
int nid = 0x2A6F0A0A;
if (moduleMgr.TryGetExport(nid, out var exported))
{
    int result = exported.Function(cpuContextInstance);
    // Result returned to guest as syscall return value
}

```

After registration completes, the `Freeze()` method ensures all exports are JIT-compiled and ready for thread-safe execution.

## Summary

- **SharpEmu uses an attribute-driven architecture** where `SysAbiExportAttribute` marks C# methods as replacements for PS5 kernel functions in [`src/SharpEmu.HLE/SysAbiExportAttribute.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/SysAbiExportAttribute.cs).

- **The `ModuleManager` handles discovery and validation**, scanning assemblies to build concurrent dispatch tables (`_dispatchTable` and `_exportTable`) in [`src/SharpEmu.HLE/ModuleManager.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/ModuleManager.cs).
- **Generation flags** in [`src/SharpEmu.HLE/Generation.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/Generation.cs) enable conditional exports for specific PS5 hardware revisions without code duplication.
- **The `Freeze()` method** pre-compiles all exports after registration to ensure thread-safe execution during guest syscall handling.
- **The `ExportedFunction` wrapper** in [`src/SharpEmu.HLE/ExportedFunction.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/ExportedFunction.cs) carries metadata and delegates for rich, debuggable invocation.

## Frequently Asked Questions

### What is the purpose of the SysAbiExportAttribute in SharpEmu?

The `SysAbiExportAttribute` serves as a declarative marker that binds a C# method to a specific PS5 kernel function. It stores the library name (typically `libKernel`), the Numeric ID (NID), the export name, and the target generation flags. When applied to methods with valid signatures, it enables the `ModuleManager` to discover and register the method as a high-level emulation target for guest syscalls.

### How does ModuleManager validate export methods before registration?

The `ModuleManager` validates exports through the `ValidateSignature()` method, which enforces that export methods return `int` and accept either no parameters or a single `CpuContext` parameter. This ensures compatibility with the `SysAbiFunction` delegate signature. Additionally, `ResolveExportInfo()` verifies that each export has either a valid NID or export name, preventing ambiguous registrations that could cause dispatch failures.

### What are the differences between _dispatchTable and _exportTable?

The `_dispatchTable` is a concurrent dictionary that maps raw NID integers directly to `SysAbiFunction` delegates, optimized for fast lookup during hot-path syscall execution. The `_exportTable` maps NIDs to `ExportedFunction` instances, which contain rich metadata including library names, export names, and generation flags. While the dispatcher uses the raw table for speed, the export table supports debugging, logging, and name-based lookups.

### Why does SharpEmu pre-compile exports using the Freeze() method?

The `Freeze()` method pre-JIT-compiles all registered exports and warms type initializers after registration completes but before the guest begins execution. This prevents runtime compilation delays and avoids CLR fail-fast errors that could occur if the JIT compiler attempted to generate code while operating on a hijacked guest thread stack during syscall handling.