Compile whole‐program LLVM bitcode files via rllvm - SVF-tools/SVF GitHub Wiki

rllvm builds a project as usual through compiler wrappers, then extracts one .bc for the whole program, like gllvm and wllvm. It needs no environment variables, and it also captures Rust and mixed C/Rust programs.

1. Install

# on macOS or Linux with Homebrew
brew install h1994st/tap/rllvm

# or build from source via cargo
cargo install rllvm

After this, we have the rllvm commands including rllvm-cc, rllvm-cxx, rllvm-rustc, rllvm-get-bc, rllvm-info and rllvm-init.

2. Choose the LLVM

On first run, rllvm detects LLVM from llvm-config and writes ~/.rllvm/config.toml. To use a specific LLVM, such as the one the bitcode's reader was built with ($LLVM_DIR after SVF's build.sh):

rllvm-init --llvm-prefix $LLVM_DIR

Add --dry-run to print what was detected without writing it. A reader handles bitcode from its own LLVM version and older.

3. Compile and extract bc

Set CC=rllvm-cc and CXX=rllvm-cxx, build as usual, then extract the bitcode from the finished binary:

# Makefile
CC=rllvm-cc make
rllvm-get-bc program  # output: program.bc

# CMake
CC=rllvm-cc CXX=rllvm-cxx cmake -S . -B build
cmake --build build
rllvm-get-bc build/program  # output: build/program.bc

Extra compiler flags pass through the wrappers, such as the ones the other examples on this wiki use:

export CC="rllvm-cc -O0 -Xclang -disable-O0-optnone -g -fno-discard-value-names"
export CXX="rllvm-cxx -O0 -Xclang -disable-O0-optnone -g -fno-discard-value-names"
make

rllvm-info program.bc prints the target and the function, block and instruction counts.

4. Rust and mixed C/Rust programs

CC=rllvm-cc CXX=rllvm-cxx RUSTC_WRAPPER=rllvm-rustc cargo build

rllvm-get-bc target/debug/program

C and C++ dependencies built by the crate go through CC=rllvm-cc CXX=rllvm-cxx as well, and land in the same module. The Rust standard library is prebuilt and contributes no bitcode. The configured LLVM must be at least as new as the one rustc -vV reports.

5. Examples

SVF

Please check SVF example in rllvm repo to learn more details on how to extract SVF whole-program bitcode, which also has a reproducible script running in Docker

Validated with SVF f3f09503 and LLVM 22.1.8 on Ubuntu.

git clone https://github.com/SVF-tools/SVF
cd SVF
git checkout f3f09503

apt-get install -y libz3-dev zlib1g-dev libzstd-dev libncurses-dev
rllvm-init --llvm-prefix /usr/lib/llvm-22

CC=rllvm-cc CXX=rllvm-cxx cmake -S . -B build \
    -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_DIR=/usr/lib/llvm-22 \
    -DBUILD_SHARED_LIBS=OFF -DSVF_WARN_AS_ERROR=OFF
cmake --build build

rllvm-get-bc build/bin/wpa -o wpa.bc

Static libraries put all of SVF into wpa, so one extraction yields the whole tool: 3351 functions.

nghttp2

nghttp2 repo: https://github.com/nghttp2/nghttp2

Please check nghttp2 example in rllvm repo to learn more details, which also covers nghttp3 and ngtcp2

git clone https://github.com/nghttp2/nghttp2
cd nghttp2
git checkout 140157a8

CC=rllvm-cc CXX=rllvm-cxx cmake -S . -B build \
    -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_LIB_ONLY=ON \
    -DBUILD_TESTING=OFF -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF
cmake --build build

rllvm-get-bc build/lib/libnghttp2.a -o nghttp2.bc

We get the library's 469 functions at this step.

quiche (Rust + C++), Cloudflare's QUIC library

quiche repo: https://github.com/cloudflare/quiche

Please check quiche example in rllvm repo to learn more details, including how BoringSSL, built by quiche's build script, is captured

git clone --recursive https://github.com/cloudflare/quiche
cd quiche
git checkout 4d23d859
git submodule update --init --recursive

CC=rllvm-cc CXX=rllvm-cxx RUSTC_WRAPPER=rllvm-rustc cargo build --release -p quiche

rllvm-get-bc target/release/libquiche.a -o quiche.bc

One module with the Rust crates and BoringSSL's C and C++: 7376 functions.

Run cargo clean first if quiche was built before without the wrappers: Cargo does not rebuild BoringSSL when only the compilers change.