MoH Vanguard (SLUS-21597) bring-up: 18.9k functions recompiled with 0 undecoded instructions — generated code builds, links and boots to guest execution (+ toolchain findings)

Open
#351 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 5 days

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
35/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
cpp
Domain
devtools, tooling

Research direction

Start by reading the four toolchain findings and their cited locations: ps2_recompiler.cpp, code_generator_tests.cpp, ps2xRuntime/src/runner/register_functions.cpp, and the dump workflow. The report proposes separate fixes, each with a suggested test where applicable; choose one finding and confirm its scope with the maintainers before changing code. Done means a focused fix and the corresponding test or workflow check demonstrates the reported problem is addressed.

Written by the indexing model from the issue text.

Description

We brought Medal of Honor: Vanguard through the full M1 pipeline: ISO → ELF extraction → ps2_analyzer → ps2_recomp → generated code compiled and linked against ps2xRuntime. This is a report of how the toolkit handled a multi-MB retail EA title end to end, plus a few toolchain findings. The full measured report can be pasted in this issue on request.

Environment: toolkit at eb8688b, MSVC Release, Windows 11.

Disc facts: BOOT2 = cdrom0:\SLUS_215.97;1 (NTSC) — the boot ELF is only a 124 KB loader; the real game is MOH5RDVD.ELF, 4.89 MB ELF32 MIPS. IOP modules on disc: PADMAN, LIBSD, SNDDRV, SIO2MAN, MCMAN, MCSERV, MTAPMAN + IOPRP280.IMG.

Results:

Vanguard
Functions discovered 18.876 (485 via SCE symbol DB, 0 ELF symbols — retail stripped)
Configured → applied stubs 134 → 133 (see finding 1)
Undecoded instructions 0 (Unhandled instructions: 0, decode failures: 0)
Generated code 18.878 .cpp + 2 headers, 7.31 M lines, ~51 s generation
Build (MSVC, unity) 0 errors in generated code, 28.6 min
Link + boot ps2EntryRunner loads the ELF (Entry point: 0x10a008), enters run(); call/return-balanced trace proves recompiled game code executes (7.120 enters = 7.120 exits over 54 functions)

For a 4.89 MB retail ELF, low_memory_mode = true + multi-file output worked well; note that low_memory_mode forces a single output worker (ps2_recompiler.cpp:1325), so output_worker_threads is inert in that mode — worth a README mention.

Findings while doing this (happy to file/PR separately):

  1. Configured stubs at non-function-boundary addresses are silently dropped. Vanguard: 134 stubs configured, 133 applied — sceGsSetDefLoadImage@0x00471F80 produced no warning. The apply loop only iterates discovered functions (ps2_recompiler.cpp:1091) and the existing warning (:1106-1109) only fires for a matched function, so there is no inverse check "every configured stub matched something". By contrast, non-boundary entry_points entries do get a synthesized entry (e.g. SetT2@0x004A0558) — asymmetric handling of the same condition.
  2. ps2_recomp exits 0 even when a recompile reports decode errors (observed while validating the recompiler against an additional retail ELF; the Vanguard recompile itself was clean). A CI/probe calling the tool silently passes on partial decodes. Same run also emitted byte-identical duplicate lines in the unhandled-instruction output, which inflates counts.
  3. ps2x_tests VU0 macro mappings cover all S1/S2 enums (code_generator_tests.cpp:1277) resolves instructions.h via repo-relative paths and fails when the suite runs from outside the repo root.
  4. ps2xRuntime/src/runner/register_functions.cpp is tracked upstream but is overwritten by the gen dump workflow (the rest of src/runner/ and the ps2_recompiled_*.h headers are already gitignored). After installing 18.878 generated files, the clone holds ~517k lines of game-derived code in a tracked file — one routine git add -u while preparing a fork/PR would publish it. Making it untracked would make the documented dump workflow safe.

Proposed PRs (after your feedback):

# Topic Content Test
1 recomp: warn on configured stubs that match no discovered function Inverse check after the apply loop: configured stub with no match → warning (and/or error behind a flag) new ps2xTest case with a non-boundary stub in config
2 recomp: non-zero exit code when decode errors remain Exit ≠ 0 when errors > 0 (or opt-in --strict-exit); dedupe identical unhandled lines (count + first address) integration test with an ELF containing an unsupported instruction
3 test: make VU0 enum coverage test independent of CWD Resolve instructions.h from the source file's path fix to the test itself
4 runtime: stop tracking ps2xRuntime/src/runner/register_functions.cpp .gitignore change so the documented dump workflow can't leak game-derived code n/a (.gitignore change)
Dominant language
C++
Stars
3.3k
Forks
149
Avg merge
8h 46m
Merged PRs (30d)
1

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ran-j/PS2Recomp

All issues in ran-j/PS2Recomp

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.