Home / Alt manpages / llvm-ifs-20(1)

  • llvm-ifs-20(1)
  • User command
  • linux

Generate and Check ELF ABI Stubs with llvm-ifs

llvm-ifs-20 turns a shared library into a text-based IFS description you can diff, and when needed a linkable ELF stub generated straight from it. The IFS file earns its keep in ABI review, because it records the target, needed libraries and exported symbols in a form that is easy to compare across builds.

Allow about fifteen minutes. You need the llvm-20 package, a readable ELF shared object and a writable working directory. The examples use the installed llvm-ifs-20 20.1.8 package. None of them need sudo; reach for elevated privileges only to read a library your account cannot access, or to write into a protected build directory.

1. Confirm the installed interface

Start with read-only checks. This catches a common source of confusion: the installed binary's help is newer and more detailed than the local manpage's synopsis:

$ command -v llvm-ifs-20
/usr/bin/llvm-ifs-20
$ llvm-ifs-20 --version
Ubuntu LLVM version 20.1.8
  Optimized build.
$ dpkg-query -W -f='${Package} ${Version}\n' llvm-20
llvm-20 1:20.1.8~++20250804090239+87f0227cb601-1~exp1~20250804210352.139

The practical command shape on this installation is one input path followed by an output option: for an IFS file use --output-ifs=PATH, for a binary stub use --output-elf=PATH. Do not put an output path in the positional arguments. The help text does display llvm-ifs-20 <input_file> <output_file>, but doing that makes the second path another input and can produce a misleading parse error.

Checkpoint

If the version or option names differ on your system, stop and read that binary's --help before copying the commands below.

2. Choose an input without changing it

Pick the actual shared object, not a generated output file. This example follows the system's zlib symlink so the command reads the ELF file directly:

$ realpath /usr/lib/x86_64-linux-gnu/libz.so.1
/usr/lib/x86_64-linux-gnu/libz.so.1.3
$ test -r /usr/lib/x86_64-linux-gnu/libz.so.1.3 && echo readable
readable

Replace the path with your own library, and do not guess its architecture from the filename. If you are preparing a release artefact, record the library's build and package version alongside the generated IFS so a later diff has context.

3. Write an IFS ABI description

Create a temporary output directory and generate the text representation. Stating the input format explicitly makes the operation predictable instead of relying on format inference:

$ mkdir -p build/abi
$ llvm-ifs-20 /usr/lib/x86_64-linux-gnu/libz.so.1.3 \
    --input-format=ELF \
    --output-ifs=build/abi/libz.ifs
$ printf 'exit status: %s\n' "$?"
exit status: 0
$ sed -n '1,12p' build/abi/libz.ifs
--- !ifs-v1
IfsVersion:      3.0
SoName:          libz.so.1
Target:          { ObjectFormat: ELF, Arch: x86_64, Endianness: little, BitWidth: 64 }
NeededLibs:
  - libc.so.6
Symbols:
  - { Name: ZLIB_1.2.0, Type: Object, Size: 0 }

On this build the field is spelled IfsVersion and the target member is BitWidth. The installed manpage example instead uses IFSVersion and Bitwidth, spellings the 20.1.8 binary will not accept when reading an IFS file back in. Treat the generated file as the machine-readable contract, not something to hand-correct against the manpage.

The symbols are sorted, so a normal diff is genuinely useful:

$ file build/abi/libz.ifs
build/abi/libz.ifs: ASCII text
$ diff -u previous/libz.ifs build/abi/libz.ifs

No diff is not proof an ABI is safe in every context, but a changed symbol, size, target or needed library deserves review before you skip a relink on the strength of it.

4. Generate a linkable ELF stub

If a build needs an ELF object rather than a review file, read the IFS back and request an ELF output. This writes only the named destination:

$ llvm-ifs-20 build/abi/libz.ifs \
    --input-format=IFS \
    --output-elf=build/abi/libz.stub.so
$ file build/abi/libz.stub.so
build/abi/libz.stub.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), no program header, stripped
$ readelf -h build/abi/libz.stub.so | sed -n '1,14p'
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64

This is a linker-facing stub, not a replacement runtime library. It has no program headers in this tested output, and ordinary ELF analysis tools may not understand every stub shaped like this. Keep the real shared object for execution and package testing; use the stub only to skip an unnecessary relink when the recorded ABI has not moved.

Safety boundary

Do not install the stub over a system library or put it ahead of the real library in a production runtime search path. That can break programs outright. Keep it in a build-specific directory and pass it only to the link step that expects an ABI stub.

5. Keep repeatable generation quiet

For generated files, --write-if-changed preserves the existing output when the new content is identical. This helps build systems skip needless downstream work:

$ llvm-ifs-20 /usr/lib/x86_64-linux-gnu/libz.so.1.3 \
    --input-format=ELF \
    --output-ifs=build/abi/libz.ifs \
    --write-if-changed
$ sha256sum build/abi/libz.ifs
2b9f...  build/abi/libz.ifs

That hash is an example shape, not a value to copy: calculate it on your own output. If an earlier file was produced from a different library or target, do not let this option paper over that mistake; compare the input path, target and IFS content first.

6. Diagnose failures before retrying

A missing or unreadable input should return a non-zero status:

$ llvm-ifs-20 /path/to/missing.so --input-format=ELF --output-ifs=build/abi/missing.ifs
error: Could not open `/path/to/missing.so`
$ printf 'exit status: %s\n' "$?"
exit status: 1

Check the path and permissions without changing anything:

$ ls -l /path/to/library.so
$ test -r /path/to/library.so && echo readable

If an IFS read fails, inspect its first lines and compare the keys against a file generated by this same binary, in particular IfsVersion, BitWidth and a valid target. Do not "fix" a conflict by adding both spellings. If the target inside the file conflicts with --arch, --endianness, --bitwidth or --target, remove the conflicting override or regenerate the IFS for the target you actually intend.

Warning

The local 20.1.8 binary can crash when an ELF input and an output path are both supplied positionally, and it can also crash on malformed IFS data. Use one positional input and an explicit output option as shown above, and keep malformed or untrusted IFS files out of automated jobs. If a correctly shaped command still crashes, save the exact command, version and input details and report it to the LLVM project rather than treating the output as valid.

Done means

  • Version recorded. llvm-ifs-20 --version and the package version are noted.
  • Input untouched. The input is a readable ELF shared object and remains unchanged.
  • IFS generated correctly. An IFS file was produced with one positional input and --output-ifs.
  • Content reviewed. The IFS target and symbols were inspected or diffed before use.
  • Stub checked. Any ELF stub was written to a build directory and checked with file or readelf.
  • Nothing else affected. No stub replaced a runtime library or changed a service.