xr is a standalone Rust CLI tool for ultra-fast, parallel extraction of
cross-references from stripped binaries (ELF, Mach-O, PE). It emits
(from_va, to_va, kind) tuples at orders-of-magnitude faster speed than
traditional disassemblers.
cargo build --release
# Analyse a binary at the recommended depth
./target/release/xr /path/to/binary --depth paired
# Output as JSONL or CSV
./target/release/xr /path/to/binary --depth paired --format jsonl
./target/release/xr /path/to/binary --depth paired --format csv
# Filter to a specific xref kind
./target/release/xr /path/to/binary --depth paired --kind call
# Show disasm context around each xref site (like grep -A/-B)
./target/release/xr /path/to/binary --depth paired -A 3 -B 2
206 million xrefs from a 4.6 GB dyld shared cache (3240 images) in under 6 seconds:
$ xr /System/Library/dyld/dyld_shared_cache_x86_64 > /dev/null
dyld shared cache: arch=X86_64 mappings=24 images=3240 subcaches=5
xrefs: 206432528 | 5.7s | 4620.3 MB scanned | 24 segments
Default text output:
$ xr binary --depth paired --limit 4
0x00000000006a268f -> 0x00000000006a2699 jump [linear-immediate]
0x00000000006a26a1 -> 0x00000000006a25ea call [linear-immediate]
0x00000000006a26b7 -> 0x0000000000798345 call [linear-immediate]
0x00000000006a26cf -> 0x00000000006a2368 data_ptr [linear-immediate]
With disassembly context (-B 2 -A 1):
$ xr binary -k call --limit 2 -B 2 -A 1
0x00000000006a26d6 -> 0x00000000006a2393 call [linear-immediate]
0x00000000006a26ca 48 8d 4c 24 0c lea rcx, [rsp+0Ch]
0x00000000006a26cf 48 8d 15 92 fc ff ff lea rdx, [6A2368h]
> 0x00000000006a26d6 e8 b8 fc ff ff call 00000000006A2393h
0x00000000006a26db 48 83 c4 18 add rsp, 18h
With Rust string heuristics (--rust):
$ xr target/release/my_app --rust -k data_ptr
...
0x00000001002b0238 -> 0x0000000100243834 data_ptr [byte-scan] "STRIKETHROUGH"
0x00000001002b4b68 -> 0x00000001002744d2 data_ptr [byte-scan] "failed to write the buffered data"
0x00000001002b5de0 -> 0x000000010022e8b0 data_ptr [byte-scan] "src/arch/arm64.rs"
0x00000001002b5e10 -> 0x000000010022e8c2 data_ptr [byte-scan] "src/arch/x86_64.rs"
| Flag | Name | What it does |
|---|---|---|
--depth scan |
ByteScan | Pointer-sized byte scan of data sections |
--depth linear |
Linear | Linear disasm, immediate targets + RIP-relative |
--depth paired |
Paired | ADRP+ADD/LDR pairs (ARM64) or register prop (x86-64), recommended |
See docs/STATUS.md for architecture details and known gaps.
- ELF (x86-64, AArch64), including PIE (ET_DYN)
- Single-arch Mach-O (x86-64, ARM64). Fat binaries require
lipo -extractfirst - PE / COFF (x86-64, ARM64)
- Apple dyld shared cache
- Raw flat binary (treated as single executable segment)
x86-32 and ARM32 binaries are loaded but not scanned (architecture stubs only).
USAGE:
xr [OPTIONS] <BINARY>
OPTIONS:
-d, --depth <DEPTH> Analysis depth: scan | linear | paired [default: paired]
-j, --workers <N> Worker threads; 0 = all CPUs [default: 0]
-f, --format <FORMAT> Output format: text | jsonl | csv [default: text]
-k, --kind <KIND> Filter by kind: call | jump | data_read | data_write | data_ptr
--base <VA> Override PIE ELF load base (hex or decimal)
--min-ref-va <VA> Drop xrefs whose 'to' VA is below this value
--start <VA> Scan only 'from' addresses >= VA
--end <VA> Scan only 'from' addresses < VA
--ref-start <VA> Retain only xrefs with 'to' >= VA
--ref-end <VA> Retain only xrefs with 'to' < VA
--limit <N> Cap output at N xrefs (0 = unlimited)
-A, --after-context <N> Show N instructions after each xref site
-B, --before-context <N> Show N instructions before each xref site
--rust Extract Rust string literals from data_ptr xrefs
--rust-min-blob <N> Min UTF-8 blob size in bytes [default: 16]
--rust-string-max <N> Max display width for strings (0 = unlimited) [default: 100]
# Build the benchmark binary
cargo build --release --bin benchmark
# Run against a ground-truth file
./target/release/benchmark \
--binary /path/to/binary \
--ground-truth /path/to/binary.xrefs.json \
--depth pairedThis project includes a Claude Code skill
in .claude/skills/xrefs/ that teaches Claude how to use xr for binary
reverse-engineering workflows: finding callers/callees, data references,
pointer hunting, and more.