Skip to content

Fix snapshot load on macOS arm64 (W^X + relocation decode + exec-link quoting)#1788

Open
dg1sbg wants to merge 3 commits into
clasp-developers:mainfrom
dg1sbg:fix/macos-arm64-snapshot-load
Open

Fix snapshot load on macOS arm64 (W^X + relocation decode + exec-link quoting)#1788
dg1sbg wants to merge 3 commits into
clasp-developers:mainfrom
dg1sbg:fix/macos-arm64-snapshot-load

Conversation

@dg1sbg

@dg1sbg dg1sbg commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Makes snapshot load work on macOS arm64. With #1787 (which fixes the save unwinding), SLAD-SNAPSHOT and SLAD-EXECUTABLE both pass; full regression suite 1957/11 (the 11 are pre-existing, orthogonal).

Three independent fixes, all in snapshotSaveLoad.cc:

1. W^X faults during in-place fixup (commit 1)

snapshot_load fixes up the loaded code in place in MAP_JIT (rwx, W^X) memory; on Apple Silicon a bare store into execute-mode JIT memory faults with SIGBUS/KERN_PROTECTION_FAILURE. Three sites now switch to write mode via JITDataReadWriteMaybeExecute()/JITDataReadExecute() (same pattern as the existing JIT-literal write sites): the code-literals memcpy, and the fixup_objects / fixup_internals walks. (The save path fixes up a RW copy, so it never hit this.)

2. Relocation-decode false positive (commit 2)

The entry-point decode validated the resolved address by comparing its first byte against a saved firstByte, and aborted on mismatch (decodeEntryPointForCompiledCode) / warned (fixedAddress). But a function's first instruction is frequently a relocatable instruction (e.g. ADRP), whose encoded page-offset immediate legitimately differs between the save-time and load-time JIT (different load addresses). The offset/symbol-based decode is correct — verified: with the check made non-fatal the snapshot loads, runs, and returns the right value — so the firstByte equality check is a false positive on every relocated first instruction. Dropped at both sites.

3. Executable-link path quoting (commit 2)

save-lisp-and-die :executable builds a clang++ command run via system() (a shell). The -Wl,-force_load,<libdir>/libiclasp.a path was unquoted, so a build/lib dir containing a space (e.g. a Dropbox path) split the arg and the link failed (no such file). The output, -sectcreate file, and -force_load paths are now quoted.

Verification (macOS arm64, native boehmprecise image)

SLAD-SNAPSHOT and SLAD-EXECUTABLE pass; full suite run from build/ = 1957 passed / 11 failed (the 11 known pre-existing). No regressions.

🤖 Generated with Claude Code

@dg1sbg

dg1sbg commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

Added a 4th commit (save-lisp-and-die :executable absolute -L): the executable link command carried only the relative -Lboehmprecise/lib from BUILD_LINKFLAGS, so -lclasp resolved only when run with CWD=build/; from any other directory the link failed with "library not found for -lclasp". Now adds an absolute -L"<_LibDir>" (matching the Linux branch). Verified: a standalone executable created and run from /tmp returns the right value, and SLAD-EXECUTABLE passes from the repo root, not just build/.

dg1sbg and others added 3 commits June 2, 2026 15:52
On Apple Silicon, snapshot_load fixes up the loaded code's data in place in
MAP_JIT (W^X) memory; the bare stores fault with SIGBUS (KERN_PROTECTION_FAILURE).
Wrap the three load-side write sites in JITDataReadWriteMaybeExecute() /
JITDataReadExecute() (same pattern as the other JIT-literal write sites):
  - the code-literals memcpy,
  - the fixup_objects walk (walk_temporary_root_objects<fixup_objects_t>),
  - the fixup_internals walk.
(The save path fixes up a RW copy of the buffer, so it never hit this.)

This unblocks snapshot load past the W^X SIGBUS. The remaining failure -- the
position-independent function-pointer relocation decode (decodeEntryPoint /
fixedAddress) -- is separate, pre-existing sc598 relocation work.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ath quoting

Make snapshot save/load/executable work on macOS arm64 (SLAD-SNAPSHOT and
SLAD-EXECUTABLE now pass):

1. Relocation decode: the entry-point decode validated the resolved address by
   comparing its first byte against a saved firstByte and ABORTED on mismatch
   (decodeEntryPointForCompiledCode) / warned (fixedAddress). But a function's first
   instruction is frequently a relocatable instruction (e.g. ADRP) whose encoded
   immediate bytes legitimately differ between the save-time and load-time JIT
   (different load addresses => different page offsets). The offset/symbol-based decode
   is correct (verified: snapshot loads and returns the right value); drop the
   firstByte equality check, which was a false positive on every relocated first insn.

2. Executable link: save-lisp-and-die :executable builds a clang++ command run via
   system() (a shell); the -Wl,-force_load,<libdir>/libiclasp.a path was unquoted, so
   a build dir containing a space (e.g. a Dropbox path) split the arg and the link
   failed. Quote the output, sectcreate, and force_load paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e -L

The executable link command (run via system()) carried only the RELATIVE
-Lboehmprecise/lib from BUILD_LINKFLAGS, so -lclasp resolved only when
save-lisp-and-die :executable ran with CWD=build/; from any other directory the
link failed ("library not found for -lclasp"). Add an absolute, quoted
-L"<_LibDir>" (as the Linux branch already does). The runtime rpath is already
absolute, so the produced executable both links and runs from any CWD.

Verified: created and ran a standalone executable from /tmp (returns the right
value); SLAD-EXECUTABLE now passes from the repo root, not just build/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dg1sbg dg1sbg force-pushed the fix/macos-arm64-snapshot-load branch from b85f994 to aedda03 Compare June 2, 2026 14:01
@Bike

Bike commented Jun 9, 2026

Copy link
Copy Markdown
Member

1, the snapshot load change, appears to be duplicating the similar change in #1768.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants