Run Linux binaries on macOS.

No Docker, no full VM — just a lightweight per-process virtual machine that translates Linux syscalls to macOS equivalents. Millisecond startup, native speed, ~170 syscalls.

$ curl -fsSL https://hyper-linux.app/install.sh | sh click to copy
~1–3 ms VM startup time
~170 Linux syscalls
250 KB Single binary
23,000 Lines of C + asm

Everything you need, nothing you don't

A single 250KB native macOS binary. No daemon, no disk image, no multi-GB download.

Millisecond startup

VM creation takes ~1–3ms. Docker container start is seconds; full VM boot is minutes. hl is imperceptible in pipelines.

Native speed

Guest aarch64 code runs on real ARM64 hardware — zero instruction emulation. x86_64 runs via Apple's Rosetta with hardware-accelerated JIT/AOT.

Both architectures

aarch64-linux natively, x86_64-linux via Rosetta. Both from the same tool, auto-detected from the ELF header.

Static + dynamic binaries

Statically linked ELFs work out of the box. Dynamically linked work with --sysroot (musl or glibc).

Direct filesystem access

The guest reads and writes the macOS filesystem directly. No overlay, no volume mount, no copy. Changes are instant.

Real threading

Up to 64 concurrent guest threads, each mapped 1:1 to a host pthread with its own HVF vCPU. Full futex support.

~170 Linux syscalls

I/O, filesystem, networking, signals, threading, process management, time, epoll, inotify, /proc, /dev — all translated.

Zero dependencies

A single native macOS binary. No daemon, no runtime, no disk image. Runs from anywhere — even a USB stick.

How it works

A 5-step pipeline that translates Linux syscalls to macOS equivalents inside a lightweight HVF virtual machine.

1

Load

hl parses the ELF binary and maps PT_LOAD segments into a demand-paged guest address space (up to 1TB — only touched pages use RAM).

2

Boot

A minimal EL1 kernel shim (~500 lines of AArch64 assembly) provides exception vectors. The MMU is enabled inside the guest on the first instruction.

3

Run

The guest binary executes at full native hardware speed on an Apple Hypervisor.framework vCPU.

4

Translate

