Skip to content

fix(relinker): rewrite XSAVEOPT to XSAVE under --to-rosetta - #7918

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
Kernel-Hunter:fix/rosetta-xsaveopt
Oct 24, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
Kernel-Hunter:fix/rosetta-xsaveopt

Conversation

@Kernel-Hunter

Copy link
Copy Markdown
Contributor

What

XSAVEOPT raises an illegal instruction under Rosetta. The PS5's Zen 2 has it, so code built for the console can use it without a CPUID check. With --to-rosetta it is now rewritten to XSAVE in place: 0F AE /6 with a memory operand becomes 0F AE /4, keeping the prefixes, REX and operand, the same way RDSEED becomes RDRAND.

XSAVEOPT differs from XSAVE only in the init and modified optimizations (Intel SDM volume 1, chapter 13). They let it skip writing state that is in its initial configuration or unchanged since the last XRSTOR from the same area. XSAVE writes the same XSTATE_BV and the full state, so XRSTOR restores the same registers from either area.

Not taken: CLWB (66 0F AE /6, already a NOP), MFENCE, UMONITOR, UMWAIT, XSAVE, XRSTOR, CLFLUSH. The Intel target and a plain relink are unchanged. XSAVEC also faults under Rosetta but is not converted, because it writes the compacted format. The debt entry says so.

Changes:

  • DecodedInstruction::IsXsaveopt, the XSAVEOPT table entry, and the in-place case in _matchRosetta.
  • Amd64OnlyConverterTests: rewrite checks for the plain, REX.W, RSP-relative, r12-based, RIP-relative and FS-relative forms; the neighbouring 0F AE encodings are not taken; not converted for Intel. New xsaveoptExecution runs the rewritten XSAVEOPT64, clears YMM3, runs XRSTOR and checks YMM3, XSTATE_BV and the standard-format offsets. It runs on x86-64 Linux and macOS hosts and is empty elsewhere.
  • test_to_rosetta.py now includes XSAVEOPT in the relinked fixture.
  • docs/user/USAGE.md (--to-rosetta row) and a new entry in docs/dev/debt/relinker.md.

Tested

Apple M5, macOS 27.0.1 (26A434), Apple clang, relinker-only Release build.

Under Rosetta, from a standalone clang -arch x86_64 program (sysctl.proc_translated = 1) that runs the bytes from executable memory:

48 0F AE 37 (XSAVEOPT64)     signal 4 (Illegal instruction: 4)
48 0F AE 27 (XSAVE64)        executed

Same host: XSAVEC also raises SIGILL. XSAVE64 with RFBM 7 followed by XRSTOR64 restores YMM3, XSTATE_BV reads 7, and the AVX high half is at offset 576. XGETBV reads XCR0 = 7 and CPUID (0xD, 0) gives 832 bytes, but CPUID leaf 1 reports neither XSAVE nor OSXSAVE, and leaf (0xD, 1) reports neither XSAVEOPT nor XSAVEC.

  • Native arm64 build: ctest, 207/207 pass.
  • x86-64 build under Rosetta (-DCMAKE_OSX_ARCHITECTURES=x86_64), where xsaveoptExecution actually runs: 207/207 pass, including amd64_only_converter and to_rosetta.
  • With the rewrite disabled, amd64_only_converter fails with XSAVEOPT was not rewritten to XSAVE.
  • python3 tools/check_conventions.py --base origin/main and git diff --check pass.

Not tested on Linux or Windows. The execution test is also built for x86-64 Linux, so the Linux CI job runs it natively. No title was tested, and I don't know of one that uses XSAVEOPT.

No open PR or issue covers XSAVEOPT or XSAVEC. This branch is rebased on main after #6111.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes. The tests above were run on the hardware listed.

@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

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.

Pull request Shared files not compared
PR 5021 docs/dev/debt/relinker.md
docs/user/USAGE.md
PR 5925 docs/user/USAGE.md
PR 6171 docs/user/USAGE.md
PR 6924 docs/user/USAGE.md
PR 7173 core/relinker/codegen/src/x86/Amd64OnlyInstructionMatcher.cpp
docs/dev/debt/relinker.md
PR 7642 docs/user/USAGE.md
PR 7942 docs/user/USAGE.md
PR 8042 core/relinker/codegen/tests/Amd64OnlyConverterTests.cpp
PR 8076 docs/dev/debt/relinker.md
PR 8236 core/relinker/codegen/tests/Amd64OnlyConverterTests.cpp
PR 9184 core/relinker/codegen/tests/Amd64OnlyConverterTests.cpp
PR 9228 docs/dev/debt/relinker.md
PR 9401 docs/user/USAGE.md
PR 9408 docs/dev/debt/relinker.md
docs/user/USAGE.md
PR 9508 docs/user/USAGE.md
PR 10193 docs/user/USAGE.md

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 20, 2026
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 20, 2026
@blawesom

Copy link
Copy Markdown
Contributor

Rebase handoff — rebased onto current main (a9cfea22f, clean, authorship unchanged).

Verified on Linux (CachyOS, kernel 7.2.9, GCC 16.2.1, Ninja, Release, BUILD_TESTING=ON, AMD RX 9070 XT / RADV): builds; 1717/1720 — green apart from the three known current-main failures on this stack (#7784 guest-memory, tessellation pending Mesa 26.2.6, and image_array_window_past_layer_limit — newly-arrived red flagged on #6772), none from this PR; conventions pass. The Rosetta XSAVE rewrite itself is macOS-gated, not exercised here.

To pick it up:

git fetch https://github.com/blawesom/AnyPS5 rebase/7918
git checkout <your branch>
git merge --ff-only FETCH_HEAD

Head is baafb462a.

XSAVEOPT raises an illegal instruction under Rosetta on an M5 running
macOS 27.0.1, as XSAVEC does, while XSAVE and XRSTOR save and restore
x87, SSE and AVX state in the standard format. The PS5's Zen 2 has
XSAVEOPT, so code built for it can use the instruction without a CPUID
check.

XSAVEOPT differs from XSAVE only in the init and modified optimizations:
it may skip writing state that is in its initial configuration or
unchanged since the last XRSTOR from the same area. XRSTOR restores the
same state from the area XSAVE writes, so --to-rosetta rewrites
XSAVEOPT (NP 0F AE /6, memory operand) to XSAVE (/4) in place, keeping
the prefixes and the operand, as RDSEED becomes RDRAND. CLWB (66 0F AE
/6), MFENCE, UMONITOR, UMWAIT and the Intel target are left alone.
XSAVEC is not converted: it writes the compacted format.

The converter tests check the rewrite for the plain, REX.W,
RSP-relative, extended-base, RIP-relative and FS-relative forms, check
that the neighbouring 0F AE encodings are not taken, and execute the
rewritten XSAVEOPT64 followed by XRSTOR on YMM3 in the x86-64 build.
The --to-rosetta integration test now covers XSAVEOPT as well.
@adriadam10
adriadam10 force-pushed the fix/rosetta-xsaveopt branch from 0c93987 to ce6c2a0 Compare October 24, 2026 09:03
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 24, 2026
@adriadam10
adriadam10 merged commit b84322d into boykopovar:main Oct 24, 2026
12 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the XSAVEOPT decoder (66 = CLWB, F3 = CLRSSBSY, F2 and the register form are left alone), the ModRM rewrite /6 to /4 with prefixes, REX and operand kept, the converter tests (plain, REX.W, RSP, r12, RIP-relative, FS, neighbouring 0F AE forms, Intel unchanged), xsaveoptExecution on x86-64 Linux, and the USAGE and debt entries. Rebased onto main (conflicts in Amd64OnlyConverterTests.cpp and docs/dev/debt/relinker.md, both sides kept); the relinker tests pass on the rebased branch; merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants