Repository navigation
fix(relinker): rewrite ALU reads of guest TLS through %fs in macOS output - #6419
Conversation
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
jotitadev
left a comment
There was a problem hiding this comment.
Ran this on a Mac, since the stubs were only executed in an emulator so far.
Machine: Apple M2 Max, macOS 27.2, AppleClang (Xcode 27). Head 4c4980e0b merged without a commit onto main 03c4cb5.
Suites (relinker-only Release)
- arm64: 174/174.
- x86_64 under Rosetta with
/usr/bin/python33.9.6: 171/174. The 3 failures (pr_overlap_tools,release_package,linux_fixed_base) fail the same way onmainwith Python 3.9. macos_tls_aluwith only the test applied tomain: fails on both arches. With the fix: passes.
Stubs executed under Rosetta 2
I converted each form with --macos, mapped the output's __ELF* and __APS5* segments at their addresses in an x86_64 process (sysctl.proc_translated = 1), stored a real pthread_key_create key in the key slot the stub loads, and set its value with pthread_setspecific to a guest TCB whose word at offset 0 points to itself. A trampoline loaded all 15 GPRs and RFLAGS, called the patched site, and saved them back. The slow path was never reached (its callee is not bound in this harness), so every trial went through the %gs-indexed TSD lookup.
Forms, 1000 trials each with random registers, flags, guard and TLS words (a quarter set every register to the guard): sub rax/rcx, %fs:0x28, xor r10, %fs:0x28, adc rdx, %fs:-8, sbb rax, %fs:-8, cmp r8, %fs:0, and r15, %fs:-16, add rax, %fs:0, or rbx, %fs:0x28, sbb r11, %fs:0x28, adc rax, %fs:0x28.
Result: 11000/11000. The destination register matched the reference, every other GPR was unchanged, and CF PF AF ZF SF OF matched, with AF skipped for the logical ops. adc/sbb consumed the incoming carry correctly.
Not run: a real title. On macOS, main still can't link the runtime the output needs.
Written with AI assistance (Claude Code). I ran the builds and tests above on my machine.
|
Hardware run on Apple silicon. macOS 26.7.1, Apple M2 (8 GB), Rosetta 2, AppleClang 21.0.0. Relinkers built (
AI-assisted: yes |
…te ALU reads of guest TLS through %fs in macOS output (@DavidSamir) Taken from the open upstream pull request so the macOS integration branch carries every piece of the port that is already under review, instead of re-implementing it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
Morrowind (OpenMW, PPSA99630) cannot be converted for macOS on
main:64 48 2b 0c 25 28 00 00 00issub %fs:0x28,%rcx, the stack-protector check that compilers emit at a function's end: it subtracts the guard in the thread control block from the saved copy and branches on the flags. PS5MC (PPSA99420) stops on the same check (sub %fs:0x28,%rax,64 48 2b 04 25 28 00 00 00) once #6410 lets it get past its first refusal. After this PR, Morrowind stops on its emptyPT_TLS, which #6448 handles. The Windows TLS rewriter converts ALU reads of%fs:disp32(add,or,adc,sbb,and,sub,xor,cmpinto a 64-bit register); the macOS scan inMacOsImage.cppaccepts only loads and the stack-guard store, and refuses the module.The macOS scan now accepts the same ALU reads as the Windows rewriter, and the writer gives each one a stub like a load's: it finds the guest thread pointer through the pthread key and reads the value at the displacement, then restores the guest's flags before applying the operation, so
adcandsbbsee the guest's carry and the operation's flags reach the branch after it. Forraxthe stub swaps the value with the savedraxon the stack and applies the operation to that memory operand. The displacement check of loads applies unchanged. Load and store stubs are byte-identical tomain.Four commits:
fix(relinker): rewrite ALU reads of guest TLS through %fs in macOS output.test(relinker): rewrite stack-guard subtractions through %fs for macOS: a newmacos_tls_alutest convertssub %fs:0x28,%raxandsub %fs:0x28,%rcxwith--macosand checks that the access is gone and the stub applies the operation.test(relinker): cover other ALU operations and registers reading guest TLS for macOS:xorintor10,adcfrom the TLS block (%fs:-8),cmpagainst the thread pointer (%fs:0).test(relinker): keep refusing a macOS TLS ALU read outside the thread TLS block.Tested
Windows host (4c4980e on
main0afa6a6, Windows 11 10.0.26300, WinLibs GCC 15.2.0 r7, Release). The relinker writes macOS output on any host:tools/check_conventions.py --base origin/main: passed.tools/pr_overlap.py: no overlap with open pull requests.-DANYPS5_RELINKER_ONLY=ON -DBUILD_TESTING=ON), the relinker builds at each of the four commits and every test that runs passes. The 27 that fail are the same at every commit and come from that build: 25 test programs it does not compile,windows_diagnostic_fixture_isolation, which copies one of them, andcheck_main_sync, which reads git's UTF-8 output as cp1252 on this host (sp ace é.txt) and fails the same way onmain. The change is inMacOsImage.cpp, which only the relinker links, so the relinker-only build runs every test that can see it.macos_tls_alufails without the fix: withmain's relinker,sub-rax-stack-guardstops withUnsupported macOS guest TLS instruction (bytes: 64 48 2b 04 25 28 00 00 00).sub raxandsub rcxagainst%fs:0x28,xor r10, %fs:0x28,adc rdx, %fs:-8,sbb rax, %fs:-8,cmp r8, %fs:0,and r15, %fs:-16,add rax, %fs:0,or rbx, %fs:0x28; a quarter of the trials set every register to the guard, sosubandcmpalso produce zero. Two plain loads ran as controls and matched as well.macos|tlstests pass (guest_force_tls_destructoris not run because only the relinker target was built).main's relinker against this branch's, same arguments: all 79 outputs are byte-identical, because neither title this unblocks converts with this PR alone. Morrowind (PPSA99630) gets pastsub %fs:0x28,%rcxand stops onGuest TLS access without a non-empty PT_TLS(fix(relinker): convert stack-guard and thread-pointer reads with an empty PT_TLS for macOS #6448); PS5MC (PPSA99420) still stops first on the refusal fix(relinker): skip prefixed decodings inside an earlier instruction in the macOS TLS scan #6410 removes. With fix(relinker): skip prefixed decodings inside an earlier instruction in the macOS TLS scan #6410, this PR and fix(relinker): convert stack-guard and thread-pointer reads with an empty PT_TLS for macOS #6448 merged together, both convert, and 78 of the 79 titles convert (47 onmain, whose 47 outputs are byte-identical); the 79th is Prospero Win (PPSA99995), whose GS instructions fix(relinker): trap guest GS accesses in macOS output instead of refusing the module #6458 handles.Not run on macOS: I have no Mac. The stubs were executed in an emulator instead (above).
Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)