# How to Register HLE Modules in SharpEmu: The Complete ModuleManager Workflow

> Learn to register HLE modules in SharpEmu efficiently. Follow the ModuleManager workflow: scan assemblies, create delegates, populate tables, and freeze registration for optimal performance.

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

---

**Registering HLE modules in SharpEmu involves calling `ModuleManager.RegisterFromAssembly()` to scan assemblies for methods marked with `[SysAbiExport]`, creating delegates for each export, populating internal dispatch tables, and finally calling `Freeze()` to lock the registration and warm up the JIT compiler.**

SharpEmu is a PlayStation 5 emulator that relies on High-Level Emulation (HLE) to expose host system functions to guest binaries. The process for registering HLE modules is handled by the `ModuleManager` class in [`src/SharpEmu.HLE/ModuleManager.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/ModuleManager.cs), which discovers annotated methods, builds dispatch tables, and prepares the runtime for safe execution.

## The HLE Registration Pipeline

The registration workflow follows a strict sequence to ensure thread safety and runtime stability. Each phase transforms static C# methods into callable HLE exports that guest code can invoke via NID (Numeric ID) lookups.

### Scanning Assemblies with RegisterFromAssembly

Registration begins with `RegisterFromAssembly(Assembly assembly, Generation generation, ISymbolCatalog? symbolCatalog = null)`. This method first checks `_scannedAssemblies` to deduplicate the pair *(assembly, generation)*, preventing double-scanning. It also verifies that `_isFrozen` is false, throwing an exception if registration occurs after the manager has been sealed.

### Identifying Exports via SysAbiExportAttribute

For every type in the supplied assembly, `RegisterFromAssembly` inspects all methods (public, non-public, static, or instance) using reflection:

```csharp
var exportAttribute = method.GetCustomAttribute<SysAbiExportAttribute>(inherit: false);

```

Only methods adorned with **`[SysAbiExport]`** are considered HLE exports. The attribute defines the library name (e.g., `"sceAudio"`), the NID (numeric identifier), and the export name.

### Resolving Export Metadata

The private `ResolveExportInfo` method constructs an `ExportInfo` structure containing:
- **Library name** (e.g., `"sceAudio"`)
- **NID** (hexadecimal identifier)
- **Export name**
- **Target** (linkage to the symbol catalog if supplied)

If resolution fails due to missing symbols, the method is skipped and `registeredCount` is not incremented.

### Creating Handler Delegates

For valid exports, `CreateHandler(type, method, instances)` builds a **Delegate** capable of being invoked from the emulator core. This delegate is wrapped in a `SysAbiFunction` object that standardizes the calling convention for the dispatcher.

### Populating Dispatch Tables

The manager populates three internal collections:
- **`_dispatchTable`** – Maps NID strings to `SysAbiFunction` delegates for fast lookup during guest execution
- **`_exportTable`** – Stores complete `ExportInfo` records for introspection
- **`_exportNameTable`** – Indexes exports by human-readable names

Duplicate NIDs generate a warning and are ignored to prevent collision.

### Finalizing with Freeze and WarmHleTypeInitializers

After all modules are registered, `Freeze()` sets `_isFrozen = true` and immediately calls `WarmHleTypeInitializers()`. This method walks every scanned assembly and forces static constructors to run via `RuntimeHelpers.RunClassConstructor`, then JIT-compiles each method using `RuntimeHelpers.PrepareMethod`. This eliminates first-time JIT stalls and protects the CLR from fail-fast crashes during guest execution.

## Code Implementation Examples

### Defining an HLE Export

Create a static class with methods annotated using `SysAbiExportAttribute`:

```csharp
using SharpEmu.HLE;

public static class Audio
{
    [SysAbiExport(library: "sceAudio", nid: 0x12345678, name: "sceAudioOutput")]
    public static int Output(int channel, int volume, IntPtr buffer, uint size)
    {
        // Implementation that runs on the host
        return 0;
    }
}

```

### Registering During Startup

Instantiate `ModuleManager` and scan your assembly before the guest begins execution:

```csharp
using System.Reflection;
using SharpEmu.HLE;

var moduleMgr = new ModuleManager();
moduleMgr.RegisterFromAssembly(typeof(Audio).Assembly, Generation.Orbis2);
moduleMgr.Freeze();   // Locks registration and warms up JIT

```

### Looking Up Functions by NID

Guest code can resolve and invoke HLE functions using their NID:

```csharp
if (moduleMgr.TryGetFunction("0x12345678", out var func))
{
    var del = (Func<int, int, IntPtr, uint, int>)func;
    int result = del(0, 100, bufferPtr, 256);
}

```

## Key Source Files and Architecture

The HLE infrastructure is distributed across these core files:

- [`src/SharpEmu.HLE/ModuleManager.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/ModuleManager.cs) – Core registration logic, dispatch table management, and warm-up routines
- [`src/SharpEmu.HLE/SysAbiExportAttribute.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/SysAbiExportAttribute.cs) – Attribute definition that marks methods as HLE exports
- [`src/SharpEmu.HLE/IModuleManager.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/IModuleManager.cs) – Interface exposing `RegisterFromAssembly`, `Freeze`, and lookup operations
- [`src/SharpEmu.HLE/ExportedFunction.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/ExportedFunction.cs) – Data transfer object representing export metadata (library, NID, name)
- [`src/SharpEmu.HLE/SysAbiFunction.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.HLE/SysAbiFunction.cs) – Wrapper that encapsulates the delegate and invocation safety

## Summary

- **Discovery**: `RegisterFromAssembly` scans assemblies for `[SysAbiExport]` methods and deduplicates by generation
- **Metadata**: Each export is resolved into an `ExportInfo` containing library name, NID, and target symbol
- **Dispatch**: Delegates are created and stored in `_dispatchTable` for NID-based lookups
- **Safety**: `Freeze()` prevents further registration and triggers `WarmHleTypeInitializers` to pre-JIT all HLE methods
- **Integration**: The process allows SharpEmu to expose host system calls to PlayStation 5 guest binaries through a type-safe, attributed API

## Frequently Asked Questions

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

The `SysAbiExportAttribute` marks managed methods as exported HLE functions that guest code can call. It specifies the library namespace, the unique NID (Numeric ID), and the human-readable function name, allowing the `ModuleManager` to build the dispatch tables required for interop between the emulated guest and the host implementation.

### Why does ModuleManager require a Generation parameter during registration?

The `Generation` parameter (e.g., `Generation.Orbis2`) indicates which PlayStation 5 system version the assembly targets. This allows the emulator to support multiple firmware generations simultaneously while preventing conflicts between APIs that may have changed across hardware revisions.

### What happens if I try to register modules after calling Freeze()?

Calling `RegisterFromAssembly` after `Freeze()` has been invoked will result in an exception. The `_isFrozen` flag is set to true inside `Freeze()`, explicitly blocking any further registrations to ensure the dispatch tables remain immutable during guest execution and to prevent race conditions.

### How does WarmHleTypeInitializers improve emulator performance?

`WarmHleTypeInitializers` executes static constructors and JIT-compiles every HLE method before the guest starts running. This eliminates "first-time" compilation stalls that would otherwise occur when the guest first invokes a system call, and it prevents the CLR from entering fail-fast mode due to concurrent type initialization during emulation.