Skip to content

Installation

xollvm ships three ways from one source tree, with no edits to any LLVM file:

Target Mechanism Platforms
clang/opt toolchain (obfuscator built in) LLVM static extension (LLVM_EXTERNAL_PROJECTS + LINK_INTO_TOOLS) Linux · Windows · macOS
loadable plugin Obfuscator.so standalone build against installed LLVM (-fpass-plugin) Linux · macOS

Windows & loadable plugins

Loadable pass plugins need the host LLVM built with -DLLVM_EXPORT_SYMBOLS_FOR_PLUGINS=ON, which prebuilt toolchains don't ship. On Windows, use the static extension — the pass is compiled straight into clang/opt.


Prebuilt releases

If you just want binaries, skip building — grab a release:

File What OS
xollvm-linux-Release.tar.zst clang/opt with the obfuscator built in Linux x86_64
xollvm-windows-Release.7z clang/opt with the obfuscator built in Windows x64
Obfuscator-linux-x64.so loadable -fpass-plugin Linux x86_64

Backends included: X86 · AArch64 · ARM · RISCV.


Prerequisites

Common to every build:

  • CMake ≥ 3.20
  • Ninja (recommended generator)
  • Python 3 (generates the AES stub bitcode header)
  • A C++17 compiler
  • git

Mode-specific:

Build Also needs
Static extension A checkout of stock LLVM (release/22.x or release/23.x) and an external clang on PATH (see below)
Loadable plugin An installed LLVM 22 or 23 with CMake config + dev headers (llvm-22-dev / llvm-23-dev) and clang-22 / clang-23

LLVM 22 and 23

xollvm builds against both LLVM 22 and 23 from the same sources — the version is detected at compile time (LLVM_VERSION_MAJOR), no flags to flip. Every command below that pins release/22.x works identically with release/23.x. Changes are validated against both before release.

Why an external clang? (static extension only)

The AES runtime stub is compiled to LLVM bitcode by clang. When the obfuscator is linked into the tools (LINK_INTO_TOOLS), it cannot use the in-tree clang being built — that would form a dependency cycle (clang → LLVMExtensions → Obfuscator → aes → clang). So the build uses a separate, already-installed clang found on PATH. Any reasonably recent clang works; the LLVM 22/23 you build reads its (older) bitcode.

  • Linux: sudo apt-get install -y clang
  • Windows: choco install llvm (gives C:\Program Files\LLVM\bin\clang.exe)
  • macOS: the Xcode/Homebrew clang on PATH

Static extension (toolchain)

Builds clang, opt, etc. with the obfuscator compiled in. The three obfuscator flags are the whole integration:

  • LLVM_EXTERNAL_PROJECTS=Obfuscator — register xollvm as an external LLVM project
  • LLVM_EXTERNAL_OBFUSCATOR_SOURCE_DIR=<xollvm dir> — where its CMakeLists.txt lives
  • LLVM_OBFUSCATOR_LINK_INTO_TOOLS=ON — statically link it into clang/opt
git clone --depth 1 --branch release/22.x https://github.com/llvm/llvm-project  # or release/23.x
git clone https://github.com/und3ath/xollvm
sudo apt-get install -y ninja-build cmake python3 clang   # external clang for the aes stub

cmake -S llvm-project/llvm -B build -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_ENABLE_PROJECTS="llvm;clang" \
  -DLLVM_ENABLE_RTTI=ON -DLLVM_ENABLE_EH=ON \
  -DLLVM_TARGETS_TO_BUILD="X86;AArch64;ARM;RISCV" \
  -DLLVM_INCLUDE_TESTS=OFF -DLLVM_BUILD_TESTS=OFF \
  -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_BUILD_BENCHMARKS=OFF \
  -DLLVM_INCLUDE_EXAMPLES=OFF \
  -DCLANG_INCLUDE_TESTS=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF -DCLANG_ENABLE_ARCMT=OFF \
  -DLLVM_ENABLE_ASSERTIONS=OFF \
  -DLLVM_DISTRIBUTION_COMPONENTS="clang;clang-resource-headers;opt" \
  -DLLVM_EXTERNAL_PROJECTS=Obfuscator \
  -DLLVM_EXTERNAL_OBFUSCATOR_SOURCE_DIR="$PWD/xollvm" \
  -DLLVM_OBFUSCATOR_LINK_INTO_TOOLS=ON \
  -DCMAKE_INSTALL_PREFIX="$PWD/install"

# install-distribution builds ONLY the shipped components (clang, opt + libs),
# not the ~40 other standalone llvm-* tools — a big time saving.
cmake --build build --target install-distribution

