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

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

Create and Check ELF Link Stubs with llvm-ifs

llvm-ifs-18 builds a text-based IFS description of a shared library for ABI review, plus a small ELF stub a linker can use instead of the real thing. Both come out reproducible. The examples use the installed llvm-ifs-18, LLVM 18.1.3 from package llvm-18.

Allow about fifteen minutes. You need a shell, the LLVM 18 package, a readable ELF shared object, and a directory where you can throw away generated files. This workflow only reads the input and writes new output; it does not replace a library, touch the linker cache, or need sudo.

1. Check the installed command

Start with version and help output. These are ordinary, read-only commands:

$ llvm-ifs-18 --version
Ubuntu LLVM version 18.1.3
  Optimized build.
$ dpkg-query -W -f='${Package} ${Version}\n' llvm-18
llvm-18 1:18.1.3-1ubuntu1

The manpage describes the tool as accepting ELF shared objects or IFS files and producing IFS, ELF or Apple TAPI output. The installed help also shows the current positional form, llvm-ifs-18 <input_file> <output_file>, plus explicit --input-format and output-path options. Prefer the explicit options in scripts, since the input and output roles stay visible on the command line rather than hidden in position.

Checkpoint

If llvm-ifs-18 --version reports a different release, keep that version in your notes. Option details and IFS fields can vary between LLVM releases.

2. Choose a safe input and workspace

Use a shared object that is readable and not being replaced by a package upgrade mid-run. This example uses zlib's system library and writes only below /tmp:

$ input=/usr/lib/x86_64-linux-gnu/libz.so.1
$ work=$(mktemp -d /tmp/llvm-ifs.XXXXXX)
$ test -r "$input" && printf 'input: %s\nworkspace: %s\n' "$input" "$work"
input: /usr/lib/x86_64-linux-gnu/libz.so.1
workspace: /tmp/llvm-ifs.example

Warning

The workspace name above is generated by mktemp, so the displayed path is only an example. Do not point an output option at a production library or at a path a build is using concurrently. If the input is a private build artefact, check its architecture and ABI separately before comparing it with another file.

3. Export an IFS ABI snapshot

Generate a text IFS file from the ELF input. The command can infer the ELF contents on its own, but stating --input-format=ELF makes a wrong guess easier to diagnose:

$ llvm-ifs-18 --input-format=ELF \
    --output-ifs="$work/libz.ifs" \
    "$input"
$ sed -n '1,12p' "$work/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 }

IFS is YAML-based text. It records target information, needed libraries and sorted symbol records, including whether a symbol is undefined or weak where that is known, which makes it suitable for review or for a diff in an ABI-checking job. A changed file is a signal to investigate, not automatic proof a release is incompatible.

Checkpoint

Confirm the file begins with --- !ifs-v1, has an IfsVersion, and names the expected shared object. If generation fails with an interface type mismatch, try another shared object or investigate the input's symbol metadata; do not treat a failed export as an empty snapshot.

4. Build a linkable ELF stub

Convert the IFS snapshot into an ELF shared-object stub in the same disposable workspace:

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

Warning

The stub is for link-time use only. It is not a replacement runtime library, since it contains the interface the linker needs, not the implementation. Keep the real library available for execution and packaging, and make sure your build cannot accidentally install the stub over it.

LLVM documents a deliberately minimal ELF layout for this purpose. Some ELF analysis tools expect program headers, while linkers such as LLD can work fine with the minimal output. Use your actual linker and build tests to confirm compatibility before adopting a stub in a release pipeline.

5. Make repeated generation quiet and stable

For a job that regenerates snapshots on every build, add --write-if-changed. It leaves an existing output untouched whenever the generated content is identical:

$ sha256sum "$work/libz.ifs"
30ffa4f0a3326e7f976d9c83ad626a8a2230bcd56d97510fdf23a88ce38daff3  /tmp/llvm-ifs.example/libz.ifs
$ llvm-ifs-18 --input-format=ELF \
    --output-ifs="$work/libz.ifs" \
    --write-if-changed "$input"
$ sha256sum "$work/libz.ifs"
30ffa4f0a3326e7f976d9c83ad626a8a2230bcd56d97510fdf23a88ce38daff3  /tmp/llvm-ifs.example/libz.ifs

That hash is an observed result for the installed library on this machine, not a value to hard-code in your own checks: compare the file in version control or against a trusted build artefact instead. There is no persistent undo step here; remove the disposable workspace once you have finished reviewing it, or leave it and clean it up under your normal temporary-file policy.

6. Handle target metadata deliberately

When converting IFS to ELF, the target fields inside the IFS describe the output architecture, byte order and bit width. If the IFS deliberately omits target details, supply compatible values with --arch, --endianness and --bitwidth, or use one --target triple. Do not mix --target with the other target flags.

Never force a different target just to make a command complete. The tool reports a conflict when metadata disagrees, and that is a useful safety stop, as this attempt to produce an AArch64 output from an ELF x86-64 input shows: it fails rather than silently relabelling anything:

$ llvm-ifs-18 --input-format=IFS \
    --target=aarch64-linux-gnu \
    --output-elf="$work/wrong-target.so" "$work/libz.ifs"
error: Target triple cannot be used simultaneously with ELF target format
$ printf 'status=%s\n' "$?"
status=1

If you need a portable IFS, generate it with target fields intentionally stripped, then restore them only once the consuming build knows the target. Keep that choice visible in the build configuration and revisit it when architectures change.

Done means

  • Version noted. You recorded the installed LLVM version and selected a readable ELF input.
  • Snapshot generated. You generated an IFS file and inspected its target, dependencies and symbols.
  • Stub built and checked. You generated an ELF stub in a disposable path and checked it with file or readelf.
  • Stability considered. You use --write-if-changed where stable repeated output matters.
  • Conflicts respected. You treat target conflicts and interface type errors as diagnostics, not reasons to force output.
  • Nothing else disturbed. You kept the generated stub away from runtime library paths and made no system changes.