Skip to content

Add macOS Apple Silicon (arm64) support#51

Open
Simon9997 wants to merge 2 commits intocoolxv:masterfrom
Simon9997:macos-arm64-support
Open

Add macOS Apple Silicon (arm64) support#51
Simon9997 wants to merge 2 commits intocoolxv:masterfrom
Simon9997:macos-arm64-support

Conversation

@Simon9997
Copy link
Copy Markdown

Summary

Adds runtime support for cpp-stub on macOS, including Apple Silicon (M-chip).
Previously, calling Stub::set on arm64 macOS failed with stub set memory protect to w+r+x faild because:

  1. macOS caps mprotect by the Mach-O segment's maxprot, and __TEXT defaults to r-x.
  2. Apple Silicon enforces W^X at the page-table level, so even raising maxprot isn't enough — you cannot simultaneously hold write + execute on the same physical page via the original mapping.
  3. Even with a writable VM alias of the text page, a plain store instruction whose own opcode lives on the destination page deadlocks the current thread.

Refs #49.

Changes

  • src/stub.h: on __APPLE__, obtain a writable alias via mach_vm_remap(VM_INHERIT_SHARE) + mach_vm_protect(RW), and route every write through libSystem's memcpy (called through a volatile function pointer) so the store opcodes are not co-located with the destination. The aarch64 REPLACE_FAR macro is specialized for Apple to stage the trampoline in a stack buffer and memcpy it across. All non-Apple branches are unchanged.
  • tool/macos_enable_stub.sh: post-link helper that walks the Mach-O load commands, patches __TEXT's maxprot to rwx, and ad-hoc re-signs with codesign. Required once per macOS binary that uses cpp-stub.
  • test/Makefile.darwin.clang: Darwin build recipe that filters Linux/Windows-only tests and automatically runs the enable-stub helper on each produced binary.
  • .github/workflows/make-test-multi-platform.yml: enable macos-13 (Intel) and macos-latest (Apple Silicon) matrix entries using the new Makefile; drop the old commented-out macOS stubs.
  • README / README_zh: document the new macOS support.

Verification

Locally on macOS 26.4 arm64 (M-chip), test_function, test_class_member_function, and test_variadic_function all pass via make -f Makefile.darwin.clang. Repeated set/re-set/reset cycles behave correctly. CI will additionally validate on macos-13 (Intel) and macos-latest (Apple Silicon).

macOS (especially Apple Silicon) enforces W^X on the __TEXT segment at
the page-table level and caps mprotect by the segment's maxprot. Two
issues previously prevented cpp-stub from patching its own text segment
on an M-chip Mac:

1. mprotect cannot raise __TEXT to PROT_WRITE|PROT_EXEC.
2. Even with a writable alias obtained via mach_vm_remap, a plain
   store instruction that happens to sit on the same physical page as
   the destination deadlocks the current thread.

Fixes:

* src/stub.h: on __APPLE__, obtain a writable alias of the target
  page(s) via mach_vm_remap(VM_INHERIT_SHARE) + mach_vm_protect(RW)
  and route every write through libSystem's memcpy (invoked through a
  volatile function pointer) so the store opcodes live on libSystem's
  pages rather than our own __TEXT. The aarch64 REPLACE_FAR macro is
  specialized for Apple to build the trampoline in a local buffer and
  memcpy it across. All non-Apple branches keep the original logic.

* tool/macos_enable_stub.sh: post-link helper that walks the Mach-O
  load commands, patches __TEXT's maxprot to rwx, and ad-hoc re-signs
  the binary with codesign. Required once per test executable (see
  issue coolxv#49).

* test/Makefile.darwin.clang: new Darwin Makefile that drives clang++
  and runs macos_enable_stub.sh automatically.

* .github/workflows/make-test-multi-platform.yml: enable macOS-13
  (Intel) and macOS-latest (Apple Silicon) jobs using the new
  Makefile, replacing the commented-out stubs.

* README / README_zh: document the new macOS support.

Verified on macOS 26.4 arm64 (M-chip): test_function,
test_class_member_function, test_variadic_function all pass, and
repeated set/reset cycles behave correctly.

Refs: coolxv#49

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Simon9997 Simon9997 marked this pull request as draft April 17, 2026 08:11
Downstream users no longer need to invoke tool/macos_enable_stub.sh
themselves. The repo now ships:

* CMakeLists.txt — INTERFACE target cpp-stub. When add_subdirectory'd,
  a cmake_language(DEFER) callback runs at end-of-config, finds every
  executable that links cpp-stub, and attaches the enable-stub
  post-build step automatically on Apple. A cpp_stub_enable(target)
  helper is exposed for the transitive-link corner case.

* mk/cpp-stub.mk — Makefile fragment. Defines CPP_STUB_INCLUDE and a
  CPP_STUB_POSTLINK macro that expands to the enable-stub invocation
  on macOS and to ':' (no-op) elsewhere, so one rule works on every
  platform.

* example/cmake_smoke/ — self-contained CMake project that just links
  cpp-stub and expects the patch+sign to happen with zero manual
  steps. Exercised by CI on both macos-13 and macos-latest.

* test/Makefile.darwin.clang now dogfoods mk/cpp-stub.mk.

* README.md / README_zh.md gain a 'macOS integration' section showing
  the zero-step CMake path, the one-line Make path, and a snippet for
  Xcode/Bazel/other build systems.

* .github/workflows/make-test-multi-platform.yml gains a second step
  per macOS runner that configures and runs example/cmake_smoke,
  proving end-to-end that a downstream CMake project need do nothing
  beyond target_link_libraries(... cpp-stub).

Verified locally on macOS 26.4 arm64: CMake smoke + Makefile-based
tests all pass, and the existing test matrix (test_function,
test_class_member_function, test_variadic_function) is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Simon9997 Simon9997 marked this pull request as ready for review April 17, 2026 09:01
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.

1 participant