Change: generic NSO rewriter (crates/napple-rewrite)¶
Objective¶
Rewrite every NSO module so it runs natively on Apple Silicon: virtual x18 / tpidr_el0 / tpidrro_el0 in
per-thread slots, svc and counter reads through a host gate. Own Rust implementation of the generic part
of the reference patch_nso.py (per-game CUTS/OBS/PARAMS tables intentionally not ported).
Files¶
crates/napple-rewrite/: src/{a64,image,relocs,scan,patch,templates,jumptab,windows,rewrite,output,check,cli,error,types}.rs,
src/bin/napple-rewrite.rs, tests/{templates.rs,support/}, examples/{rw,verify,at}.rs, Cargo.toml (rayon, yaxpeax; dev: unicorn-engine).
Docs: docs/rewrite-format.md.
Logic¶
Linear scan (parallel) of text for svc/sysreg/x18 (decoder-confirmed); inline data (bl .+8 literal, literal-pool targets, MOD0) excluded.
Exclusive windows grouped (retry fragments linked); then each site gets a template (see format doc). br x18: exact table recovery
(adr+ldrb/ldrh; ldrsw signed tables) else the whole enclosing function as landing-pad range. Output is verified by check::verify (structure).
Decisions¶
- Spill at
sp-144instead of the reference'ssp-16: real guest code (LA main) uses the red zone; reference spill would corrupt it. blr x18replaced in place by a block that sets x30 to the original return address andbr x16(no alternate-entry constraints, no prefix word needed, so RELR/dynamic scans for call entry are unnecessary; relocations are only decoded as a safety net inrelocs.rs).- Gates also lower sp by 144 (host C code must not run in the guest red zone).
cntfrqgated too. - Unhandled sites are reported, never guessed; CLI fails.
Risks / pending¶
- Signal handlers on guest threads need sigaltstack (see format doc).
tpidrro_el0low bits assumed zero (reference assumption), unverified on hardware. - Function-span fallback for
br x18assumes compiler jump tables stay inside the function (1 site: LA subsdk0 0x1be6e8). - Data words that decode as x18 code outside the recognised inline-data idioms would be rewritten (warnings list data matches, none found in the two games).
- Equivalence harness uses Unicorn: exclusive ops are de-exclusified, MTE/LORegion/undefined encodings are not modelled; gate host semantics are not tested (no-op host stub: state preserved).
- No independent disassembler (llvm-objdump) cross-check of the site denominator was done (no ELF wrapper tool available).
- Not covered: x18-targeted counter/sysreg reads, sp-writing x18 instructions (none occur in LA/SMO).
Tests¶
cargo test -p napple-rewrite (needs brew install unicorn pkgconf): unit tests (encoders, scan, relocs, jump tables) and Unicorn
differential tests per template (plain incl. sp push/pop and red zone, cond, pcrel, literal, br tables, blr, exclusive windows, sysreg r/w, svc/counter gates,
6000-instruction random corpus with mutation self-check). Real games: cargo run --release --example verify -p napple-rewrite -- <nso files>
(results in the final report).