Files
Cesarus85--mjolnir-vr/docs/object_matching_logs/shaders_obj.md
T
2026-08-13 05:20:30 -07:00

9.0 KiB

shaders.obj exact-match log

Current disposition (2026-08-11): strict-exact and admitted. All 20 functions, all 11 target-owned .rdata COMDATs, and the complete 12-byte .bss pass the hardened comparison and ownership gates. The experiment history below is retained so future work does not repeat the rejected source-shape search.

Current-campaign revalidation (2026-08-13)

The completed but unintegrated result was transplanted onto campaign commit 738deff8 and independently rebuilt with XDK 3911. The hardened comparator again reported all_equal: true for all 20 functions, including exact internal jump-table destinations and all external relocation identities/addends. A full 466-object halobetacache_build completed successfully. The complete current tooling suite passed 173/173 tests. The ordinary ninja progress target could not be regenerated in this isolated lane only because cachebeta.exe is not provisioned there; no strict comparison or build depends on that executable.

The house/Berth audit was repeated: parameters remain one per line; every no-argument parameter list uses void on its own line; void functions end in explicit return;; typed shader access macros wrap the type-verifying getter; and the exact BSS uses natural layout rather than alignment pragmas. There is no assembly, volatile forcing, undefined behavior, byte patch, or flag change.

Scope and admission standard

Target: January 14, 2002 Xbox source/shaders/shaders.obj, compiled with XDK 3911 CL 13.00.9254.1 and the repository flags (/O2 /Oy- /DDEBUG /Dxbox). Credit requires strict section_infos_equal equality for all 20 functions plus the target-owned .rdata and 12-byte .bss. No fuzzy score, assembly, byte patch, undefined behavior, forced inline, alignment pragma, compiler-flag change, or relocation-destination substitution is admissible.

Baseline

The committed skeleton had 12/20 strict-exact functions and 287/2,353 meaningful target code bytes. The missing/non-strict set was:

  • shader_get_vertex_shader_permutation — target 288 bytes / 18 relocs.
  • shader_is_mirror — target 80 / 2.
  • shader_is_decal — target 144 / 10.
  • shader_is_water_decal — target 80 / 2.
  • shader_ignores_effect — target 80 / 2.
  • shader_environment_texture_animation_evaluate — target 336 / 25.
  • shader_texture_animation_evaluate — target 736 / 35.
  • numeric_countdown_timer_update — code bytes exact, but its BSS relocation destination was wrong.

The target owns no .data, eleven external SelectAny .rdata string COMDATs (478 literal payload bytes), and one ordinary 12-byte zero-initialized .bss. The original candidate BSS was only 9 bytes and ordered the hidden previous-time static before the public on/off byte.

Proven cross-build/salvage findings

HCEA source and PDB information are used only for names and control-flow hypotheses; January bytes remain authoritative. A prior disposable January lane proved exact readable-C bodies for the four shader predicates and the environment animation evaluator. Those bodies were adapted here using typed SHADER_GET_* accessors and January-proven layouts. The environment evaluator uses a 32-bit real time_value; the later HCEA double signature is not valid for January.

Current measurements

After rebuilding the adapted bodies:

  • shader_is_mirror: strict exact, 80 bytes / 2 relocs.
  • shader_is_decal: strict exact, 144 / 10.
  • shader_is_water_decal: strict exact, 80 / 2.
  • shader_ignores_effect: strict exact, 80 / 2.
  • shader_environment_texture_animation_evaluate: strict exact, 336 / 25, normalized SHA-256 90887e3c1c540ade41928b8e94cee254e9e4de2731bbe7f1e13ddde79433ccb3.

This raises the working result to 17/20 strict functions. The first direct permutation transcription compiled to 304 bytes / 19 relocs because it emitted both transparent cases' second typed-access calls independently. January is 288 / 18 and shares the second access/screen-space tail and the lit-bit tail between type 5 and type 6.

