Skip to content

Add arm64 Linux port - #4

Open
FBarrca wants to merge 2 commits into
ambonvik:mainfrom
FBarrca:arm64-linux
Open

FBarrca wants to merge 2 commits into
ambonvik:mainfrom
FBarrca:arm64-linux

Conversation

@FBarrca

@FBarrca FBarrca commented Nov 3, 2026 •

Copy link
Copy Markdown

Depends on #3 (macOS port). This branch is built on top of #3, which adds the arm64 detection in cmi_config.h, the setjmp/longjmp trial recovery on arm64 and the CPU/OS port selection in src/port/meson.build. Until #3 is merged, this PR's diff also shows the macOS commit. Only the last commit, "Add arm64 Linux port", is new here.

Adds support for arm64 (AArch64) Linux.

New port: src/port/aarch64/linux

  • Context switch. The same frame layout as the arm64 macOS port (X19–X30, D8–D15, FPCR/FPSR, 176 bytes), in ELF form. The object has no BTI/PAC property note, because the stack switch returns into frames it did not call.
  • Stacks. Keeps the Linux per-thread pool of recycled guarded stacks. The main thread's stack bounds come from pthread_getattr_np.
  • Seeds. getrandom(), falling back to the thread id, the clock and cntvct_el0.
  • Reused code. Page size, aligned allocation and core count reuse the x86-64 Linux sources instead of duplicating them.

Shared changes

  • TLS model. initial-exec is now used on x86-64 Linux only, in both meson.build and CMB_THREAD_LOCAL. On aarch64, glibc refuses to dlopen a library marked as using static TLS late in the process ("cannot allocate memory in static TLS block"), which breaks loading Cimba from Python. The default TLS descriptor model is cheap on arm64.
  • _FORTIFY_SOURCE. Turned off in cimba.c on arm64 Linux. Distribution GCCs turn it on by default, which makes longjmp go through __longjmp_chk. That check aborts ("longjmp causes uninitialized stack frame") when an abandoned trial jumps from a coroutine stack back to the worker stack. x86-64 is unaffected because it uses __builtin_longjmp.

Testing

Not run as part of preparing this PR, since I have no arm64 Linux machine here. Checked so far: the assembly builds for aarch64-linux-gnu and exports the expected symbols, and the macOS tests still pass with this branch. The port comes from a fork where it has been in use. Running meson test on an arm64 Linux machine before merging would be good.
Tested on AWS arm64 boxes.

Co-Authored-By: Claude noreply@anthropic.com
Includes-AI-Code: true

FBarrca and others added 2 commits November 3, 2026 13:53
New ports under src/port/aarch64/macos and src/port/x86-64/macos:
- Context switch: AArch64 assembly saving X19-X30, D8-D15, FPCR/FPSR,
  and a Mach-O (macho64) variant of the x86-64 NASM switch.
- Guarded coroutine stacks via posix_memalign + mprotect, main stack
  bounds from pthread_get_stackaddr_np / pthread_get_stacksize_np.
- Seeds from arc4random_buf, core count from sysconf.

Shared changes, all limited to the new platforms:
- cmi_config.h recognises arm64 and macOS.
- Trial recovery uses setjmp/longjmp on arm64, since Clang does not
  implement __builtin_setjmp on AArch64.
- Build: dispatch to the new ports, only require NASM on x86-64, use
  _DARWIN_C_SOURCE instead of _POSIX_C_SOURCE on macOS, and only pass
  -ffat-lto-objects when the compiler accepts it (Apple Clang does not).

Co-Authored-By: Claude <noreply@anthropic.com>
Includes-AI-Code: true
Context switch shares the arm64 macOS frame layout (X19-X30, D8-D15,
FPCR/FPSR) in ELF form. Stack allocation keeps the Linux per-thread pool
of recycled guarded stacks and pthread_getattr_np main stack bounds.
Seeds come from getrandom(), page size, aligned allocation and core
count reuse the x86-64 Linux sources.

initial-exec TLS sets DF_STATIC_TLS, and glibc on aarch64 refuses to
dlopen such a library late in the process ("cannot allocate memory in
static TLS block"), which breaks loading it from Python. Keep
initial-exec on x86-64 Linux only; arm64 uses TLS descriptors.

Distribution GCCs enable _FORTIFY_SOURCE, which turns longjmp into
__longjmp_chk. That check aborts ("longjmp causes uninitialized stack
frame") when an abandoned trial jumps from a coroutine stack back to
the worker stack, so it is disabled for cimba.c on arm64 Linux.

Co-Authored-By: Claude <noreply@anthropic.com>
Includes-AI-Code: true
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