← 返回日报
精读 预计 3 分钟

elfuse: Run Arm64/x86-64 Linux ELF binaries on macOS Apple Silicon

摘要

elfuse 是一个进程范围的 Linux 用户空间运行时,每个 guest 运行在由 elfuse 进程自身拥有的轻量级 Hypervisor.framework VM 中,Linux 系统调用通过主机侧处理器映射到 macOS 行为实现。 正文具体列出功能:单文件二进制(~560 KiB,已签名,无守护、无镜像);毫秒级 VM 启动,微秒级 syscall 开销;原生 Apple Silicon 执行;支持静态/动态链接 aarch64 和 x86_64 guest(x86_64 通过内置 Rosetta 自动检测);Linux 风格进程、线程(1:1 到 64 个 HVF vCPU)、信号、定时器、futex、轮询;guest 直接读写 macOS 文件系统;内置 /proc 和 selected /dev 模拟;guest 内部 FUSE;内置 GDB Remote Serial Protocol 桩;自含测试矩阵(QEMU 和 Rosetta 交叉验证);定位为单二进制轻量工具,不支持命名空间、cgroups 等内核功能;要求 macOS 13+ Apple Silicon 和 Xcode CLI 工具;构建和快速启动说明;限制包括 Intel Mac 仅限 Apple Silicon、单进程树等;Apache License 2.0。

荐读理由

它能直接在你的 macOS Apple Silicon 项目中跑单个 Linux ELF 二进制文件,通过 Hypervisor.framework 提供毫秒级启动和微秒级 syscall 开销,无需 Docker 或完整 VM。每个 ELF 头自动检测架构,支持静态或动态链接,还带内置 GDB stub 可直接接 gdb/lldb。

原文

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-linux ELF binaries

  • Static and dynamically linked x86_64-linux ELF 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 /proc and selected /dev emulation for user-space probes

  • Guest-internal FUSE: /dev/fuse and mount("fuse") work without macFUSE / FUSE-T / FSKit

  • Built-in GDB Remote Serial Protocol stub usable from gdb or lldb

  • 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 GNU make

  • GNU objcopy or llvm-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 attaching gdb / lldb to the built-in stub.

  • docs/testing.md: build prerequisites, the make check flow, 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 elfuse host process. HVF allows one VM per host process; Linux-style fork is implemented by posix_spawn-ing a fresh elfuse host 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.tbl returns -ENOSYS rather than silently succeeding.

  • FUTEX_LOCK_PI and friends behave as plain mutex acquire / release; true priority-inheritance scheduling is not modeled.

  • sched_setaffinity is 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.

Lobsters · 5 赞 · 1 评 讨论 → 阅读原文 →

这条对你有帮助吗?