Rui UeyamaandClaude Opus 5.5 5eb4fb99d7 Write the output from the driver, as mold does
passes.rs's copy_chunks copied the chunks and then wrote the rest of
the output itself: it reported the text relocations, wrote the fixups,
applied the target's optimization hints, wrote the symbol table, the
mach header, the UUID and the code signature, and queued each range of
the buffer to the output file as soon as it was final. In mold,
copy_chunks is in driver.rs and only copies, and the driver calls the
passes after it one by one (finish_output, rewrite_endbr,
write_build_id). copy_chunks is in driver.rs now and copies only, and
the driver runs the rest in the same order: report_text_relocs and
compute_uuid are pub passes of passes.rs, and the fixups, the symbol
table, the header and the signature are written by the chunk modules
as before. The driver queues each range at the same point as
copy_chunks did, so the file is still written while the rest of it is
produced.

compute_uuid keeps its name. It is mold's write_build_id, as its doc
comment now says, but everywhere else the Mach-O build ID is the UUID
(LC_UUID, -no_uuid, ctx.uuid), and the name says what it computes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:26:55 +09:00
2026-10-08 13:21:50 +09:00
2026-09-19 10:48:37 +09:00

mold-macho: mold for macOS

mold-macho is a Mach-O linker for macOS, written in Rust as a port of the mold linker to Apple platforms. It is a drop-in replacement for Apple's ld for common workloads: it accepts ld64's command line, and links working, correctly code-signed executables, dylibs and bundles for arm64 and x86-64 macOS.

C, C++, Objective-C, Swift and Rust programs link and run, including real-world projects (ripgrep builds and passes its full test suite; the C++ mold tree with vendored tbb/zstd/zlib builds at -O3; the linker links itself). Debugging works (stabs for lldb/dsymutil), and so do C++ exceptions, thread-locals, LTO, auto-linking, frameworks and Objective-C selector stubs.

Usage

Build with cargo build --release. The binary is target/release/mold; ./install.sh (PREFIX=/usr/local by default) installs it as mold with an ld64.mold symlink, the same arrangement as mold's ld.mold. Then point your compiler driver at the linker:

clang -o hello hello.c --ld-path=path/to/ld64.mold
swiftc -o hello hello.swift -use-ld=path/to/ld64.mold
RUSTFLAGS="-C link-arg=--ld-path=path/to/ld64.mold" cargo build

Feature highlights

  • Classic dyld info and chained fixups (the default for deployment targets of macOS 13+), ad-hoc code signing, export tries, and content-hash UUIDs
  • Subsections via symbols, -dead_strip, identical code folding (on by default, like ld64's deduplication), literal merging
  • __unwind_info synthesis from compact unwind, __eh_frame re-synthesis for DWARF-only unwind, range-extension thunks
  • Archives with mold's order-insensitive resolution model, .tbd stubs with umbrella reexports, frameworks, auto-linking (LC_LINKER_OPTION), LTO via libLTO
  • Parallel input parsing, output writing and code-signature hashing, following the design described in the mold paper

Architecture

The code mirrors mold's layout: macho/driver.rs runs the passes in order, macho/passes.rs implements them, macho/arch/ isolates the target-dependent relocation handling (arm64 and x86-64 are each instantiated in a crate under arch/ and dispatched by the executable in cli/), and macho/chunks/ builds every piece of the output file. Parsing is decoupled from resolution: all inputs, including every archive member, are parsed in parallel, and symbol resolution ranks competing definitions with a liveness walk deciding which archive members join the link.

The commit history doubles as a reference on the Mach-O file format and dyld: each commit's message explains the structures and loader behavior involved in that change.

Tests

Tests are shell scripts under tests/, one feature per script, driving the real toolchain through cc --ld-path=...; a harness runs each for macOS on arm64 and (under Rosetta) x86-64, and then for the arm64 iOS simulator if its runtime is installed, building the programs with the simulator's SDK and running them on a simulator device it boots. Logs and outputs go under target/<profile>/mold-test/out/test. --all adds the x86-64 iOS simulator (which only the iOS 17 runtime runs) and the tvOS and visionOS simulators; --host runs macOS's alone, and --triple (or TRIPLE) one simulator. The harness is the integration test of the cli crate; name that target to pass it options, which the unit tests would otherwise reject:

cargo test
cargo test --test integration -- dead-strip --native --timeout 120
cargo test --test integration -- --all
cargo test --test integration -- --triple arm64-apple-tvos-simulator
cargo test --test integration -- --list

License

MIT, like mold.

S
Description
mold 🦠: A Modern Linker in Rust 🦀
Readme MIT
43 MiB
0 Stars 1 Watchers 0 Forks
mold 3.0.0
Latest
2026-11-06 16:54:55 -10:00
Languages
Rust 67.4%
Shell 32.1%
C 0.3%
Python 0.2%