How SharpEmu Parses eboot.bin Files: A Deep Dive into the SELF/ELF Loader

SharpEmu parses eboot.bin files by detecting whether they are SELF-wrapped or raw ELF executables, extracting headers, mapping loadable segments into virtual memory, resolving import NIDs through dynamic relocation tables, and constructing a fully-prepared SelfImage for the CPU dispatcher.

SharpEmu is an open-source PlayStation 4/5 emulator that handles commercial game executables packaged as eboot.bin files. According to the par274/sharpemu source code, the emulator treats these binaries as either standard ELF executables or SELF-wrapped (Signed ELF) images requiring format detection. The parsing pipeline combines the SharpEmuRuntime facade with the SelfLoader class to validate, map, and prepare the executable for CPU emulation.

Detecting the SELF Wrapper Format

The parsing process begins with format detection to determine if the binary uses Sony's proprietary SELF encryption wrapper or a standard ELF.

File Loading in SharpEmuRuntime.LoadImage ([src/SharpEmu.Core/Runtime/SharpEmuRuntime.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Runtime/SharpEmuRuntime.cs#L103-L127)) reads the binary from disk into a byte array and hands it to the loader.

Magic Detection occurs in SelfLoader.ParseLayout ([src/SharpEmu.Core/Loader/SelfLoader.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Loader/SelfLoader.cs#L19-L48)). This method checks the first 4 bytes for the SELF magic value 0x4F153D1D. If present, it extracts the SELF header and segment list; otherwise, the loader treats the file as a plain ELF starting at offset 0.

Parsing ELF Headers and Program Segments

Once the format is determined, the loader validates the ELF structure and extracts the program header table.

Header Validation uses ReadUnmanaged<ElfHeader> in SelfLoader.LoadCore ([src/SharpEmu.Core/Loader/SelfLoader.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Loader/SelfLoader.cs#L62-L66)) to read the ELF header located after the SELF header (or at offset 0 for raw ELF). The loader validates the ELF magic, class, and ABI version before proceeding.

Program Header Parsing happens in SelfLoader.ParseProgramHeaders ([src/SharpEmu.Core/Loader/SelfLoader.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Loader/SelfLoader.cs#L51-L78)), which walks the program-header table to build an array of ProgramHeader structures describing loadable segments, dynamic sections, and proc-param regions.

Memory Mapping and Segment Allocation

After parsing headers, the loader prepares the virtual address space for execution.

Virtual Memory Reservation in SelfLoader.LoadCore ([src/SharpEmu.Core/Loader/SelfLoader.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Loader/SelfLoader.cs#L71-L88)) uses PhysicalVirtualMemory to reserve a contiguous region large enough for all loadable segments. The base address is chosen based on the image type (PS4 vs PS5) and may be forced to a specific address for SELF images.

Segment Mapping is handled by SelfLoader.MapLoadSegments ([src/SharpEmu.Core/Loader/SelfLoader.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Loader/SelfLoader.cs#L89-L104)). For each ProgramHeader of type Load, the loader copies file bytes (or zero-fills the remainder) into virtual memory at vaddr + imageBase, creating the in-memory image the CPU will execute.

Dynamic Linking and Import Resolution

Modern PlayStation executables rely heavily on dynamic imports identified by NIDs (Name IDs), which the loader must resolve before execution.

Dynamic Section Resolution in SelfLoader.ResolveAndPatchImportStubs ([src/SharpEmu.Core/Loader/SelfLoader.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Loader/SelfLoader.cs#L59-L71)) loads the Dynamic program header and parses the dynamic table via ParseDynamicInfo. This extracts offsets for the string table, symbol table, and relocation tables (Rela, JmpRel).

Relocation Collection occurs in SelfLoader.CollectRelocations ([src/SharpEmu.Core/Loader/SelfLoader.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Loader/SelfLoader.cs#L113-L130)), which reads all relocation entries (ElfRelocation) from the Rela and JmpRel sections. Each entry becomes a RelocationDescriptor recording the target address, addend, and import NID.

Stub Patching via SelfLoader.CreateImportStubMapping ([src/SharpEmu.Core/Loader/SelfLoader.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Loader/SelfLoader.cs#L127-L140)) allocates a stub address for every unique import NID. The loader writes the resolved address (or addend) into the target location, handling special relocation types such as TLS module ID.

Metadata Extraction and Symbol Registration

The loader also extracts game metadata and registers symbols for high-level emulation (HLE).

param.json Loading in SelfLoader.TryLoadParamJson ([src/SharpEmu.Core/Loader/SelfLoader.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Loader/SelfLoader.cs#L80-L118)) looks for sce_sys/param.json (or param.json) if a filesystem is provided. It extracts the title, title ID, and version, storing this metadata in the SelfImage object.

Runtime Symbol Registration scans both section and dynamic symbol tables:

Both methods add kernel exports and HLE symbols to runtimeSymbols with their associated NIDs for fast lookup.

Finalization and CPU Dispatch

Before execution, the loader prepares initialization routines and packages the final image.

Initializer Collection in SelfLoader.CollectInitializerFunctions ([src/SharpEmu.Core/Loader/SelfLoader.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Loader/SelfLoader.cs#L158-L170)) resolves .init, .init_array, and .preinit_array entries, recording their entry points so the emulator can run module constructors before the main entry point.

Image Construction in SelfLoader.LoadCore packages all gathered data—image base, ELF header, mapped regions, import stubs, runtime symbols, relocations, init functions, and metadata—into a SelfImage instance.

Execution Dispatch via SharpEmuRuntime.Run ([src/SharpEmu.Core/Runtime/SharpEmuRuntime.cs](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Core/Runtime/SharpEmuRuntime.cs#L30-L48)) receives the SelfImage, configures video/audio, registers the main module, and calls CpuDispatcher.DispatchEntry with the computed entry point (elfHeader.EntryPoint + imageBase).

Code Examples

Loading and Inspecting an eboot.bin

// Create a runtime with default options
var runtime = SharpEmuRuntime.CreateDefault(options);

// Path to the eboot file (absolute or relative)
string ebootPath = @"E:\Games\Demo\eboot.bin";

// Load the image – this parses the file and returns a SelfImage
SelfImage image = runtime.LoadImage(ebootPath);

// Inspect parsed metadata
Console.WriteLine($"Title: {image.Title ?? "unknown"}");
Console.WriteLine($"TitleID: {image.TitleId ?? "unknown"}");
Console.WriteLine($"Entry point: 0x{image.EntryPoint:X}");
Console.WriteLine($"Mapped segments: {image.MappedRegions.Count}");

Running the Executable

// Executes the eboot after all initializers have been processed
OrbisGen2Result result = runtime.Run(ebootPath);

Console.WriteLine($"Run finished with status: {result}");

Querying Imported NIDs

foreach (var kv in image.ImportStubs)
{
    Console.WriteLine($"Stub at 0x{kv.Key:X16} → NID {kv.Value}");
}

Accessing Runtime Symbols

foreach (var kv in image.RuntimeSymbols)
{
    Console.WriteLine($"{kv.Key} → 0x{kv.Value:X16}");
}

Key Source Files

Summary

  • SharpEmu treats eboot.bin files as either SELF-wrapped or raw ELF executables, detecting the format via magic value 0x4F153D1D in SelfLoader.ParseLayout.
  • The loader validates ELF headers using ReadUnmanaged<ElfHeader> and walks program headers to identify loadable segments.
  • Virtual memory allocation and segment mapping occur through PhysicalVirtualMemory and SelfLoader.MapLoadSegments, creating the executable image at the appropriate base address.
  • Dynamic imports are resolved by collecting relocations from Rela and JmpRel sections, then patching stub addresses via SelfLoader.CreateImportStubMapping.
  • Game metadata is extracted from param.json while runtime symbols are registered for HLE functionality.
  • The fully parsed image is packaged into a SelfImage object and dispatched through SharpEmuRuntime.Run to the CPU emulation engine.

Frequently Asked Questions

Does SharpEmu support both PS4 and PS5 eboot.bin files?

Yes. The loader handles both PS4 and PS5 executables by detecting the SELF wrapper format and adjusting the base address allocation during the PhysicalVirtualMemory reservation phase based on the detected image type.

What is the difference between SELF and ELF in SharpEmu's loader?

SELF (Signed ELF) is a Sony-specific wrapper format that may contain encrypted segments. SharpEmu checks for the magic value 0x4F153D1D in SelfLoader.ParseLayout to detect the SELF header; if absent, the loader treats the file as a standard ELF executable beginning at offset 0.

How does SharpEmu handle imported functions in eboot.bin?

The loader collects relocation entries from the Rela and JmpRel sections via SelfLoader.CollectRelocations, then creates import stub mappings for each unique NID using SelfLoader.CreateImportStubMapping. These stubs are patched to point to HLE implementations or resolved kernel exports before execution begins.

Where does SharpEmu look for game metadata like title IDs?

During the loading process, SelfLoader.TryLoadParamJson searches for sce_sys/param.json (or param.json) within the provided filesystem. It extracts the title, title ID, and version, storing this information in the SelfImage metadata object for later use by the emulator interface.

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 →