When the guest makes a Linux syscall (SVC #0), the shim forwards it via HVC. hl translates it to the equivalent macOS call — errno codes, flag values, struct layouts, all converted.

5

Return

Results flow back to the guest. The vCPU resumes. This loop repeats for every syscall — typically microseconds per round-trip.

For x86_64 binaries: Apple's Rosetta Linux translator is loaded as a co-resident aarch64 binary. Rosetta JIT/AOT-translates x86_64 instructions to ARM64 at runtime. All resulting syscalls appear as ARM64 SVC #0 — hl's existing syscall handlers work transparently.

How it compares

hl is not a replacement for Docker or a full VM. It runs single Linux binaries with minimal overhead.

hyper-linux Docker Desktop Lima UTM / QEMU
What runs Single Linux binary Full Linux VM + containers Full Linux VM + containerd Full Linux/other VM
Linux kernel None (syscall translation) Yes (in VM) Yes (in VM) Yes (in VM)
Startup time ~1–3 ms ~0.2–4 s ~5–30 s ~2–60 s
Memory overhead Used pages only (~MB) VM RAM (default ~50% host) VM RAM (default 4 GB) VM RAM (configured at creation)
Disk overhead ~250 KB binary Multi-GB (app + VM image) Multi-GB (VM image) Multi-GB (app + VM image)
Filesystem Direct macOS FS access virtiofs bind mounts virtiofs (VZ) / 9p (QEMU) virtiofs / shared folders
x86_64 support Via Rosetta (fast) Rosetta or QEMU Rosetta (VZ) or QEMU Rosetta (VZ) or QEMU TCG
Threading 1:1 HVF vCPUs (up to 64) Full kernel scheduler Full kernel scheduler Full kernel scheduler
Networking In-process translation Virtual network Virtual network Virtual network
Install Single binary or nix run Desktop app brew install Desktop app

What it runs

Verified with real-world programs — from coreutils to Haskell binaries. Both aarch64 and x86_64 via Rosetta.

GNU Coreutils 9.9

102 tools tested: ls, cat, sort, grep, wc, cp, mv, rm, chmod, date, head, tail, tr, cut, uniq, seq, stat, du, df, and many more.

static + dynamic

BusyBox 1.37.0

60+ applets including awk, sed, grep, tar, gzip, bzip2, find, bc, diff, hexdump, wget, nc, ash shell.

static

Shells

bash (arrays, associative arrays, regex, arithmetic, subshells/fork), dash (loops, conditionals, recursion, case/glob).

static + dynamic

Developer tools

jq (JSON processing), GNU grep, GNU sed, GNU find, tree, diffutils.

static

SQLite3

CREATE, INSERT, SELECT, ORDER BY, recursive CTEs, string functions. Full database engine running in the guest.

static

Languages

Lua interpreter (Sieve of Eratosthenes, Fibonacci), GNU awk (Mandelbrot renderer).

static

pandoc

Markdown→HTML, HTML→Markdown, JSON AST. Exercises GHC RTS + Lua FFI.

haskell · dynamic

ShellCheck

Shell script linter. Exercises GHC threaded RTS + regex engines.

haskell · dynamic

x86_64 via Rosetta

All of the above also work as x86_64-linux binaries, auto-detected from the ELF header. Some edge cases (SA_RESETHAND signals, TLS-dependent threading) have known Rosetta limitations.

rosetta · JIT + AOT

Quick start

hl takes a Linux ELF binary and runs it. That's it.

terminal
$ hl ./hello-static
Hello, world!

$ hl /path/to/jq '.name' data.json
"hyper-linux"

# Run bash interactively with a musl sysroot
$ hl --sysroot ./musl-sysroot /path/to/bash
bash-5.2$

# x86_64 binaries are auto-detected via ELF header
$ hl ./my-x86_64-binary

# Verbose output for debugging
$ hl --verbose ./my-program arg1 arg2

Overhead characteristics

Pure computation runs at native ARM64 hardware speed. The only overhead is per-syscall VM exit round-trips.

~1–3 ms

VM startup

mmap + hv_vm_create + page table setup. Imperceptible in pipelines.

~1–5 µs

Per-syscall overhead

Each VM exit round-trip for syscall translation. Microseconds, not milliseconds.

Zero

Computation overhead

Guest aarch64 code runs on real ARM64 hardware. No instruction emulation, no interpretation.

Demand-paged

Memory usage

Address space up to 1TB, but only touched pages consume physical RAM. macOS handles the rest.

In practice: Single-command tools (echo, true, basename) are dominated by 1–3ms startup. Long-running programs (bash sessions, pandoc) amortize startup to zero — steady-state performance is native + microseconds per syscall.

Installation

Apple Silicon Mac (M1+), macOS 13+. macOS 15+ recommended for 1TB address space.

Quick install

One command. Downloads, codesigns, and installs to /usr/local/bin.

curl -fsSL https://hyper-linux.app/install.sh | sh

Homebrew

Via the zw3rk tap. Handles codesigning automatically.

brew install zw3rk/hyper-linux/hl

Nix

Run directly without installing, or add to your flake inputs.

nix run github:zw3rk/hyper-linux

macOS Installer

Download .pkg from GitHub Releases. Double-click to install.

Download v0.2.4

Technical architecture

Key innovations that make kernel-less Linux binary execution possible.

Syscall translation, not emulation

Every Linux syscall is intercepted via HVC and translated to the equivalent macOS call in-process. Full translation of errno codes, flag values, struct layouts, and socket address formats.

W^X demand paging

Apple HVF enforces write-xor-execute even with SCTLR.WXN=0. The page table system handles this via 4KB L3 splitting when mixed permissions are needed within a 2MB block.

Fork via IPC serialization

HVF allows only one VM per process. Fork spawns a new hl process and serializes entire VM state — registers, memory, FDs via SCM_RIGHTS, signals — over a Unix socket.

Multi-vCPU threading

Guest threads map 1:1 to host pthreads, each with its own HVF vCPU sharing the same physical memory. Full futex support (including PI) enables musl pthread and GHC RTS.

Rosetta integration

x86_64 binaries run by co-loading Apple's Rosetta at 128TB using 48-bit IPA. JIT and AOT translation with persistent caching via built-in rosettad handler.

/proc & /dev emulation

/proc/self/exe, /proc/cpuinfo, /proc/meminfo, /proc/self/maps, /dev/null, /dev/urandom, and more — synthesized responses that match Linux format.

Guest memory layout
0x010000      Page table pool (960KB)
0x100000      Shim code (2MB, RX)
0x200000      Shim data/stack (2MB, RW)
0x400000      ELF LOAD segments
0x1000000     brk heap (grows up)
0x7800000     Stack guard page (dynamic, moves for large binaries)
0x7801000     Stack (8MB, grows down from 0x8000000)
0x10000000    mmap RX region (256MB initial, extends on demand)
0x200000000   mmap RW region (8GB, 256MB initial, extends on demand)
interp_base   Dynamic linker (60GB / 1020GB)

CLI usage

hl --help
USAGE:
    hl [OPTIONS] [--] <elf-path> [args...]

OPTIONS:
    -h, --help              Display the manual page
    -V, --version           Print version and exit
    -v, --verbose           Enable verbose diagnostic output on stderr
    -t, --timeout SECONDS   Per-iteration vCPU timeout (default: 10s)
    --sysroot PATH          Musl/glibc sysroot for dynamically-linked binaries
    --                      Stop processing hl options

EXIT STATUS:
    The exit status of hl is the exit status of the guest binary.

ENVIRONMENT:
    Guest inherits the host environment verbatim. No special variables.

Known limitations

hl translates syscalls, not the kernel. Some things are outside scope by design.

Apple Silicon only

Requires M1/M2/M3/M4 or later. Intel Macs are not supported.

No Linux kernel features

No namespaces, cgroups, or kernel modules. This is syscall translation, not a full kernel.

No external debuggers

ptrace is implemented internally (used by Rosetta's JIT), but GDB/LLDB cannot attach to the guest from the host.

64 thread limit

Up to 64 concurrent guest threads per VM instance.

MAP_SHARED as MAP_PRIVATE

Shared memory semantics are not preserved across processes (guest is process-scoped).

Rosetta AOT automatic

x86_64 binaries get JIT translation immediately and automatic AOT pre-translation via the built-in rosettad handler with persistent caching.