Active experiment ledger

  1. Direct macro-expression permutation body — rejected. 304 / 19 versus target 288 / 18. It preserved semantics but duplicated one helper call and did not encode January's shared tails.
  2. Next experiment: reproduce the previously measured 288 / 18 local-view form, then express the two January shared tails explicitly if VC7 chooses the wrong block order.
  3. Texture evaluator: recover January expression/store order from the target and compile the HCEA topology as a hypothesis; measure all 35 relocation identities and x87 ordering before accepting it.
  4. BSS: test declaration/linkage/source-order shapes in a disposable build; accept only a 12-byte BSS with anchors at +0/+4 and previous time at +8, without changing any already-exact timer code.

Measured follow-up:

  • Per-case local-view form — best retained. It reproduces the target size and relocation count (288 / 18) and is byte-identical through +0xB4. Its remaining difference is block placement: VC7 emits the generic shared work before the Chicago initial calculation, while January emits both initial calculations before the shared screen-space and lit tails.
  • One function-scope transparent pointer plus explicit shared labels — rejected. It over-merged the two paths, compiling to 272 / 18 and changing the prologue and jump table. The source-level pointer lifetime was not free; it changed allocation before the intended tail window. Restored the 288 / 18 local-view form.

Texture evaluator experiments

  • Preinitialize U/V/R to 1.0 and conditionally overwrite — rejected. This shortened the function to 704 / 35 because VC7 eliminated the three explicit default branches. The target is 736 / 35.
  • Separate input, animation-result, and total locals — near match only. This reproduced 736 / 35 with every relocation address, type, destination, and addend exact, but left ten argument-home-slot displacement bytes different.
  • Reuse each channel input in place — accepted. Assigning the periodic result back into u_input, v_input, and r_input, then adding the U/V translation offsets back into those same variables, reproduced January's slot chains: U at [ebp+0x28], V at [ebp+0x08], and R at [ebp+0x2c]. This reduced the entire function to two differing bytes.
  • Null-animation defaults ordered V, U, R — accepted. January stores the three 1.0 defaults in that order. Reversing only U/V in the else block closed the last two bytes. Final result: strict exact, 736 / 736 bytes, 35 / 35 relocations, normalized SHA-256 bc0e37db95c846a77a02447a81645f721a1628ff853c41aaa3072bd3b967270b.

The October executable has the same relocation-masked body as January. It also confirms that January has only the zero-angle shortcut; the later HCEA 360.0f shortcut and double time parameter are not valid for this target.

Countdown-timer ownership

The accepted representation is one external four-byte millisecond counter followed by one external naturally aligned state structure containing the on/off byte and the previous game time. It emits an exact 12-byte zeroed BSS:

struct numeric_countdown_timer_state
{
	boolean on;
	long previous_game_time;
};

long numeric_countdown_timer_milliseconds = 0;
struct numeric_countdown_timer_state numeric_countdown_timer_on = { 0 };

All five timer functions remain strict-exact, including relocation identities; numeric_countdown_timer_update resolves the previous-time field as _numeric_countdown_timer_on + 4. No .data, alignment pragma, or explicit padding is needed.

Plain-English status

All eight formerly missing/non-strict functions now reproduce the original machine code exactly, and the complete BSS layout is exact. The final permutation breakthrough was a readable asymmetric control-flow spelling: the generic non-screenspace path keeps a local copy of the lit-bit test, while the screenspace path and both Chicago paths converge on test_lit. VC7 cross-jumps the duplicate generic test into the shared forward tail, yielding January's block order without assembly, volatile forcing, undefined behavior, or a compiler flag change.

Final strict totals are 20/20 functions, 2,528/2,528 padded .text bytes, and 126/126 relocations. All eleven target-owned SelectAny .rdata string COMDATs are exact (478 bytes, zero relocations), and the ordinary 12-byte zero-initialized .bss is logically exact with external anchors _numeric_countdown_timer_milliseconds at +0 and _numeric_countdown_timer_on at +4. The target splitter stores twelve zero bytes physically while MSVC correctly emits fileless BSS; the hardened logical comparison proves identical size, bytes, relocations, flags, and ownership.

Ordinary objdiff under-reports shader_get_vertex_shader_permutation, shader_is_decal, and numeric_countdown_timer_get because csplit and VC7 spell compiler-local labels differently. The hardened semantic ledger re-verifies complete normalized bytes and relocation destinations before crediting those three false negatives.