Repository navigation
Conversation
…adding The Windows TLS rewriter only patches FS-relative instructions that CodeInstructionCollector decodes. Code that no symbol, unwind range or root reaches is covered by a linear sweep that starts after int3 padding and stops at the first instruction beginning with two zero bytes, so zero-filled bytes are not read as code. The .NET NativeAOT homebrew titles pad between functions with zero bytes instead of int3 and have unwind entries for only part of their code. In Prospero Vibrate (PPSA99920) the sweep ended at the padding after the first function. Functions reached only through switch jump tables, which the control-flow graph does not follow, or through pointers it cannot resolve kept 105 of 670 FS loads unpatched: 84 `mov reg, fs:[0x28]` stack-guard reads (65 into rax, 19 into rcx) and 21 `mov rax, fs:[0]` thread-pointer reads. The title faulted reading address 0x28 within a second of start. The sweep now treats a zero run that follows a jump, call, return or trap and ends at the next 16-byte boundary as alignment padding, and continues at that boundary. A call counts because a function can end in a call to a noreturn function. Zero fill after straight-line code, or a whole zero 16-byte block, still ends the sweep as before. All 670 FS loads in PPSA99920 are now patched, as are the 102 of 685 in Prospero Explorer (PPSA99109) and the 103 of 718 in Prospero Multi Tools (PPSA99110). New tls_function_coverage padding cases: loads behind zero padding after a return, a call and a jump, with 13, 2, 1 and 5 zero bytes, are patched; a load behind zero fill after a nop is left unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Merged upstream as boykopovar#2821 (fccfbee). |
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.
What
On Windows the relinker rewrites FS-relative guest TLS reads, but only for instructions that
CodeInstructionCollectordecodes. Code that no symbol, unwind range or root reaches is covered by a linear sweep. That sweep starts after int3 padding and stops at the first instruction beginning with two zero bytes, so zero fill is not read as code.The .NET NativeAOT homebrew titles pad between functions with zero bytes instead of int3, and they have unwind entries for only part of their code. In Prospero Vibrate (PPSA99920) the sweep ended at the padding after the first function. Functions reached only through switch jump tables (which the control-flow graph does not follow) or through unresolved pointers kept 105 of 670 FS loads unpatched: 84
mov reg, fs:[0x28]stack-guard reads and 21mov rax, fs:[0]thread-pointer reads. The title faulted within a second of start:The sweep now treats a zero run that follows a jump, call, return or trap and ends at the next 16-byte boundary as alignment padding, and continues at that boundary. A call counts because a function can end in a call to a noreturn function. Zero fill after straight-line code, or a whole zero 16-byte block, still ends the sweep as before. Every site found still goes through the TLS builder's existing checks, so an unsupported form still fails hard.
Tested
Windows 11, WinLibs GCC 15.2.0 r7, NVIDIA RTX 5070 Laptop.
tls_function_coveragegains padding cases. Loads behind 13, 2, 1 and 5 zero bytes after a return, a call, a return and a jump are patched. A load behind zero fill after anopis left as it was. The new cases fail with the old relinker.zero-filled-after-paddingstill passes.app.exe: PPSA99920 105 → 0, Prospero Explorer (PPSA99109) 102 → 0, Prospero Multi Tools (PPSA99110) 103 → 0.app.exeand all 42 converted guest modules are identical apart from their time stamps.check_conventions.pypassed.pthread_sigmask(feat(libkernel): implement pthread_sigmask boykopovar/AnyPS5#2106) and preadv/pwritev/sync (feat(libkernel): export preadv, pwritev and sync #21) to get that far, so those were merged locally for that run only.Not handled: switch jump tables are still not followed, so code behind other fill patterns could still be missed.
Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt.mdfiles or images added to the repository🤖 Generated with Claude Code