Skip to content

feat(relinker): write Mach-O output for macOS with --macos - #1597

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
mugurc:macos-relinker
Oct 10, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
mugurc:macos-relinker

Conversation

@mugurc

@mugurc mugurc commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

What

Adds --macos to the relinker: the executable and the bundled modules are written as x86-64 Mach-O files (modules as dylibs in app0/sce_module) that run under Rosetta on Apple silicon. This is the second piece of the macOS port after #927, as announced on #1 (#1 (comment)).

  • MacOsMachOPatcher writes the executable and GuestModuleWriter::WriteMacOs the modules, both through MacOsImage. The ELF segments keep their layout (__ELF0, __ELF1, ...). Imports bind by NID to the prx libraries through @rpath, exports and TLS imports use the dynamic symbol names, and the original program headers and the image metadata go to __APS5DATA,__meta, the section the unwinder from feat(libc): exception runtime on macOS hosts #927 reads.
  • FreeBSD code reaches its thread pointer through %fs, which macOS cannot set. Each %fs access becomes a stub that reads the 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.
  • Relocations and imports are collected with the existing Windows::WindowsLoadImage and WindowsRelocationBuilder. Moving them to general/ is a refactor for a follow-up.
  • --macos conflicts with --windows. --to-intel with --macos still uses the Intel target here; the Rosetta target comes in its own PR.

The Linux and Windows output is unchanged. The Mach-O output needs the macOS runtime (TLS allocation in libkernel, libraries built for macOS), which comes in separate PRs.

Tested

  • Linux and Windows: this branch's CI run on my fork, https://github.com/mugurc/AnyPS5/actions/runs/37784600652 (Linux 462 of 462, Windows 454 of 454, conventions and report green).
  • New test macos_output: relinks two byte-built guests and reads the Mach-O back (header, segment layout and protections, entry point, dependencies, run path, binds by NID, the TLS descriptor, and that no %fs access is left). It needs no macOS, so it runs in the Linux and Windows jobs.
  • macOS 26.5 on an M5 Max: the relinker builds and all 32 relinker tests pass, macos_output included.
  • Running relinked programs needs the runtime pieces that are not in this PR. On my full port branch (https://github.com/mugurc/AnyPS5/tree/macos-port) 10 of 10 relinked fixtures run under Rosetta, but that is not this branch alone.
  • No commercial title was tested; I have no PS5.

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 in TechnicalDebt
  • 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 (none added)
  • Generic behaviour, not specific to one title
  • Depends on: none
  • AI-assisted: yes

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.
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
#2117 core/relinker/cli/src/CliArgs.cpp L66-70

@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the build and the relinker ctest scope on Linux (43/43, macos_output included), the head's CI (conventions, eligibility, relinker on ubuntu/windows/macos), and that Linux/Windows output paths are untouched. macos_output fails without the change. Runtime behaviour on macOS/Rosetta is not verified here (it needs the runtime pieces from the follow-up PRs); merging for the structure and the CLI. Note #2117 touches the usage line in CliArgs.cpp, whoever lands second rebases.

@adriadam10
adriadam10 merged commit 3181e71 into boykopovar:main Oct 10, 2026
7 checks passed
@mrzacarias

Copy link
Copy Markdown
Contributor

Tried mugurc/macos-port (e9db5eb) with Balatro (PPSA21402) on an M1 Pro, macOS 26.4, LunarG SDK 1.4.363. It gets to gameplay at ~33 FPS. On top of the branch I needed:

Still open: text truncated partway through long batches with a stray triangle to (0,0); host import, draw sync, texture cache and flip pacing are ruled out. Also a crash on exit in sceKernelGetModuleInfoFromAddr (garbage st_size), and an occasional "guest protection or unmap range has a hole" at startup. Happy to send PRs once intake reopens.

Branch: https://github.com/mrzacarias/AnyPS5/tree/balatro-macos

SleglJan pushed a commit to SleglJan/AnyPS5 that referenced this pull request Oct 10, 2026
feat(relinker): write Mach-O output for macOS with --macos
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