llvm-link-20 combines two LLVM bitcode modules into one file, then lets you inspect the result as readable IR before you trust it. Allow about fifteen minutes. You need the llvm-20 package and two readable bitcode files, or the LLVM assembler if you want to make the small test modules below.
The examples describe Ubuntu's llvm-link-20 from LLVM 20.1.8, installed from package llvm-20. The command links LLVM bitcode modules, not native object files, ELF executables or source files.
Start with ordinary, read-only checks. No elevated privileges are needed:
$ command -v llvm-link-20
/usr/bin/llvm-link-20
$ llvm-link-20 --version
Ubuntu LLVM version 20.1.8
Optimized build.
$ llvm-link-20 --help | sed -n '1,12p'
OVERVIEW: llvm linker
USAGE: llvm-link-20 [options] <input bitcode files>
Keep the version in mind when comparing results with another machine. LLVM tools are often installed side by side, so use the versioned command explicitly in scripts when you need this toolchain.
If you already have bitcode, skip to the next step. Otherwise, create temporary LLVM assembly files and assemble them. This changes only files under /tmp:
$ cat > /tmp/llvm-link-left.ll <<'EOF'
define i32 @left() {
ret i32 7
}
EOF
$ cat > /tmp/llvm-link-right.ll <<'EOF'
define i32 @right() {
ret i32 42
}
EOF
$ llvm-as-20 /tmp/llvm-link-left.ll -o /tmp/llvm-link-left.bc
$ llvm-as-20 /tmp/llvm-link-right.ll -o /tmp/llvm-link-right.bc
$ file /tmp/llvm-link-left.bc /tmp/llvm-link-right.bc
/tmp/llvm-link-left.bc: LLVM IR bitcode
/tmp/llvm-link-right.bc: LLVM IR bitcode
Do not use sudo for this workflow. The assembler and linker read the inputs and write your chosen output. If the input directory is protected, copy files to a workspace where you have permission rather than broadening privileges casually.
Pass one or more input bitcode files and use -o for the destination. The input order matters when definitions collide, so make it explicit:
$ llvm-link-20 /tmp/llvm-link-left.bc /tmp/llvm-link-right.bc -o /tmp/llvm-linked.bc
$ printf 'exit status: %s\n' "$?"
exit status: 0
$ file /tmp/llvm-linked.bc
/tmp/llvm-linked.bc: LLVM IR bitcode
A zero exit status means the link completed. The two input files remain untouched. If you omit -o, llvm-link writes raw bitcode to standard output, which is useful in a pipeline but awkward for a terminal.
Checkpoint: If the destination already exists, stop and decide whether it is disposable. A normal shell redirection or an explicit output path can replace an existing file. Use a new name while testing:
$ test ! -e /tmp/llvm-linked-check.bc && echo destination-is-new
destination-is-new
$ llvm-link-20 /tmp/llvm-link-left.bc /tmp/llvm-link-right.bc -o /tmp/llvm-linked-check.bc
Use -S to write LLVM assembly instead of bitcode. This is an output choice, not a request to assemble the inputs again:
$ llvm-link-20 -S /tmp/llvm-link-left.bc /tmp/llvm-link-right.bc -o /tmp/llvm-linked.ll
$ sed -n '1,20p' /tmp/llvm-linked.ll
; ModuleID = 'llvm-link'
source_filename = "llvm-link"
define i32 @left() {
ret i32 7
}
define i32 @right() {
ret i32 42
}
LLVM may print harmless metadata or formatting differences between builds. The useful check here is that both definitions are present. You can also convert the bitcode produced in step 3 with llvm-dis-20:
$ llvm-dis-20 /tmp/llvm-linked.bc -o /tmp/llvm-linked-from-bc.ll
$ grep -E '^define .*@(left|right)\(' /tmp/llvm-linked-from-bc.ll
define i32 @left() {
define i32 @right() {
Raw bitcode is not readable terminal output. With no -o, redirect it to a file or pipe it to a program that expects bitcode:
$ llvm-link-20 /tmp/llvm-link-left.bc /tmp/llvm-link-right.bc > /tmp/llvm-linked-stdout.bc
$ cmp --silent /tmp/llvm-linked.bc /tmp/llvm-linked-stdout.bc && echo same-link-result
same-link-result
The installed linker normally refuses raw binary output when standard output is a terminal. The manual documents -f for deliberately enabling binary output on terminals. Avoid that option during normal interactive use: it produces control characters rather than useful text. Choose -S when your goal is inspection.
For a brief activity trace, add -v. Diagnostics are written separately from the bitcode result, so redirecting standard output does not turn warnings into part of the output file:
$ llvm-link-20 -v /tmp/llvm-link-left.bc /tmp/llvm-link-right.bc -o /tmp/llvm-linked-verbose.bc
llvm-link-20: Linking file '/tmp/llvm-link-left.bc'
llvm-link-20: Linking file '/tmp/llvm-link-right.bc'
The exact verbose wording can vary. Treat it as a diagnostic aid, not as a stable machine-readable format.
A missing input, a non-bitcode input, or incompatible module content produces a non-zero exit status. Capture the error while keeping the previous output safe by linking to a temporary name:
$ if llvm-link-20 /path/to/first.bc /path/to/second.bc -o /tmp/linked.new; then
> mv /tmp/linked.new /path/to/linked.bc
> else
> status=$?
> rm -f /tmp/linked.new
> printf 'link failed with status %s\n' "$status" >&2
> fi
That pattern does not overwrite the established output if linking fails. The mv is the state-changing step: use it only after the new bitcode has passed your inspection or downstream test. If you replace a file accidentally, restore it from your normal backup or build artefact; llvm-link has no undo operation.
llvm-link-20 --version reports the intended LLVM 20 toolchain.-S or llvm-dis-20 shows the expected definitions in the result.