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.
A bundled module's import keeps its name only when the executable
exports it as a visible global or weak symbol, as the dynamic loader
can bind it. Test local, internal and hidden executable symbols of the
same name next to global, weak and protected ones.
ValidationPolicy rejects R_X86_64_GOT32, PLT32, GOTPCREL, 32S, GOTPCRELX
and REX_GOTPCRELX for every DT_RELA and DT_JMPREL entry before the Linux
patcher runs, so the R_X86_64_32S case of the fixed-base relocation
list cannot be reached. It was the only user of R_X86_64_32S, and the
other five constants have none. Remove the case and the six constants;
no behaviour changes.
red_zone_framer frames two leaves whose 4-byte cmp %rdi,(%rsp) sits
before a jne: after an add (inflate_fast's shape) and after a load below
rsp that heads the loop and moves by the shift inside the stub, and no
operand in a stub is also moved in place. A cmp whose loop branches back
to it stays refused, the widened stub covering the branch target. The
execution test runs both framed leaves under writes below rsp.
When the instruction after an rsp operand that cannot move in place is
a branch, a rip-relative instruction or a freeing add, the operand's stub
could stay shorter than a jump and the leaf was skipped. The stub now
also takes the contiguous sequential instructions before the operand,
moving their own rsp operands by the shift; the branch-target, site and
existing-stub checks run on the widened range, and the instructions it
covers leave the in-place moves. zlib's inflate_fast, whose only operand
left is a 4-byte cmp %rdi,(%rsp) between an add and a jne, frames this
way.
The backward extension is tibzejoker's, from their comment on
boykopovar/AnyPS5#5640: with it, 243 of Grand Theft Auto V's 991
red-zone leaves frame (240 before), inflate_fast among them, and one
leaf is left with no room for a stub.
red_zone_framer's leaf whose operand at rsp sits before a rip-relative
load now frames; the one before an exit stays refused, its forward
extension reaching the exit's pops.
Co-authored-by: tibzejoker <[email protected]>
Retain DT_INIT presence when emitting the deferred Linux lifecycle slot. Check zero-valued initializers with and without preinit, native argument forwarding and return status, and the absent-tag case. Addresses the interaction with PR #6684 identified in review.