Skip to content
Oeiuwq Faith Blog OpenSource Porfolio

Mic92/formatelf

Modify dynamic linker, RPATH and other ELF metadata of executables

Mic92/formatelf.json
{
"createdAt": "2026-06-26T09:45:20Z",
"defaultBranch": "main",
"description": "Modify dynamic linker, RPATH and other ELF metadata of executables",
"fullName": "Mic92/formatelf",
"homepage": "",
"language": "Rust",
"name": "formatelf",
"pushedAt": "2026-07-03T18:28:43Z",
"stargazersCount": 5,
"topics": [],
"updatedAt": "2026-07-03T22:04:30Z",
"url": "https://github.com/Mic92/formatelf"
}

Status: beta, currently under testing in https://github.com/numtide/llm-agents.nix

A reimplementation of patchelf in Rust: modify the dynamic linker, RPATH, and other ELF metadata of executables and shared libraries.

It is CLI-compatible with patchelf and the Nix package installs a patchelf symlink, so it works as a drop-in replacement.

Terminal window
nix build github:Mic92/formatelf # result/bin/formatelf (+ patchelf symlink)
nix run github:Mic92/formatelf -- --version

To build without the patchelf symlink:

Terminal window
nix build --expr '(builtins.getFlake (toString ./.)).packages.x86_64-linux.default.override { patchelfSymlink = false; }'

Without Nix:

Terminal window
cargo build --release # target/release/formatelf
Terminal window
formatelf --set-interpreter /lib/ld-linux-x86-64.so.2 ./prog
formatelf --set-rpath '$ORIGIN/../lib' ./prog
formatelf --print-needed ./prog
formatelf --replace-needed libfoo.so.1 libbar.so.1 ./prog

Run formatelf --help for the full option list. The flags mirror patchelf, including --set-interpreter, --set-rpath/--add-rpath/--shrink-rpath, --add-needed/--remove-needed/--replace-needed, --set-soname, --set-os-abi, --clear-symbol-version, --set-execstack/--clear-execstack, --rename-dynamic-symbols, and the NixOS --build-resolution-cache.

The read-only operations (--print-rpath, --print-needed, --print-interpreter, --print-soname) work on binaries whose section headers have been stripped, recovering the data from PT_DYNAMIC and PT_INTERP. Reference patchelf refuses these outright.

The flake’s dev shell provides the toolchain:

Terminal window
nix develop
cargo test
cargo clippy --tests

Tests build their own ELF fixtures with zig cc on demand (no binaries are committed). The differential tests compare output byte-for-byte against a reference patchelf; they skip themselves when zig or the reference is absent. PATCHELF_REFERENCE overrides the reference binary’s path.

cargo-fuzz targets cover the read path (parse), the write path (mutate), and the argument parser (cli). They build on stable via RUSTC_BOOTSTRAP:

Terminal window
RUSTC_BOOTSTRAP=1 cargo fuzz run parse -s none

MIT