elfuse: Run Arm64/x86-64 Linux ELF binaries on macOS Apple Silicon
Summary
elfuse is a lightweight, process-scoped runtime that runs Linux ELF binaries natively on macOS Apple Silicon without Docker or full VMs, using Hypervisor.framework and optionally Rosetta for x86_64 translation.
View Cached Full Text
Cached at: 07/15/26, 11:49 PM
sysprog21/elfuse
Source: https://github.com/sysprog21/elfuse
elfuse
Run Linux ELF binaries directly from the macOS shell – no Docker, no
full VM image, no daemon. elfuse is a process-scoped Linux user-space
runtime: each guest runs inside a lightweight Hypervisor.framework VM
owned by the elfuse process itself, and Linux syscalls are translated
to macOS behavior in host-side handlers rather than served by a real
Linux kernel.
Native aarch64-linux executes directly on the CPU. x86_64-linux
executes through Apple’s embedded Rosetta translator hosted inside the
same VM; the architecture is auto-detected from the ELF header. Both
static and dynamically linked guests are supported, with the dynamic
linker resolved against an external sysroot via --sysroot.
Features
- Single native macOS binary (~560 KiB signed), no daemon and no disk image
- Millisecond-scale VM startup; per-syscall overhead is microseconds
- Native Apple Silicon execution through Hypervisor.framework
- Static and dynamically linked
aarch64-linuxELF binaries - Static and dynamically linked
x86_64-linuxELF binaries via Apple Rosetta (auto-detected from the ELF header, opt out with--no-rosetta) - Linux-style processes, threads (1:1 with HVF vCPUs, up to 64), signals, timers, futexes (incl. PI ops), and polling
- Guest reads and writes the macOS filesystem directly; no overlay or volume mount layer
- Synthetic
/procand selected/devemulation for user-space probes - Guest-internal FUSE:
/dev/fuseandmount("fuse")work without macFUSE / FUSE-T / FSKit - Built-in GDB Remote Serial Protocol stub usable from
gdborlldb - Self-contained test matrix that cross-checks elfuse against QEMU and exercises a separate Rosetta acceptance suite
Positioning
elfuse is intentionally narrow. It runs single Linux binaries (and
their fork/exec children) with minimal overhead; it does not host a
Linux kernel, namespaces, cgroups, or kernel modules. For workloads
that need full kernel features, container orchestration, or systemd,
prefer a full VM tool (Lima, UTM, OrbStack) or Docker Desktop. For
single-binary tooling, language runtimes, test harnesses, and
debugger-driven workflows, elfuse removes the disk-image and
boot-time overhead those tools impose.
Requirements
- macOS on Apple Silicon
- macOS 13 or newer
- Xcode Command Line Tools,
clang,codesign, and GNUmake - GNU
objcopyorllvm-objcopy - Hypervisor entitlement:
com.apple.security.hypervisor
To build only (make elfuse) without running tests, just the
Xcode Command Line Tools and objcopy (brew install binutils) suffice.
For guest test binaries, the project also expects an AArch64 Linux cross
toolchain. The default paths in mk/toolchain.mk target the toolchain layout
used by the repository test harness, but CROSS_COMPILE and
BAREMETAL_CROSS are overridable.
See docs/testing.md for toolchain setup guide.
Quick Start
git clone https://github.com/sysprog21/elfuse
cd elfuse
make elfuse
make test-busybox
build/elfuse build/busybox
Replace build/busybox with an aarch64-linux or x86_64-linux executable.
The guest architecture is auto-detected from the ELF header.
For dynamically linked guests:
build/elfuse --sysroot /path/to/sysroot ./path/to/program
For x86_64-linux guests, Rosetta is on by default. To disable:
build/elfuse --no-rosetta ./path/to/aarch64-only-binary
For early debugging:
build/elfuse --gdb 1234 --gdb-stop-on-entry ./path/to/program
--gdb is rejected for x86_64 guests because the stub serves the
aarch64 view Rosetta produces, not the original x86_64 architectural
state.
The build signs build/elfuse before use. Override the signing identity with
SIGN_IDENTITY="Developer ID ..." when needed.
Documentation
- docs/usage.md: command-line options, x86_64 via
Rosetta, dynamic linking via
--sysroot, and attachinggdb/lldbto the built-in stub. - docs/testing.md: build prerequisites, the
make checkflow, the QEMU and Rosetta cross-check matrices, and fixture handling. - docs/internals.md: canonical technical reference – runtime lifecycle, HVF constraints, EL1 shim and HVC protocol, page-table splitting, syscall translation tables, threads / futex, fork / clone IPC, signals, ptrace, and the GDB stub.
Build And Validation
Most common targets:
make elfuse # build and codesign build/elfuse
make check # quick unit suite + BusyBox applet smoke
make test-gdbstub # debugger integration
make test-matrix # cross-check elfuse against QEMU on the same corpus
make lint # clang-tidy
make check is the recommended pre-commit gate. make test-matrix is the
recommended gate for changes touching procfs, dynamic linking, networking,
or process semantics. make test-rosetta-all covers the x86_64 acceptance
suites in isolation. See docs/testing.md for the full
target list, fixture flow, and validation-by-change-type guidance.
Limitations
elfuse runs single Linux user-space processes (and their fork /
exec children). It is not a Linux kernel.
That framing shapes both what it does and what it explicitly will not
do.
- Linux kernel features that have no user-space-syscall analog:
namespaces, cgroups, kernel modules, eBPF,
io_uring, KVM, perf events. - Intel Macs. Apple Silicon only (M1 and later).
- Hosting a VM from inside a guest. The guest cannot use HVF or KVM.
- One guest process tree per
elfusehost process. HVF allows one VM per host process; Linux-styleforkis implemented byposix_spawn-ing a freshelfusehost process and transferring state (see docs/internals.md). - Up to 64 concurrent guest threads per VM (
MAX_THREADS = 64). - Around 213 syscalls implemented; anything outside
src/syscall/dispatch.tblreturns-ENOSYSrather than silently succeeding. FUTEX_LOCK_PIand friends behave as plain mutex acquire / release; true priority-inheritance scheduling is not modeled.sched_setaffinityis honored as a no-op (returns the all-CPUs mask); the host scheduler picks the actual CPU./proc,/dev, and mount data are synthetic compatibility views, not host pass-throughs.
License
Apache License 2.0. See LICENSE.
Copyright 2026 elfuse contributors
Copyright 2025 Moritz Angermann, zw3rk pte. ltd.
Similar Articles
@alswl: Did you know the Linux kernel has a feature introduced in 1997 that allows Apple Silicon Macs to efficiently run x86 containers? It's called binfmt_misc, introduced in Linux 2.1.43, nearly 30 years ago. The principle is extremely simple: Linux...
This article introduces the binfmt_misc feature introduced in the Linux kernel in 1997. It allows registering rules to hand off binary execution to a specified interpreter. Today, combined with Rosetta on Apple Silicon Macs, it enables efficient x86 container operation, achieving performance close to 70-90% of native.
@geekbb: NTFS read/write on Apple Silicon macOS — no kernel extensions, no SIP disable. It actually runs a libkrun microVM (based on anylinuxfs, with ntfs-3g inside) to handle the actual NTFS writes, then…
ntfsmac is an open-source tool that enables NTFS read/write on Apple Silicon macOS by using a libkrun microVM running ntfs-3g, avoiding kernel extensions and SIP modifications. It provides both CLI and a GUI menu-bar app.
macOS Container Machines
Apple has released 'container', an open-source tool that lets macOS users create and run Linux containers as lightweight virtual machines, optimized for Apple silicon and supporting OCI-compatible images.
@QingQ77: An open-source project written in Rust and C that uses JIT compilation to run Linux containers directly on macOS. https://github.com/ricccrd/dd It does not require a VM, hypervisor, or Linux kernel, but instead…
dd is an open-source tool written in Rust and C that runs Linux containers on macOS without a VM by using JIT compilation to translate container instructions and handle syscalls in userspace. It implements the Docker Engine API, supports arm64 and x86-64 Linux images, and offers performance comparable to or better than VM-based solutions.
I ported EXL3 to run well on Apple Silicon - PonyExl3
Ported the EXL3 LLM codec to run on Apple Silicon via Metal, achieving high prefill and generation speeds on M5 Max (e.g., ~600 tok/s prefill, 17-80 tok/s gen on various models).