Skip to content

Running the original's code on a whole-process snapshot ​

What to know ​

2026-10-24, the run4 snapshot (derived/truth/run4/frame-1004.snap), docs/sim.md.

A snapshot from Hardwar's vm_snapshot.py holds every writable mapping of the running game, the program's own sections included (Watcom marks them writable). Mapped into Unicorn page by page, it lets one routine of the original run on the real world of that step: the pilots, the vehicles, the buildings as they were. That answered a question no emulation of a routine on its own could: which system draws stream A on a paused step. pilots_update (0x46a8d0), called on the snapshot with a hook on rng_next (0x4fc4e0) that logs the return addresses on the stack, made exactly four draws, all in the weapons' fire control.

Three things it needed:

  • A stack outside every region. Wine's mappings fill most of the low 2 GB and the top of the address space; a stack at 0xc0100000 was free.
  • pop gs breaks the stack. Watcom saves and restores GS around some routines (push gs0f a8, pop gs 0f a9). Unicorn loads the segment from a GDT it does not have, and the following stack accesses go to the low 16 bits of ESP (the symptom: a read at 0xea88 from a plain pop ebp). Hooking each 0f a8 / 0f a9 in the code section and replacing it with a move of ESP by 4 fixes it.
  • No imports on the path. pilots_update and its callees call no Windows routine; a routine that does would need the import stubbed, since the DLLs' code is not in the snapshot (only their writable data is).

For GameFrame: a snapshot runner (map, stack, segment-op hooks, a draw logger) belongs next to pe32_emu; the pop gs fix applies to any Watcom program under Unicorn.

Code: Apache 2.0. Content: CC0 1.0. No game material: bring your own copy.