必须加 --recurse-submodules 克隆,否则子模块缺失;需要 CMake 3.20+ 和 C++20 编译器,目前主要在 MSVC 上测试;零售或 stripped 游戏建议先用 Ghidra 导出 TOML/CSV,直接跑 analyzer 只适合带调试符号的 ELF。
PS2Recomp
ran-jGPL-3.0活跃维护把 PS2 游戏二进制静态重编译成可在 PC 上原生运行的程序,省去逐行模拟开销,方便做移植和逆向分析。
Playstation 2 Static Recompiler & Runtime Tool to make native PC ports
git clone --recurse-submodules https://github.com/ran-j/PS2Recomp.git
cd PS2Recomp
cmake -S . -B out/build
cmake --build out/build --config DebugREADME 未说明显存或 GPU 型号要求;仅要求宿主 CPU 支持 SSE4/AVX 以运行部分向量路径。
把 PS2 ELF 静态重编译成 C++ 并配运行时,用来做原生 PC 移植
把 PS2 游戏二进制静态重编译成可在 PC 上原生运行的程序,省去逐行模拟开销,方便做移植和逆向分析。
核心能力
- 将 MIPS R5900 指令逐条翻译为等价 C++ 代码
- 支持 PS2 专用 MMI 与 VU0 macro 指令
- 用 TOML 配置 stubs、skip 和指令补丁
- 支持 handler@地址 绑定 stripped 游戏函数
- 内置 ps2xIOP 执行原始 IRX 模块
容易踩的坑
- v0.4pre-release最新正式版2026-04-05 · 2026-04-05 02:24 UTC
What's Changed
-
sceGsSetDefDBuff and sceGsSwapDBuff implementation based on the DC version by @roby65 in https://github.com/ran-j/PS2Recomp/pull/106
-
feat: remove memory and pad from stub section
-
feat: add support for resume entry targets in CodeGenerator (this allow jumps in address outside function) feat: refactor entry point discovery one more try to reduce big generated file
-
feat: optmizations for release build
-
feat: remove unused file
-
feat: added some test cases for code gen
-
feat: added log macro and remove win specific code
-
feat: refactor runtime folder structure feat: added reset sound driver RPC state and compatibility layout feat: rename and added new test feat: update RPC calls to use defined constants feat: added more PSMC(16, 32) feat: change cd read to try find the asset ignoring case sensitive fix: fix some render problems feat: add logs on pad feat: added more RPC handles
-
feat: added game override for code veronica
-
feat: apply vita patch
-
feat: flags to disable build
-
feat: fix merges feat: break a lot of tests
-
feat: better throw error on empty cd path feat: remove recompiler unusde function feat: apply missing patch
-
feat: gamedp is now part of lib feat: missing file
-
feat: small cleanup
-
feat: missing vita changes
-
feat: fix more merge
-
feat: fix tests
-
feat: last missing feature
-
feat: added missing import
-
feat: rename test local functions
-
feat: init syscall on ps2 list
-
feat: added DMA helpers
-
feat: faster builds feat: more implement for darkcloud
-
feat: back missing file
-
feat: added missing includes
-
feat: remove test
-
feat: missing include
-
feat: read register funtion
-
feat: build fix
-
feat: force exit on detach thread
Full Changelog: https://github.com/ran-j/PS2Recomp/compare/v0.3...v0.4
Note the runtime is way more generic, but since we dont emulate IOP modules YOU need to handle then on RPC or your game will be stuck.
Code veronica graphical fixes and we can boot dark cloud 2 with some graphic glitchs.
-
- v0.3pre-release2026-03-18 · 2026-03-18 23:27 UTC
查看更新说明
What's Changed
-
fix: CRITICAL fix on code gen on generating BEQ translation, I added a small yeld because goto could spin forever and monopolize guest execution
-
feat: add scratchpad alias base and improve scratchpad address handling
-
feat: added debug logging on GifArbiter for submit and drain operations
-
feat: add interrupt and thread management syscall implementations fix: change some IDs calls to match ps2sdk
-
feat: added vif1 logs
-
feat: added logs on gs gpu feat: added performLocalToLocalTransfer to GS emulation path for TRXDIR = 2. (emulates the PS2 GS “copy this rectangle from one place in VRAM to another”)
-
feat: added PSMT8 and refactor PSMT4
-
feat: some identation on vu1 feat: added some logs on vu1
-
feat: added GuestExecutionScope to temporarily stop owning guest execution, then restore it exactly as it was. feat: added vsync wizardry feat: added some regression test
-
fix: fix gs logger
-
feat: remove extra logs I think they will help no one feat: move join all threads to prevent the app to get stuck on close, but now it random crash on closing feat: one more small test on psmt4 to try fix ghosting on re code veronica
-
feat: added a small case for exporter from ghidra for metal slug 3
-
feat: added ugly code to pass on test
Full Changelog: https://github.com/ran-j/PS2Recomp/compare/v0.2...v0.3
Know issue
Some games create larger cpp files, I`m aware about that bug, but I dont have a solution for now, the bug consist in wrong boundries funcctions check, that can occur even on ghidra so this is a bit more complicated to solve.
Special
Now we can boot Resident Evil code veronica (SLUS_201.84). Its only get to memory card part not more than that for now.
I used ghidra workflow but should work on local analyzer as well.
-
- v0.2pre-release2026-03-09 · 2026-03-09 03:43 UTC
查看更新说明
What's Changed
- Fixed recompiler error when the cpp filename is too long by @roby65 in https://github.com/ran-j/PS2Recomp/pull/88
- Integrate ps2xStudio and improve elf_analyzer callback detection by @BlackLineInteractive in https://github.com/ran-j/PS2Recomp/pull/83
- Issue 13: Minimal libpad (SIO2/PAD) stubs, input mapping and tests by @Whoneon in https://github.com/ran-j/PS2Recomp/pull/69
- Normalize Windows drive paths exported by Ghidra by @Whoneon in https://github.com/ran-j/PS2Recomp/pull/92
- Filter Ghidra auto-generated symbols using map start addresses by @Whoneon in https://github.com/ran-j/PS2Recomp/pull/95
- Implement syscall 0x83 (FindAddress) with kernel tests by @Whoneon in https://github.com/ran-j/PS2Recomp/pull/93
- Feature/ghidra export and syscall fixes by @ran-j in https://github.com/ran-j/PS2Recomp/pull/100
New Contributors
- @roby65 made their first contribution in https://github.com/ran-j/PS2Recomp/pull/88
- @BlackLineInteractive made their first contribution in https://github.com/ran-j/PS2Recomp/pull/83
Full Changelog: https://github.com/ran-j/PS2Recomp/compare/v0.1...v0.2
- v0.1pre-release2026-02-27 · 2026-02-27 06:46 UTC
查看更新说明
What's Changed
- Add game name to window title by @DanielSvoboda in https://github.com/ran-j/PS2Recomp/pull/74
- Add IOP, audio, pad, fio changes, VAG handling, and call-stack logger by @aslanhudajev in https://github.com/ran-j/PS2Recomp/pull/76
- Feat: GS, VIF1, VU1 pathways + font rendering stubs + mpeg stubs by @aslanhudajev in https://github.com/ran-j/PS2Recomp/pull/80
- Fix 'max' by @DanielSvoboda in https://github.com/ran-j/PS2Recomp/pull/81
- Feature/runtime review codegen fixes by @ran-j in https://github.com/ran-j/PS2Recomp/pull/87
Full Changelog: https://github.com/ran-j/PS2Recomp/compare/v0.0...v0.1
- v0.0V0pre-release2026-02-22 · 2026-02-22 05:22 UTC
查看更新说明
We have a recompiler with a lot of instructions and workflow for strip and debug symbol games. We also have a runtime with simple GS, DMA and many more.
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
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
stubsentries generate wrappers that call known runtime syscall/stub handlers by name.stubsalso supports address bindings withhandler@0xADDRESSfor stripped games (for examplesceCdRead@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 examplesceCdRead), 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/JALsites, generated code falls back toruntime->lookupFunction(0x...). skipentries are not recompiled and generate explicitps2_stubs::TODO_NAMED(...)wrappers.- Recompiled
SYSCALLnow callsruntime->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
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:
- Open the ELF in Ghidra.
- Run
ps2xRecomp/tools/ghidra/ExportPS2Functions.java. - Use the exported TOML and CSV map.
- Recompile with the exported TOML:
./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.
Configuration
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.0usesnproc - 1when at least two hardware threads are available, otherwise serial output generation.1forces serial output generation.general.patch_syscalls: apply configured patches toSYSCALLinstructions (falserecommended).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 acceptshandler@0xADDRESSto bind a stripped function address directly to a runtime syscall/stub handler. Includes generic handlersret0,ret1,reta0.general.skip: names to force as skipped wrappers.patches.instructions: raw instruction replacements by address.
Address binding for stripped ELFs:
- Use
handler@0xADDRESSinsidegeneral.stubsto map a stripped function start directly to a runtime handler. - Example:
sceCdRead@0x00123456binds function start0x00123456tops2_stubs::sceCdRead(...). - Generic temporary handlers are available:
ret0@0xADDR,ret1@0xADDR,reta0@0xADDR. - Before manual binding, prefer recompilation from a Ghidra-exported TOML/CSV first. The extra boundaries and synthetic entry points are usually more important than manual early triage.
- The address must be the function start in that exact ELF build.
- Addresses are not portable across different games/regions/builds.
- The handler name must exist in runtime call lists (
PS2_SYSCALL_LISTorPS2_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"]
Runtime
To execute the recompiled code.
ps2xRuntime currently provides:
- Guest memory model and function dispatch table.
- Some syscall dispatcher with common kernel IDs.
- Basic GS/VU/file/system stubs.
- Foundation to expand and port your game.
ps2xIOPexecution of original IRX modules with generic HLE fallbacks.
See IOP emulation for module execution and the service boundary.
Game Override Hooks
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:
- Header:
ps2xRuntime/include/game_overrides.h - Register macro:
PS2_REGISTER_GAME_OVERRIDE(name, elfName, entry, crc32, applyFn) - Direct bind helper:
ps2_game_overrides::bindAddressHandler(runtime, addr, "handler")
Use Game Override modules when:
- You need per-game/per-build routing or patches without polluting global behavior.
- You need to bind many addresses, or install custom replacement logic for a specific title.
Recommended Iteration Loop
- Run with minimal config and no aggressive skipping.
- Fix hard blockers first (
function not found, syscall TODO, critical IO stubs). - Use temporary return stubs only to classify call importance.
- Promote temporary fixes to real implementations.
- Move per-game hacks into game overrides keyed by ELF metadata.
- Re-test from cold boot after each batch.
Describing Your Game Project
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" }
}
originalis the release a user must own. On retail discs the ELF is named after the serial (SLUS_203.12isSLUS-20312), and the prefix gives the region:SLUS/SCUSUSA,SLES/SCESEurope,SLPS/SLPM/SCPSJapan.statusis one ofexploring,in-progress,playable,released,complete,paused. Edit it when the project moves on: a stale status is worse than none.- Never put a game file, or a link to one, in the file.
Other fields (Wikidata item, target platforms, maintainers, links, what help is wanted) and the JSON Schema are in the specification.
Limitations
- Performance is very bad for VU and GS
- Hardware emulation is partial and many paths are stubbed.
Acknowledgments
- Inspired by N64Recomp
- Uses ELFIO for ELF parsing
- Uses toml11 for TOML parsing
- Uses fmt for string formatting
- Reference for runtime PCSX2