This document tracks the payload-mini-linker status for Mach-O/AArch64 object relocations.
It is intentionally practical:
- which relocation families
clang/zigactually emit for patch payloads - which ones
zrwritealready supports - which ones are still blocked specifically by PIE / slide safety
- which ones need deeper runtime work instead of just "one more encoder"
For a reproducible local survey, run:
bash scripts/collect_macho_reloc_baseline.shThat script writes its scratch objects and otool -rv dumps into:
../ar-test/macho-reloc-baseline
zrwrite currently applies these Mach-O arm64 payload relocations:
ARM64_RELOC_UNSIGNED- non-PIE absolute-pointer use cases work directly
- PIE targets now support writable 64-bit pointer cells via a one-time
runtime
load_biasfixup - slide-sensitive absolute cells that would live in the primary/RX payload image are still rejected with an explicit diagnostic
ARM64_RELOC_BRANCH26ARM64_RELOC_PAGE21ARM64_RELOC_PAGEOFF12- scale is recovered from the consumer instruction
- current decoder covers
add (immediate)plus common unsigned load/store forms, including Q-register unsigned SIMD/FP accesses
ARM64_RELOC_GOT_LOAD_PAGE21ARM64_RELOC_GOT_LOAD_PAGEOFF12- the linker now materializes framework-owned synthetic GOT slots inside the writable payload image
- payload entry wrappers run a one-time writable fixup pass that rebases
those slots from linked addresses plus the live
load_bias, which keeps Zigextern varloads PIE-safe on macOS arm64
The current sample corpus consistently produces:
ARM64_RELOC_PAGE21ARM64_RELOC_PAGEOFF12ARM64_RELOC_BRANCH26ARM64_RELOC_UNSIGNEDARM64_RELOC_GOT_LOAD_PAGE21ARM64_RELOC_GOT_LOAD_PAGEOFF12ARM64_RELOC_SUBTRACTOR
otool -rv prints several of these in abbreviated form:
PAGOF12->ARM64_RELOC_PAGEOFF12GOTLDP->ARM64_RELOC_GOT_LOAD_PAGE21GOTLDPOFFalse->ARM64_RELOC_GOT_LOAD_PAGEOFF12UNSIGND->ARM64_RELOC_UNSIGNEDSUB->ARM64_RELOC_SUBTRACTOR
The most important practical observation is:
- Zig
extern varloads on Mach-O arm64 currently lower toGOT_LOAD_PAGE21 + GOT_LOAD_PAGEOFF12 - this is the Mach-O analogue of the ELF synthetic-GOT path already handled in the Linux backend
Current status:
- writable 64-bit
ARM64_RELOC_UNSIGNEDcells are now supported in PIE - read-only / primary-image absolute cells are still rejected in PIE because the runtime cannot safely mutate them after code signing
Why this matters:
- normal C/Zig payloads often create pointer tables, slice descriptors, or other data-in-data references
- writable ones now have that runtime fixup path
- primary-image ones still need a different design, such as a synthetic indirection cell or a stronger payload-image rebase model
Why the new writable path is still intentionally limited:
- the runtime performs a one-time guarded rebase pass and then stops touching payload state
- that preserves user mutations after initialization
- it still does not solve absolute cells embedded in the RX payload image
Current status:
POINTER_TO_GOTTLVP_LOAD_PAGE21TLVP_LOAD_PAGEOFF12SUBTRACTOR
are not implemented as payload-runtime-safe relocation families yet.
Not all of these are equally urgent:
- TLV/TLVP is a separate TLS story and should stay explicitly out of scope for now
- subtractor support is useful, but should be added only once the linker has a clearer PIE/rebase model for Mach-O data fixups
- Preserve and improve detailed diagnostics for unsupported Mach-O relocation failures so real samples immediately tell us which family is blocking them.
- Keep the relocation baseline corpus reproducible.
- Extend the runtime-fixup model to more Mach-O relocation families that can safely lower to writable one-time rebasing.
- Add selected subtractor/paired-relocation handling once the data-fixup model is broader.
Current policy:
- support relocations that remain correct under slide without extra runtime mutation
- support framework-owned writable fixups when the runtime semantics are clear
- reject remaining slide-sensitive families with explicit diagnostics
- avoid pretending that a structurally linked payload is safe when codesign or runtime would still be wrong