windows_named_imports, windows_trace_imports, windows_guest_weak_imports and
guest_module_identity run converted programs that stop on a missing import,
then remove their temporary directory. Windows keeps the modules of such an
exited process open for a short time after the process handle is signaled, so
under parallel ctest the removal fails with PermissionError on a .prx that
program loaded: with Defender real-time protection off, 3 or 4 of these tests
failed in each of three runs of ctest --repeat until-fail:10 -j 16 over the 69
tests that run converted programs.
Add fixture_directory to guest_import_fixtures, a temporary directory whose
removal retries on PermissionError for at most 10 s, and use it in the four
tests. Their checks are unchanged.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
windows_dependency_diagnostics rewrites the fixture images right after the
diagnostic runner exits. The runner ends with an unhandled RaiseException of
STATUS_DLL_NOT_FOUND, and Windows fault handling keeps the exited process's
image files open for a short time after its handle is signaled: on Windows 11
22621 the Restart Manager names the exited runner as the holder and the file
opens 37 to 153 ms later. The rewrite then fails with ERROR_SHARING_VIOLATION,
and the final removal of the fixtures with access denied. Retry opening a
fixture while it fails with a sharing violation and the removal while it fails
with access denied, for at most 10 s each; every other failure still fails the
test at once.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
MCOMMIT becomes STC plus NOP padding and RDPRU goes through a
runtime-checked stub returning the host TSC for MPERF/APERF while
other selectors yield zero, with converter and execution tests.
docs/dev/debt/relinker.md records the new lowering and its unverified
assumptions.
The padding bound in buildGraph's decoding loop skipped worklist targets inside the trailing zero region without decoding them, so malformed mandatory roots were accepted silently and complete instructions at targeted zero offsets lost their reachable marking. Decode the first instruction at each popped target against text.size() and keep the codeSize bound for sequential fall-through only. Covers the entry, extra-entry, branch-target, complete-zero-instruction and zero-immediate cases in the direct API test and in the CLI fixture.
buildGraph fell through from the entry points into the segment's zero
padding; an odd-length zero tail left a lone 0x00 the decoder needs a
ModRM byte for, and the non-speculative walk let that truncation escape
the pipeline, so unused-filter=1 exited 2 on input the other levels
convert. Bound the walk before the trailing zeros the way
StrictReachability does; mandatory roots still decode strictly.
unused-filter=1 kept a non-PLT import only when reachable code addresses its relocation exactly through a RIP-relative operand. That test only fits GLOB_DAT slots. An R_X86_64_64 import in a table read at an offset, such as a vtable entry called through lea rax,[rip+table]; call [rax+8], was dropped although it is used, and of a general dynamic TLS pair only DTPMOD64 was kept, so DTPOFF64 lost its relocation. The GOT access check now applies to GLOB_DAT relocations only; other import relocations are kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Linux executable sorts its PT_LOAD entries, but guest modules (*.guest.prx) kept them in the input table order. A module whose data segment comes before its text segment in the table was written with PT_LOAD entries out of address order, which the gABI forbids: glibc reserves the span from the first to the last entry, so with 0x2000, 0x1000, 0x4000 it reserved 0x2230 bytes instead of 0x3230 and mapped the text below the reservation. The PT_LOAD entries are now sorted in place, as for the executable.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Code analysis rejected R_X86_64_64, GLOB_DAT and JUMP_SLOT relocations whose symbol index is 0 (STN_UNDEF) with 'invalid relocation symbol', so the Windows and macOS conversions failed while Linux converted the same input. The pipeline already resolves such relocations to 0 plus the addend, as the gABI defines and as the relinker technical debt entry records for null symbol entries; only an all-zero entry at a nonzero index was accepted. Index 0 is now treated as an import slot like that entry.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The guard rejected every patch below the end of the program header
table, which is correct only while the table sits at the start of the
file. Outputs whose table moved into the extra block refused patches
into their first PT_LOAD, so game_patches failed once synthesis added
a header. Overlap is now checked against the ELF header and the table
range itself.
ProgramLayoutRangeTests.cpp includes this header first, and libc++ does
not provide size_t through <cstdint>, so the macOS relinker jobs failed
to compile the test.