ran-j /PS2Recomp

Playstation 2 Static Recompiler & Runtime Tool to make native PC ports

★ 3,776⑂ 241👁 99⑃ 76● 43▤ 5
C++Created 2025-04-12
3,776
stars
+0+8+418
241
forks
99
watchers
76
prs
43
issues
5
releases
–
discussions

README

PS2Recomp: PlayStation 2 Static Recompiler (Experimental)



Also check our WIKI


This project statically recompiles PS2 ELF binaries into C++ and provides a runtime to execute the generated code.

 Modules

 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.

 Features

 Translates MIPS R5900 instructions to C++ code
 PS2-specific MMI and VU0 macro support.
 Single-file or multi-file output.
 Configurable stubs, skips, and instruction patches.
 Instruction-driven syscall handling.

 How It Works
PS2Recomp works by:

 Parsing a PS2 ELF file to extract functions, symbols, and relocations
 Decoding the MIPS R5900 instructions in each function
 Translating those instructions to equivalent C++ code
 Generating a runtime that can execute the recompiled code

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);.

 Current Behavior

 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).
 Address bindings also support generic return handlers for triage: ret0, ret1, reta0.
 Recompiler now tries relocation-symbol auto-binding at callsites (J/JAL) before raw address dispatch; when relocation symbol is known (for example sceCdRead), it can call runtime handlers without manual address mapping.
 Recompiler discovers additional internal static entry targets and emits entry_... wrappers for those addresses.
 For unresolved static J/JAL sites, generated code falls back to runtime-lookupFunction(0x...).
 skip entries are not recompiled and generate explicit ps2_stubs::TODO_NAMED(...) wrappers.
 Recompiled SYSCALL now calls runtime-handleSyscall(...) with the encoded syscall immediate.
 Runtime syscall dispatch tries encoded syscall ID first, then falls back to $v1.

 Requirements

 CMake 3.20+
 C++20 compiler (currently tested mainly with MSVC)
 SSE4/AVX host support for some vector paths

 Build

bash
git clone --recurse-submodules https://github.com/ran-j/PS2Recomp.git
cd PS2Recomp

cmake -S . -B out/build
cmake --build out/build --config Debug


 Usage

Preferred workflow for retail or stripped games:

1. Open the ELF in Ghidra.
2. Run ps2xRecomp/tools/ghidra/ExportPS2Functions.java.
3. Use the exported TOML and CSV map.
4. Recompile with the exported TOML:

bash
./ps2_recomp config.toml


Fallback workflow for quick local experiments or ELFs with debug symbol :

bash
./ps2_analyzer your_game.elf config.toml


See the Ghidra Workflow for ghdira instructions.

Then build generated output and link with ps2xRuntime.

Snapshot: 2026-11-04T14:00:00Z · Data license Apache-2.0 · JSON