Skip to content

Reproducible builds

xollvm is deterministic: same input + same seed = byte-identical output. This guide turns that property into an auditable release workflow, or into deliberate per-build diversity.

Background: Determinism & seeds.

Reproducible (CI / signed releases)

Pin the base seed and archive the manifest alongside the artifact:

opt -passes=obfuscation app.ll -S -o app.obf.ll \
    -obf-seed=0xC0DE -obf-deterministic \
    -obf-seed-manifest=app.seeds.json
  • -obf-seed=<N> (non-zero) makes every run identical.
  • -obf-deterministic removes the last non-determinism when the seed is 0 (module seed from the module-id hash instead of random_device) — harmless to include always.
  • -obf-seed-manifest=<path> records the full base/module/function/pass seed tree.

Store app.seeds.json with the release. Months later you can rebuild the exact same binary, or diff two manifests to prove only the intended functions changed.

Verify reproducibility in CI

Obfuscate twice and compare — a mismatch means something non-deterministic slipped in (unpinned seed, or a transform depending on hash-map order):

opt -passes=obfuscation app.ll -S -o a.ll -obf-seed=1 -obf-deterministic
opt -passes=obfuscation app.ll -S -o b.ll -obf-seed=1 -obf-deterministic
diff a.ll b.ll && echo "reproducible"

Per-build diversity (ship a different binary each release)

To defeat signature matching across releases, vary the seed per build — e.g. derive it from the version — while still archiving each manifest so any build stays reproducible:

SEED=$(printf '%s' "$VERSION" | cksum | cut -d' ' -f1)
opt -passes=obfuscation app.ll -S -o app.obf.ll \
    -obf-seed="$SEED" -obf-deterministic \
    -obf-seed-manifest="app-$VERSION.seeds.json"

Pair this with the anti-signature knobs so nothing else stays constant across builds:

  • -adec-prefix=<random> and -adec-randomize-consts — no fixed adec.* names or decoy constants.
  • vm(randISA=1) — per-build bytecode encoding.

Embedding seeds in the IR

-obf-seed-manifest-md also stamps per-pass seeds into IR metadata (obf.seed.manifest.<passId>), so the provenance travels with the module even without the sidecar JSON. Useful when the IR is your archival artifact.