Playstation 2 Static Recompiler & Runtime Tool to make native PC ports
C++
3,387
168 commits
updated Oct 10, 2026
Also check our WIKI
This project statically recompiles PS2 ELF binaries into C++ and provides a runtime to execute the generated code.
ps2xAnalyzer: scans ELF/functions and writes TOML config (stubs, skip, instruction patches).ps2xRecomp: reads TOML + ELF, decodes R5900 instructions, and generates C++ output.ps2xRuntime: hosts memory, function registration, syscall dispatch, and hardware stubs.ps2xIOP: R3000A IRX execution, a virtual IOP kernel, and generic HLE fallbacks.PS2Recomp works by:
The translated code is very literal, with each MIPS instruction mapping to a C++ operation. For example, addiu $r4, $r4, 0x20 becomes ctx->r4 = ADD32(ctx->r4, 0X20);.
stubs entries generate wrappers that call known runtime syscall/stub handlers by name.stubs also supports address bindings with handler@0xADDRESS for stripped games (for example sceCdRead@0x00123456).ret0, ret1, reta0.J/JAL) before raw address dispatch; when relocation symbol is known (for example sceCdRead), it can call runtime handlers without manual address mapping.entry_... wrappers for those addresses.J/JAL sites, generated code falls back to runtime->lookupFunction(0x...).skip entries are not recompiled and generate explicit ps2_stubs::TODO_NAMED(...) wrappers.SYSCALL now calls runtime->handleSyscall(...) with the encoded syscall immediate.$v1.git clone --recurse-submodules https://github.com/ran-j/PS2Recomp.git
cd PS2Recomp
cmake -S . -B out/build
cmake --build out/build --config Debug
Preferred workflow for retail or stripped games:
ps2xRecomp/tools/ghidra/ExportPS2Functions.java../ps2_recomp config.toml
Fallback workflow for quick local experiments or ELFs with debug symbol :
./ps2_analyzer your_game.elf config.toml
See the Ghidra Workflow for ghdira instructions.
Then build generated output and link with ps2xRuntime.
Main fields in config.toml:
general.input: source ELF path.general.ghidra_output: recommended function map CSV exported from Ghidra.general.output: generated C++ output folder.general.single_file_output: one combined cpp or one file per function.general.low_memory_mode: reduce peak output-generation memory by avoiding retained disassembly strings and forcing serial output generation. Generated instruction comments are still emitted; disassembly text is produced while writing each output file instead of being kept in memory.general.output_worker_threads: number of output-generation workers (clamped to nproc * 2). A positive value uses exactly that many workers. 0 uses nproc - 1 when at least two hardware threads are available, otherwise serial output generation. 1 forces serial output generation.general.patch_syscalls: apply configured patches to SYSCALL instructions (false recommended).general.patch_cop0: apply configured patches to COP0 instructions.general.patch_cache: apply configured patches to CACHE instructions.general.stubs: names to force as stubs. Also accepts handler@0xADDRESS to bind a stripped function address directly to a runtime syscall/stub handler. Includes generic handlers ret0, ret1, reta0.general.skip: names to force as skipped wrappers.patches.instructions: raw instruction replacements by address.Address binding for stripped ELFs:
handler@0xADDRESS inside general.stubs to map a stripped function start directly to a runtime handler.sceCdRead@0x00123456 binds function start 0x00123456 to ps2_stubs::sceCdRead(...).ret0@0xADDR, ret1@0xADDR, reta0@0xADDR.PS2_SYSCALL_LIST or PS2_STUB_LIST).Example:
# stripped function binding by address:
stubs = ["sceCdRead@0x00123456", "SifLoadModule@0x00127890"]
# temporary return handlers:
stubs = ["ret0@0x001D9410", "ret1@0x001D5BC8", "reta0@0x0024B7C0"]
# mixed example:
stubs = ["printf", "sceCdRead@0x00123456", "SifLoadModule@0x00127890"]
To execute the recompiled code.
ps2xRuntime currently provides:
ps2xIOP execution of original IRX modules with generic HLE fallbacks.See IOP emulation for module execution and the service boundary.
Game overrides are runtime-side, build-scoped patch modules.
A game override is C++ code that runs during loadELF and can replace EE function bindings by address for one specific game build. IOP RPC/DMA behavior is handled by the ps2xIOP emulator and its runtime transport. This is separate from recompilation output and separate from global runtime stubs/syscalls.
API:
ps2xRuntime/include/game_overrides.hPS2_REGISTER_GAME_OVERRIDE(name, elfName, entry, crc32, applyFn)ps2_game_overrides::bindAddressHandler(runtime, addr, "handler")Use Game Override modules when:
function not found, syscall TODO, critical IO stubs).A game project built with PS2Recomp can describe itself in a .recomp.json file at the root of its repository. Lists of recomp and decomp projects, such as recomp.board, read that file instead of guessing the game, system and status from the README.
[!NOTE] This file is optional: PS2Recomp does not read it and works the same without it.
.recomp.jsonand recomp.board are third-party projects; the PS2Recomp developers have no ties to them.
Starter file:
{
"$schema": "https://recomp.fyi/schema/v1.json",
"game": "<title as it shipped>",
"system": "PS2",
"type": "recomp",
"toolchain": "PS2Recomp",
"status": "in-progress",
"original": { "region": "USA", "serial": "SLUS-20312" }
}
original is the release a user must own. On retail discs the ELF is named after the serial (SLUS_203.12 is SLUS-20312), and the prefix gives the region: SLUS/SCUS USA, SLES/SCES Europe, SLPS/SLPM/SCPS Japan.status is one of exploring, in-progress, playable, released, complete, paused. Edit it when the project moves on: a stale status is worse than none.Other fields (Wikidata item, target platforms, maintainers, links, what help is wanted) and the JSON Schema are in the specification.
(top 24 of 31)
579 followers · starred Jan 2026
445 followers · starred Jan 2026
193 followers · starred Jan 2026
1,977 followers · starred Jan 2026
Playstation 2 Static Recompiler & Runtime Tool to make native PC ports
C++
3,387
168 commits
updated Oct 10, 2026
Also check our WIKI
This project statically recompiles PS2 ELF binaries into C++ and provides a runtime to execute the generated code.
ps2xAnalyzer: scans ELF/functions and writes TOML config (stubs, skip, instruction patches).ps2xRecomp: reads TOML + ELF, decodes R5900 instructions, and generates C++ output.ps2xRuntime: hosts memory, function registration, syscall dispatch, and hardware stubs.ps2xIOP: R3000A IRX execution, a virtual IOP kernel, and generic HLE fallbacks.PS2Recomp works by:
The translated code is very literal, with each MIPS instruction mapping to a C++ operation. For example, addiu $r4, $r4, 0x20 becomes ctx->r4 = ADD32(ctx->r4, 0X20);.
stubs entries generate wrappers that call known runtime syscall/stub handlers by name.stubs also supports address bindings with handler@0xADDRESS for stripped games (for example sceCdRead@0x00123456).ret0, ret1, reta0.J/JAL) before raw address dispatch; when relocation symbol is known (for example sceCdRead), it can call runtime handlers without manual address mapping.entry_... wrappers for those addresses.J/JAL sites, generated code falls back to runtime->lookupFunction(0x...).skip entries are not recompiled and generate explicit ps2_stubs::TODO_NAMED(...) wrappers.SYSCALL now calls runtime->handleSyscall(...) with the encoded syscall immediate.$v1.git clone --recurse-submodules https://github.com/ran-j/PS2Recomp.git
cd PS2Recomp
cmake -S . -B out/build
cmake --build out/build --config Debug
Preferred workflow for retail or stripped games:
ps2xRecomp/tools/ghidra/ExportPS2Functions.java../ps2_recomp config.toml
Fallback workflow for quick local experiments or ELFs with debug symbol :
./ps2_analyzer your_game.elf config.toml
See the Ghidra Workflow for ghdira instructions.
Then build generated output and link with ps2xRuntime.
Main fields in config.toml:
general.input: source ELF path.general.ghidra_output: recommended function map CSV exported from Ghidra.general.output: generated C++ output folder.general.single_file_output: one combined cpp or one file per function.general.low_memory_mode: reduce peak output-generation memory by avoiding retained disassembly strings and forcing serial output generation. Generated instruction comments are still emitted; disassembly text is produced while writing each output file instead of being kept in memory.general.output_worker_threads: number of output-generation workers (clamped to nproc * 2). A positive value uses exactly that many workers. 0 uses nproc - 1 when at least two hardware threads are available, otherwise serial output generation. 1 forces serial output generation.general.patch_syscalls: apply configured patches to SYSCALL instructions (false recommended).general.patch_cop0: apply configured patches to COP0 instructions.general.patch_cache: apply configured patches to CACHE instructions.general.stubs: names to force as stubs. Also accepts handler@0xADDRESS to bind a stripped function address directly to a runtime syscall/stub handler. Includes generic handlers ret0, ret1, reta0.general.skip: names to force as skipped wrappers.patches.instructions: raw instruction replacements by address.Address binding for stripped ELFs:
handler@0xADDRESS inside general.stubs to map a stripped function start directly to a runtime handler.sceCdRead@0x00123456 binds function start 0x00123456 to ps2_stubs::sceCdRead(...).ret0@0xADDR, ret1@0xADDR, reta0@0xADDR.PS2_SYSCALL_LIST or PS2_STUB_LIST).Example:
# stripped function binding by address:
stubs = ["sceCdRead@0x00123456", "SifLoadModule@0x00127890"]
# temporary return handlers:
stubs = ["ret0@0x001D9410", "ret1@0x001D5BC8", "reta0@0x0024B7C0"]
# mixed example:
stubs = ["printf", "sceCdRead@0x00123456", "SifLoadModule@0x00127890"]
To execute the recompiled code.
ps2xRuntime currently provides:
ps2xIOP execution of original IRX modules with generic HLE fallbacks.See IOP emulation for module execution and the service boundary.
Game overrides are runtime-side, build-scoped patch modules.
A game override is C++ code that runs during loadELF and can replace EE function bindings by address for one specific game build. IOP RPC/DMA behavior is handled by the ps2xIOP emulator and its runtime transport. This is separate from recompilation output and separate from global runtime stubs/syscalls.
API:
ps2xRuntime/include/game_overrides.hPS2_REGISTER_GAME_OVERRIDE(name, elfName, entry, crc32, applyFn)ps2_game_overrides::bindAddressHandler(runtime, addr, "handler")Use Game Override modules when:
function not found, syscall TODO, critical IO stubs).A game project built with PS2Recomp can describe itself in a .recomp.json file at the root of its repository. Lists of recomp and decomp projects, such as recomp.board, read that file instead of guessing the game, system and status from the README.
[!NOTE] This file is optional: PS2Recomp does not read it and works the same without it.
.recomp.jsonand recomp.board are third-party projects; the PS2Recomp developers have no ties to them.
Starter file:
{
"$schema": "https://recomp.fyi/schema/v1.json",
"game": "<title as it shipped>",
"system": "PS2",
"type": "recomp",
"toolchain": "PS2Recomp",
"status": "in-progress",
"original": { "region": "USA", "serial": "SLUS-20312" }
}
original is the release a user must own. On retail discs the ELF is named after the serial (SLUS_203.12 is SLUS-20312), and the prefix gives the region: SLUS/SCUS USA, SLES/SCES Europe, SLPS/SLPM/SCPS Japan.status is one of exploring, in-progress, playable, released, complete, paused. Edit it when the project moves on: a stale status is worse than none.Other fields (Wikidata item, target platforms, maintainers, links, what help is wanted) and the JSON Schema are in the specification.
(top 24 of 31)
579 followers · starred Jan 2026
445 followers · starred Jan 2026
193 followers · starred Jan 2026
1,977 followers · starred Jan 2026