From an x64 Native Tools developer prompt (after choco install llvm ninja):

git clone --depth 1 --branch release/22.x https://github.com/llvm/llvm-project  REM or release/23.x
git clone https://github.com/und3ath/xollvm

cmake -S llvm-project\llvm -B build -G Ninja ^
  -DCMAKE_BUILD_TYPE=Release ^
  -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL ^
  -DLLVM_ENABLE_PROJECTS="llvm;clang" ^
  -DLLVM_ENABLE_RTTI=ON -DLLVM_ENABLE_EH=ON ^
  -DLLVM_TARGETS_TO_BUILD="X86;AArch64;ARM;RISCV" ^
  -DLLVM_INCLUDE_TESTS=OFF -DLLVM_BUILD_TESTS=OFF ^
  -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_BUILD_BENCHMARKS=OFF ^
  -DLLVM_INCLUDE_EXAMPLES=OFF ^
  -DCLANG_INCLUDE_TESTS=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF -DCLANG_ENABLE_ARCMT=OFF ^
  -DLLVM_ENABLE_ASSERTIONS=OFF ^
  -DLLVM_PARALLEL_LINK_JOBS=1 ^
  -DLLVM_DISTRIBUTION_COMPONENTS="clang;clang-resource-headers;opt" ^
  -DLLVM_EXTERNAL_PROJECTS=Obfuscator ^
  -DLLVM_EXTERNAL_OBFUSCATOR_SOURCE_DIR=%CD%\xollvm ^
  -DLLVM_OBFUSCATOR_LINK_INTO_TOOLS=ON ^
  -DCMAKE_INSTALL_PREFIX=%CD%\install

cmake --build build --target install-distribution

LLVM_PARALLEL_LINK_JOBS=1 keeps peak RAM sane during the big links.

Tip

Trim LLVM_TARGETS_TO_BUILD to just what you need (e.g. X86) for a much faster build. Want the full toolchain (llvm-*, lld, …)? Drop LLVM_DISTRIBUTION_COMPONENTS and build --target install instead — slower and much larger.


Loadable plugin

Builds only the pass, against an installed LLVM 22 or 23. No LLVM source build — fast. (The example below uses 22; substitute 23 throughout for an LLVM 23 install.)

# Ubuntu 24.04 lacks clang-22/llvm-22 in default repos; add apt.llvm.org:
wget -qO llvm.sh https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 22
sudo apt-get install -y ninja-build clang-22 llvm-22 llvm-22-dev

git clone https://github.com/und3ath/xollvm
cmake -S xollvm -B build -G Ninja \
  -DLLVM_DIR=/usr/lib/llvm-22/lib/cmake/llvm \
  -DCMAKE_C_COMPILER=clang-22 -DCMAKE_CXX_COMPILER=clang++-22 \
  -DCMAKE_BUILD_TYPE=Release
ninja -C build Obfuscator            # -> build/Obfuscator.so

On distros that already ship LLVM 22 (e.g. Ubuntu 26.04) the llvm.sh step is unnecessary — just apt-get install llvm-22-dev clang-22.


Verify the build

cat > ann.c <<'EOF'
#define OBF(spec) __attribute__((annotate("obf: " spec)))
OBF("mba, bcf, split")
int secret(int x){ int a=x*3+7; for(int i=0;i<x;i++) a+=(i^a); return a; }
EOF

clang -O0 -emit-llvm -S ann.c -o ann.ll
./install/bin/opt -passes=obfuscation ann.ll -S -o ann.obf.ll
./install/bin/opt -passes=verify ann.obf.ll -disable-output && echo OK
opt-22 -load-pass-plugin=./build/Obfuscator.so -passes=obfuscation ann.ll -S -o ann.obf.ll

@secret should grow substantially; an unannotated function is left untouched.


Troubleshooting

Symptom Cause / fix
Unable to locate package clang-22 / llvm-22-dev Ubuntu 24.04 default repos lack LLVM 22. Add apt.llvm.org: sudo ./llvm.sh 22.
fatal error: aes_stub_bc.inc: No such file AES stub header not generated before compile. Build with the current CMakeLists.txt; reconfigure from clean.
aes stub: external clang not found No clang on PATH for the stub. Install one — the in-tree clang can't be used under LINK_INTO_TOOLS.
dependency-cycle error at configure The aes stub picked the in-tree clang. Ensure an external clang is found first, or that LLVM_OBFUSCATOR_LINK_INTO_TOOLS=ON is set.
-load-pass-plugin aborts on Windows Loadable plugins aren't supported on Windows. Use the static extension.
Option '…' registered more than once A second copy of LLVM's global state. Don't static-link LLVM into the .so.