patchelf.rb is a pure-Ruby library and command-line tool for inspecting and
modifying selected fields in ELF executables and shared libraries. It implements
the operations Homebrew needs, but it is not a complete drop-in replacement for
NixOS/patchelf.
- Ruby 3.3 or newer.
- An ELF input file. The host running Ruby does not itself need to be Linux.
CI tests the gem on Linux and macOS with Ruby 3.3, 3.4, and 4.0. Tests that execute patched ELF files run on Linux only. Windows is not currently tested.
Install the released gem from RubyGems:
gem install patchelfOr add it to a Bundler-managed project:
gem 'patchelf'patchelf.rb [OPTIONS] INPUT_FILE [OUTPUT_FILE]If OUTPUT_FILE is omitted, the input file is modified in place. In-place
writes are not atomic, so use an explicit output path when the original cannot
be recreated safely.
Run patchelf.rb --help for the complete option list. Common operations are:
| Operation | Option |
|---|---|
| Print the interpreter | --print-interpreter, --pi |
| Print needed libraries | --print-needed, --pn |
Print DT_RUNPATH |
--print-runpath, --pr |
| Print the shared-library name | --print-soname, --ps |
| Set the interpreter | --set-interpreter INTERP, --interp INTERP |
| Set all needed libraries | --set-needed LIB1,LIB2, --needed LIB1,LIB2 |
| Add, remove, or replace one needed library | --add-needed, --remove-needed, --replace-needed |
Set DT_RUNPATH |
--set-runpath PATH, --runpath PATH |
Operate on DT_RPATH instead |
--force-rpath |
| Set the shared-library name | --set-soname SONAME, --so SONAME |
These examples use Linux paths and tools:
# Inspect an executable.
patchelf.rb --print-interpreter --print-needed /bin/ls
# Write a changed copy instead of modifying the input.
patchelf.rb --runpath '$ORIGIN/../lib' input.elf output.elf
# Replace one DT_NEEDED entry.
patchelf.rb --replace-needed libc.so.6,libcnew.so.6 input.elf output.elfThe executable exits non-zero for invalid options, missing arguments, more than two positional arguments, unreadable inputs, invalid ELF files, and expected patching failures.
require 'patchelf'
patcher = PatchELF::Patcher.new('/path/to/input.elf', on_error: :exception)
puts patcher.interpreter
puts patcher.needed
patcher.interpreter = '/new/dynamic/loader'
patcher.runpath = '$ORIGIN/../lib'
patcher.save('/path/to/output.elf', patchelf_compatible: true)on_error controls how missing ELF segments and tags are handled:
:loglogs a warning and returnsnil.:silentreturnsnilwithout logging.:exceptionraises aPatchELFexception.
Patcher#save provides two rewriting strategies:
| Strategy | Intended use | Current mutation support |
|---|---|---|
| Default | General-purpose rewriting | Interpreter, needed libraries, RPATH/RUNPATH, and SONAME |
patchelf_compatible: true |
Layout behavior closer to NixOS/patchelf | Interpreter and RPATH/RUNPATH |
The compatible saver does not yet implement needed-library or SONAME changes.
Some ELF layouts also require growth operations that are not implemented and
raise NotImplementedError. The CLI currently uses the default saver; use the
Ruby API when compatible layout behavior is required.
A patcher keeps its input file open for the lifetime of the object. Avoid retaining patcher instances in long-running processes after their work is complete.
Fixture coverage is primarily x86-64, with a 32-bit x86 regression fixture and unit coverage for architecture-specific page sizes. Validate rewritten binaries on every target architecture before distributing them.
Full API documentation is available on RubyDoc.
See CONTRIBUTING.md for setup, test commands, fixture policy, and the release-quality checks run in CI.
Bug reports and feature requests belong in GitHub Issues.
Please report suspected vulnerabilities through GitHub private vulnerability reporting, following Homebrew's security policy. Do not disclose a suspected vulnerability in a public issue before maintainers have had a reasonable opportunity to investigate it.
The Git history is the definitive record of contributions.
- Original author and project founder: david942j (
@david942j) - Maintainers: Homebrew maintainers and david942j
The gem is available under the MIT License. Historical third-party test fixtures retain their upstream terms, documented in THIRD_PARTY_NOTICES.md.