Skip to content

suma/rustmute

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

123 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rustmute

A Rust-based binary translator that runs x86_64 (Intel) macOS binaries on Apple Silicon (ARM64) Macs. Rustmute uses a Rosetta-style syscall-boundary architecture: user-space x86 code is translated to ARM64 via JIT or AOT, while kernel syscalls and Mach traps are bridged natively.


Requirements

Host OS macOS 26 (Tahoe) or later
CPU Apple Silicon (M1 / M2 / M3 / M4)
Rust 1.78 or later (rustup update stable)

Build

git clone https://github.com/suma/rustmute
cd macbin
cargo build --release -p rustmute-cli
# → target/release/rustmute

A debug build is fine for development:

cargo build -p rustmute-cli
# → target/debug/rustmute

Usage

rustmute run-with-dyld — real dyld mode (Phase 7.6)

rustmute run-with-dyld [--timings] <x86_64-binary> [args...]

JIT-executes the binary using the real x86_64 dyld and dyld shared cache, providing a full runtime environment including libSystem. This is the primary mode for running x86_64 system binaries on Apple Silicon.

rustmute run-with-dyld /bin/ls -l /usr/lib
rustmute run-with-dyld /bin/cp src.txt dst.txt
rustmute run-with-dyld /usr/bin/file /usr/bin/arch

Startup sequence:

  1. Load the main binary + /usr/lib/dyld (x86_64 slice)
  2. mmap the dyld shared cache (/var/db/dyld/dyld_shared_cache_x86_64h)
  3. Build the kernel argument stack (including ptr_munge / apple[] entries)
  4. Map the x86_64 commpage at 0x7fff_ffe0_0000
  5. Install native DNS intercepts (getaddrinfo / freeaddrinfo)
  6. Set up TLS at 0x7fff_ec00_0000
  7. Start the JIT engine and enter the dispatch loop

--timings flag

Pass --timings to print an execution breakdown to stderr on exit. Hot-path overhead is zero — all instrumentation is gated behind a single relaxed AtomicBool load.

rustmute run-with-dyld --timings /bin/ls -l /usr 2>&1 | tail -35

Example output:

rustmute timings [run-with-dyld]:
  load        :      3.2 ms
  stack-setup :      0.1 ms
  cache-map   :    142.5 ms
  lift        :     18.3 ms   (2043 calls)
  codegen     :     45.1 ms   (2043 calls)
  execute     :    398.7 ms   (1418174 calls)
  syscall     :     11.2 ms   (311 calls)
  ───────────────────────────────────
  measured    :    619.1 ms
  total wall  :    782.4 ms
  block cache:
    hot hit    :    1401430  (98.82%)
    slow hit   :        890  ( 0.06%)
    cold miss  :       2043  ( 0.14%)
    smc        :          0  ( 0.00%)
    ─ total    :    1404363
  dispatch exits:
    jump       :    1403484  (98.96%)  ← chainable
    syscall    :        311  ( 0.02%)
    ret        :          1  ( 0.00%)
    trap       :          0  ( 0.00%)
    ─ total    :    1403796  (== execute ✓ )
  chaining estimate:
    loop overhead  :    0.8 ns/iter
    potential save : 1121.3 ms  (= jump × overhead)

Reading the output:

Section Description
Phase times load / stack-setup / cache-map are startup costs. lift / codegen are block translation costs. execute / syscall are steady-state loop costs.
block cache hot hit: fastest cache path (inline lookup). slow hit: slower cache path. cold miss: first translation of a block. smc: recompile triggered by self-modifying code.
dispatch exits Exit type after each block execution. jump (simple branch to the next block) is a candidate for block chaining, which would eliminate the round-trip back to the Rust dispatch loop.
chaining estimate Theoretical savings if block chaining were implemented. A large potential save indicates high expected benefit.

Components

Crate Role
rustmute-core Shared types, GuestCpu state, guest memory abstraction (GuestMemory), error types, phase timers (timings)
rustmute-loader Mach-O parsing, dyld emulation (dependency resolution, relocations, symbol binding)
rustmute-cache Parser and mapper for the x86_64 dyld shared cache (Phase 7.6)
rustmute-ir Rustmute IR definitions, IR builder, optimization passes
rustmute-decoder x86_64 decoding via iced-x86, x86 → IR lifter
rustmute-arm64 ARM64 encoder (dynasm-based), IR → ARM64 lowering
rustmute-interp IR interpreter — correctness reference backend for testing
rustmute-jit JIT engine, block cache, dispatch loop
rustmute-aot AOT compiler, translated Mach-O / object file output
rustmute-runtime syscall / Mach trap translation, signal handling, TLS, guest↔host bridge
rustmute-cli rustmute run, rustmute run-with-dyld, rustmute compile commands

Crate dependency order:

cli → {jit, aot} → {arm64, interp, decoder, ir, runtime} → loader → {cache, core}

Status

Phase 7.6 M3 is complete. Real binaries including /bin/ls -l, /bin/cp, /usr/bin/file, and /usr/bin/seq run correctly under run-with-dyld.

See design-docs/ROADMAP.md for the implementation roadmap and design-docs/DESIGN.md for architecture details.


License

Licensed under either of

at your option.

About

Rust-based binary translator that runs x86_64 macOS binaries (PoC)

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

1 star

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages