Avatar

LIEF patchelf

ionicons-v5-k Romain Thomas July 13, 2025
Wave

Featuring Image

Introduction

patchelf is a utility developed by the NixOS community to facilitate modifications of some parts of an ELF binary.

The features offered by patchelf include, but are not limited to:

1# Change the interpreter path
2$ patchelf --set-interpreter /lib/my-ld-linux.so.2 my-program
3
4# Add a new dependency
5$ patchelf --add-needed libfoo.so.1 my-program
6
7# Change RUN/RPATH values
8$ patchelf --set-rpath /opt/my-libs/lib:/other-libs my-program

In addition to its use in NixOS, many projects leverage patchelf to perform post-compilation modifications. For example, pypa/auditwheel uses patchelf to change the rpath value and/or change the names of DT_NEEDED libraries.

LIEF & Patchelf

In comparison to LIEF, patchelf is not a library, and the current version (0.18.0) can only be accessed via the command line. The source code of patchelf is relatively small (around 3,000 lines of code) and is focused on specific modifications such as renaming/removing DT_NEEDED entries and changing/removing/adding DT_RPATH/DT_RUNPATH.

When it comes to design decisions for modifying ELF binaries, there is a significant difference between patchelf and LIEF:

Section vs Segments

Patchelf relies on the section layout to modify and rewrite ELF binaries, while LIEF uses segments representation. This distinction makes patchelf less reliable for ELF binaries that have a non-standard section layout, whereas the representation used by LIEF corresponds to how binaries are loaded, making it less prone to errors during modifications.

LIEF-based patchelf

LIEF already had (almost) all the internal features to provide the same functionalities as patchelf. However, LIEF does not offer a comprehensive command-line tool like patchelf does. To create a drop-in replacement for patchelf using the LIEF backend, we had to ensure compatibility with the current state of patchelf, including:

  1. A command-line interface
  2. Completion for zsh (at least)
  3. A man-page

Thanks to the recent LIEF’s Rust bindings, we can leverage the Rust ecosystem to simplify the development of this command-line tool:

  • The crate clap-rs/clap provides all the features to create a command-line interface with a man-page and completion for the main shells.
  • Cargo and its dependencies management are convenient for generating an executable.

The source code is available here: lief-project/LIEF/tools/lief-patchelf and it is worth mentioning that this LIEF-based implementation has the exact same command line interface as the original patchelf:

 1$ lief-patchelf --help
 2Patchelf based on LIEF
 3
 4Usage: lief-patchelf [OPTIONS] [filenames]...
 5
 6Arguments:
 7  [filenames]...
 8
 9Options:
10      --set-interpreter <INTERPRETER>
11          Change the dynamic loader ('ELF interpreter') of executable given to INTERPRETER.
12
13      --page-size <SIZE>
14          Uses the given page size instead of the default
15
16      --print-interpreter
17          Prints the ELF interpreter of the executable. (e.g. `/lib64/ld-linux-x86-64.so.2`)
18
19      --print-os-abi
20          Prints the OS ABI of the executable (`EI_OSABI` field of an ELF file).

Moreover, it passes1 all the original patchelf’s test suite except one test related to the IA-64 architecture support:

PASS: set-interpreter-same.sh
PASS: no-rpath-alpha.sh
PASS: no-rpath-amd64.sh
PASS: no-rpath-armel.sh
PASS: no-rpath-armhf.sh
PASS: no-rpath-hurd-i386.sh
PASS: no-rpath-i386.sh
FAIL: no-rpath-ia64.sh
PASS: no-rpath-kfreebsd-amd64.sh
PASS: no-rpath-kfreebsd-i386.sh
PASS: no-rpath-mips.sh
PASS: no-rpath-mipsel.sh
PASS: no-rpath-powerpc.sh
PASS: no-rpath-s390.sh
PASS: no-rpath-sh4.sh
PASS: no-rpath-sparc.sh
============================================================================
Testsuite summary for patchelf 0.18.0 (based on LIEF 0.17.0)
============================================================================
# TOTAL: 58
# PASS:  55
# SKIP:  2
# XFAIL: 0
# FAIL:  1
# XPASS: 0
# ERROR: 0

Download

If you want to test this new LIEF-based implementation, you can download the compiled version here:


  1. Since LIEF performs in-depth modifications and can raise different error messages, I had to make minor changes on some checks: patchelf-test-lief.diff ↩︎

Avatar
Romain Thomas Posted on July 13, 2025