fix: respect blocked_relocation_sources in x86 abs32 reconstruction#2
Merged
Conversation
The `noreloc` symbol attribute (and config `block_relocations` sources) populate `blocked_relocation_sources`, but neither x86 abs32 pass consulted it: - `resolve_abs32_candidates` (analysis/x86.rs), which resolves the abs32 candidates collected during analysis, and - `reconstruct_abs32_relocations_by_scan` (util/coff.rs), the /FIXED image data scan. As a result, data whose contents merely look like in-image pointers still got relocations invented for it. Concrete case from BW1: UTF-16 string literals — e.g. the wide chars "X\0_\0" in "MAX_DEPTH" read as 0x005F0058, which lands in the image, so the scan stamped a reloc with addend over the string and the extracted bytes no longer matched the compiler's comdat. Skip candidates whose source address falls inside a blocked range in both passes, making `noreloc` effective for PE/COFF data. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014kEDAMC4whgcjekmVde9PA
Pre-existing on coff_prototype; CI runs latest stable clippy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014kEDAMC4whgcjekmVde9PA
- anyhow 1.0.100 -> 1.0.103 (RUSTSEC-2026-0190) - crossbeam-epoch 0.9.18 -> 0.9.20 (RUSTSEC-2026-0204) - ignore RUSTSEC-2026-0194/0195: quick-xml 0.36 is pinned by nodtool 1.4; the fixed quick-xml (>=0.41) is only reachable via nodtool 2.0 alphas Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014kEDAMC4whgcjekmVde9PA
Member
|
Dtk has a |
handsomematt
added a commit
to openblack/bw1-decomp
that referenced
this pull request
Jul 12, 2026
Implement the LHLib text script engine (BW1W120 0x7E7260-0x7EA0B0) as the genuine template it was: LHScriptX<T>, LHScriptCommandX<T>, LHScriptPramX<T> and LHScriptVariable<T>, instantiated for char and wchar_t through the original's own bodge_to_force_compilation_of_versions(). Static data (Commands/Conditions/NamesToCondition tables, the Pram buffers and LastLineParsed) reconstructed verbatim from the binary. Key build-model findings, all evidence-driven: - The TU was compiled with inlining disabled (/Ob0) plus /GX: every tiny header-inline member (LHScreen::Depth/MaxDepth, LHSpriteList ctor, LHStringOps wrappers, makechar/fromchar) exists as a called comdat inside the TU's range. Depth/MaxDepth move from LHScreen.cpp into the header. - The memory-tracking operator new has a matching placement delete (declared in LHWin.h); its presence is what gives /GX functions using new(__FILE__, __LINE__) on ctor types their EH frames, and its calls are the unwind funclets parked at 0x8A7B20+. - #line pins reproduce the original __FILE__/__LINE__ values (C:\Dev\Libs\lionhead\lhlib\VER5.0\LHScript.cpp, lines 312/333/355/737/ 1032/1035), matching both the pushed line immediates and the path string. - LH_RETURN's real enumerator names (LH_OK/LH_FAIL/LH_ERROR/LH_NO_MEMORY) fall out of the script condition tables; the enum moves to LHReturn.h. - LHStringOps<char>/<wchar_t> CRT wrappers land in LHString.h (name fabricated); LHText gains LoadFont and the LHSpriteList ctor/Set. Result: 29 of 44 target functions at 100.0% instruction match and all 98 data objects (tables, both Pram statics, ~90 string literals) matching. ScanLine, ProcessCommand and GetConditionValue remain nonmatching with TODO notes; switch jump-table symbols are capped by diff-tool representation, not bytes. The wide string literals required decomp-toolkit v0.0.20 (dtk_tag bumped): its abs32 reconstruction previously ignored noreloc symbols and invented relocations inside UTF-16 text whose characters look like in-image pointers (openblack/decomp-toolkit#2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
bwrsandman
pushed a commit
to openblack/bw1-decomp
that referenced
this pull request
Jul 12, 2026
Implement the LHLib text script engine (BW1W120 0x7E7260-0x7EA0B0) as the genuine template it was: LHScriptX<T>, LHScriptCommandX<T>, LHScriptPramX<T> and LHScriptVariable<T>, instantiated for char and wchar_t through the original's own bodge_to_force_compilation_of_versions(). Static data (Commands/Conditions/NamesToCondition tables, the Pram buffers and LastLineParsed) reconstructed verbatim from the binary. Key build-model findings, all evidence-driven: - The TU was compiled with inlining disabled (/Ob0) plus /GX: every tiny header-inline member (LHScreen::Depth/MaxDepth, LHSpriteList ctor, LHStringOps wrappers, makechar/fromchar) exists as a called comdat inside the TU's range. Depth/MaxDepth move from LHScreen.cpp into the header. - The memory-tracking operator new has a matching placement delete (declared in LHWin.h); its presence is what gives /GX functions using new(__FILE__, __LINE__) on ctor types their EH frames, and its calls are the unwind funclets parked at 0x8A7B20+. - #line pins reproduce the original __FILE__/__LINE__ values (C:\Dev\Libs\lionhead\lhlib\VER5.0\LHScript.cpp, lines 312/333/355/737/ 1032/1035), matching both the pushed line immediates and the path string. - LH_RETURN's real enumerator names (LH_OK/LH_FAIL/LH_ERROR/LH_NO_MEMORY) fall out of the script condition tables; the enum moves to LHReturn.h. - LHStringOps<char>/<wchar_t> CRT wrappers land in LHString.h (name fabricated); LHText gains LoadFont and the LHSpriteList ctor/Set. Result: 29 of 44 target functions at 100.0% instruction match and all 98 data objects (tables, both Pram statics, ~90 string literals) matching. ScanLine, ProcessCommand and GetConditionValue remain nonmatching with TODO notes; switch jump-table symbols are capped by diff-tool representation, not bytes. The wide string literals required decomp-toolkit v0.0.20 (dtk_tag bumped): its abs32 reconstruction previously ignored noreloc symbols and invented relocations inside UTF-16 text whose characters look like in-image pointers (openblack/decomp-toolkit#2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The
norelocsymbol attribute (and configblock_relocationswith asource) populateblocked_relocation_sources, but neither x86 abs32 pass consulted it:resolve_abs32_candidates(src/analysis/x86.rs) — resolves the abs32 candidates collected during analysis, andreconstruct_abs32_relocations_by_scan(src/util/coff.rs) — the/FIXEDimage data scan.So
norelocparsed fine but had no effect for PE/COFF data, and data whose contents merely look like in-image pointers still got relocations invented for it.Concrete case from BW1W120's
LHScript.cppunit: UTF-16 string literals. The wide chars"X\0_\0"inL"MAX_DEPTH"read as dword0x005F0058, which lands inside the image, so the data scan stamped a reloc (rewriting the extracted bytes to the addend form18 01 00 00) and the split object's string no longer byte-matched the compiler's??_C@comdat:With this fix, marking the affected string symbols
norelocinsymbols.txtkeeps them as raw bytes; all ~90 string literals in that unit now match 100%.Both passes get the same 4-line guard: skip a candidate whose source operand address falls inside a blocked range.
Tested against
runblack-decrypted.exe(BW1W120): the LHScript unit's data goes from 16 corrupted string objects to all 98 data objects matching; no changes to any other unit's output (verified with a full report diff against a pre-change baseline).Note for the release: a binary built from the
v0.0.19tag also rejects a pre-existingtrnsctrl.objsplit/symbol overlap in the bw1 config that the published v0.0.19 binary tolerated (fixed on the bw1 side by giving?_GetRangeOfTrysToCheckan explicitsize:0x7B), so the published binary appears to predate the tag.🤖 Generated with Claude Code
https://claude.ai/code/session_014kEDAMC4whgcjekmVde9PA