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-deterministicremoves the last non-determinism when the seed is 0 (module seed from the module-id hash instead ofrandom_device) — harmless to include always.-obf-seed-manifest=<path>records the fullbase/module/function/passseed 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):
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 fixedadec.*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.