7-Zip BCJ and BCJ2 Filters for x86 Executables
This article examines the BCJ and BCJ2 executable pre-processing filters implemented in 7-Zip for x86 binaries. It explains the specific data redundancy challenges posed by compiled machine code, how BCJ transforms relative jumps into absolute addresses, and how BCJ2 splits executable streams to maximize LZMA compression ratios.
The Purpose of Executable Filters
Compiled x86 executables naturally compress poorly with standard
dictionary-based algorithms like LZMA. This is primarily caused by
CALL and JMP instructions (opcodes
0xE8 and 0xE9), which use relative 32-bit
target offsets rather than absolute addresses. Even if a program
repeatedly calls the same subroutines, each call site calculates a
different relative offset depending on its position in memory. This
continuous variation destroys recurring byte patterns, drastically
reducing compression efficiency.
To solve this, 7-Zip applies specialized pre-processing filters (BCJ and BCJ2) prior to the compression stage to normalize target addresses and restore pattern redundancy.
The Standard BCJ Filter
The standard BCJ (Branch/Call/Jump) filter is a single-stream converter designed for 32-bit x86 machine code:
- In-Place Address Translation: The BCJ filter scans
the byte stream sequentially for standard x86
CALL(0xE8) and unconditionalJMP(0xE9) instructions followed by 32-bit displacement values. - Conversion Mechanism: It transforms these relative 32-bit offsets into absolute virtual addresses by adding the current instruction pointer position. As a result, every call directed to the same function across the executable is transformed into an identical 4-byte sequence.
- Single Output Stream: The filter operates entirely in-place. The modified executable remains as a single, contiguous stream that is then passed directly to an encoder, typically LZMA or LZMA2.
- Decompression Behavior: During decompression, the filter runs in reverse, subtracting the current file offset from the absolute addresses to reconstruct the original relative jump values.
The Advanced BCJ2 Filter
BCJ2 is an advanced 4-stream x86 filter exclusive to 7-Zip and the 7z archive format. Instead of keeping the transformed code within a single stream, BCJ2 separates the executable into four distinct data streams to achieve maximum compression density:
- Main Stream (Stream 0): Contains all standard machine code opcodes, uncompressed non-jump bytes, and operands not related to jump targets.
- CALL Target Stream (Stream 1): Contains the
extracted and normalized 32-bit absolute destination addresses for all
detected
0xE8(CALL) instructions. - JMP Target Stream (Stream 2): Contains the
extracted and normalized 32-bit absolute destination addresses for all
detected
0xE9(JMP) instructions. - Control/Status Stream (Stream 3): A bitstream that
tracks which bytes in the main stream correspond to genuine jump/call
instructions versus arbitrary data that happens to match
0xE8or0xE9opcodes.
How BCJ2 Improves Compression
By segregating addresses and raw opcodes:
- The regular instruction code in the main stream remains contiguous, enabling LZMA to detect instruction loops and standard sequences without interruption from 4-byte jump targets.
- Jump and call addresses cluster into separate streams, allowing the compressor to identify frequently targeted memory locations across the entire binary.
- The control stream is compressed using a dedicated range encoder, minimizing the overhead required to track instruction boundaries.
In 7-Zip, BCJ2 serves as the default filter for x86 Windows binaries
in maximum and ultra compression profiles within the .7z
container, consistently yielding significantly smaller archive sizes
than the basic single-stream BCJ filter.