Walk each macOS function import before the guest entry and pass it through TraceImport_nid_no_patch, as Linux and Windows already do. An x86-64 libc build records the call and prints it on SIGABRT.
The command-line relinker skips an ELF module whose file name extends
another module's in the same directory when both have the same SONAME, a
dumper's backup such as libX.prx.esbak (#7380). That check lives in the
CLI's ReadModules, so the online converter, which hands every ELF in
sce_module/ straight to Conversion, still stops on such a layout with
"Ambiguous guest dependency name: libX.prx".
The check moves into the relinker core as RemoveBackupCopies, which
Conversion::Convert now runs before patching or converting modules and
reports through the progress messages, so the browser prints the same
"Skipping backup copy" lines. ReadModules uses the same function, so the
command line and --verify-patches behave as before.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Autorun added the execute bits with an unconditional chmod, even when the
output already had them. On macOS a chmod changes the file's ctime, and
Rosetta then throws away its translation of an x86_64 executable and
translates it again on the next exec, about 0.11 s per run on an M2 Max.
autorun_exit_status paid that on every POSIX run: it chmods the child and
also renames it once per quoting case, and a rename changes the ctime too.
On the x86_64 macOS relinker job it takes 5 s at the median and timed out
once at its 20 s limit, against 0.2 s on arm64. Autorun now only calls
chmod when an execute bit is missing, and the test runs symlinks to
itself instead of copying and renaming the executable. It also checks
that the executable's ctime does not change and that Autorun still makes
a non-executable output executable.
Guest module discovery skipped the input executable and the
--executable check rejected an executable converted twice through
std::filesystem::equivalent, which MinGW reports as false for hard links
whose names give different permissions, such as .bin and .exe. Move the
GetFileInformationByHandle comparison to Io::SameFile and use it for
these checks and for SameOutputFile.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Linux entry stub now passes each traced import through libc.prx's
TraceImport_nid_no_patch before it calls the guest entry, and stores the
returned thunk in the import's slot. The same imports are traced as on
Windows: functions bound through a PLT slot or a GOT slot, without an
addend, and not weak. TraceImport_nid_no_patch is bound eagerly through
an added GLOB_DAT relocation, so a libc.prx without it fails at load.
Each slot's page is made writable with mprotect first, so slots inside a
PT_GNU_RELRO range can be replaced.
--trace-imports now requires libc.prx among the libraries on Linux too,
and is refused with --macos.
Ruffle (PPSA68091), VLC (PPSA85300) and XPSemu (PPSA97358) read
app0/imports.txt, whose import slot addresses assume the executable's
lowest ELF load page at 0x400000, and dereference them at once. macOS
output always placed that page at 0x140010000, so all three fault on
their first slot read. Linux and Windows have --linux-fixed-base and
--windows-fixed-base for this; macOS had no equivalent.
--macos-fixed-base <address> builds the load image so that the lowest
ELF load page is at the address, as --windows-fixed-base does. The
Mach-O header takes the 64 KiB below it and __PAGEZERO ends there. The
executable is MH_EXECUTE without MH_PIE, so dyld does not slide it. The
address must be 64 KiB aligned, from 0x20000 through 0x7fffffff0000,
and an image ending past the macOS user address space is refused.
A per-game relinker-patches.toml (or --patches) replaces verified bytes in
the input executable and bundled modules before conversion. Entries are
checked against the expected bytes and against every in-place writer,
the ELF header range and relocation targets. An <output-stem>.patches.toml
manifest records the applied entries, and --verify-patches checks an input
or a converted output. With no patch file the output is unchanged.
Windows writes an exception frame directly below RSP, so a fault resumed on
a guest thread overwrites values a System V leaf function keeps in its red
zone. With --frame-red-zone, a leaf function with a
push rbp; mov rbp, rsp; push ... prologue that reads or writes below its
pushes gets two kinds of trampoline: the prologue lowers RSP by 128 bytes
after its pushes, and each pop ...; pop rbp; ret exit raises it back first.
Sites a branch enters, sites shorter than a jump and sites over a --to-intel
stub are skipped; the conversion reports the framed and skipped counts.
With --trace-imports the entry stub resolves TraceImport_nid_no_patch
in libc.prx and passes each function import through it before writing
the slot: every PLT slot, and a GOT slot only when the original symbol
is a function, so data imports such as __stdoutp keep their address.
Without the option the output is unchanged.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The relinker's repeatable --executable converts another executable of the
title beside the output, sharing its libs, app0 and guest modules.
sceSystemServiceLoadExec maps /app0 paths to those executables, passes the
argument list on the new command line and finds the main executable through
APS5_EBOOT. RetroArch (PPSA99169) starts its frontend picker this way.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Relinks the ELF modules of extra directories under the module parent directory. Modules the executable or another module needs start with the executable; the others are initialized when the title loads them with sceKernelLoadStartModule, with its start arguments (Windows: __aps5_guest_initialize export; Linux: left out of DT_NEEDED).
Squashed onto main by the reviewer (history had a merge commit).
Rosetta runs AVX2, FMA, BMI1/2, F16C and MOVBE, but, unlike an Intel
host, it has neither RDSEED, CLWB nor RDPID. --to-rosetta converts
everything --to-intel does and lowers these three as well:
- RDSEED becomes RDRAND (the /6 form of the same opcode), which also
returns a random value and sets CF.
- CLWB only writes a cache line back, so it becomes a NOP of the same
length.
- RDPID becomes a load of 0 through an optional stub: Rosetta's TSC_AUX
is a constant, not a processor index, so every thread reports
processor 0. A site with no movable instruction after it for the jump
is kept.
The flag implies --to-intel and conflicts with --windows. It is
independent of --macos: it only changes what the conversion produces, so
--macos alone leaves these instructions as they are, as on an Intel Mac,
and a title for Rosetta is relinked with --macos --to-rosetta. Intel
output is unchanged: the target is a parameter of the converter, Intel by
default.
The MinGW CRT delivers argv to main as ANSI code page bytes, and every narrow string became a filesystem path through the same code page, so a game in a directory with characters outside the code page failed to open (#2692). Read the command line as Unicode (wmain via -municode), keep paths as UTF-8 strings, convert at the filesystem boundaries through Io::NativePath and Io::Utf8Path, and run the --autorun output through CreateProcessW.
(cherry picked from commit 30a5181f8a)
The guest image reader and the module builder already produce a
platform-neutral GuestImage; --macos adds a third writer next to the ELF
and PE ones. The executable and every bundled module become x86-64 Mach-O
files (modules as dylibs in app0/sce_module) that run under Rosetta on
Apple silicon.
FreeBSD code reaches its thread pointer through %fs, which macOS cannot
set, so the writer rewrites each %fs access into a stub that reads the
image's thread pointer from a pthread key and allocates the TLS block on
a thread's first access. Dynamic TLS goes through the image's descriptor
instead of __tls_get_addr. Imports bind by NID to the prx libraries
beside the output, exports and TLS imports use the dynamic symbol names,
and the image's metadata lives in __APS5DATA,__meta.
--macos conflicts with --windows. The macOS runtime that consumes the
output (TLS allocation, libraries built for macOS) comes in separate
changes.