Skip to content

A value that comes from a register nobody set there: read the disassembly ​

What to know ​

2026-10-24, vh_yaw_rate (0x47a00c), airlocks_update (0x41648c).

Two traps met while porting the attitude step and the airlock doors, both invisible in the decompiler's output and both caught by the emulator on the first comparison.

  • A register kept across a call. vh_yaw_rate loads EDX = −0x600 as if it were an argument to slot_user (0x4fa844), which takes only EAX and does not touch EDX. After the call the code multiplies by EDX: the constant is the yaw's speed factor (0x2000 − 0x600 × speed). Ghidra drops the "argument" and shows a product with an undefined value. Under Watcom's register convention, check the callee's body for which registers it writes before deciding what a register holds after a call.
  • A global, not the argument. airlocks_update reads dt_fix from its global (0x59a708). A harness that passes the step only to the routines that take it as an argument leaves the global at 0, and the doors never move: 4,161 of 10,000 cases differed until the harness wrote the global too. Grep the routine for the frame timer's addresses (0x59a704, 0x59a708) before building its harness.
  • Stubbing a callee. To test vh_steer's collision response without a world, a code hook on 0x4f8c68 pops the return address, sets EAX to 1 and writes EIP: the routine returns at once with a hit. The same trick logs 0x4f0b44 and 0x4ed7c4 in the airlock case; see isolate-callees.md for callees that pop stack arguments.

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