9.0 KiB
shaders.obj exact-match log
Current disposition (2026-08-11): strict-exact and admitted. All 20 functions, all 11 target-owned
.rdataCOMDATs, and the complete 12-byte.bsspass 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-25690887e3c1c540ade41928b8e94cee254e9e4de2731bbe7f1e13ddde79433ccb3.
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
- 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.
- 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.
- 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.
- 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, andr_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
elseblock closed the last two bytes. Final result: strict exact, 736 / 736 bytes, 35 / 35 relocations, normalized SHA-256bc0e37db95c846a77a02447a81645f721a1628ff853c41aaa3072bd3b967270b.
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.