Instructions
x86-64BSF / BSR / POPCNT / LZCNT / TZCNT
Bit-counting instructions: find the first or last set bit, count leading or trailing zeros, or count how many bits are set. The hardware behind ffs, clz and popcount.
These instructions answer questions about which bits are set in a word. They map directly to common C intrinsics and standard-library helpers.
Bit scan — BSF / BSR
BSF dst, src (bit scan forward) returns the index of the
lowest set bit; BSR (reverse) returns the index of the highest
set bit.
bsf eax, ecx ; eax = index of lowest set bit of ecx
bsr eax, ecx ; eax = index of highest set bit (= floor(log2))Gotcha: if the source is 0, the result register is undefined and ZF
is set to 1. Correct code checks ZF (or guards the zero case) first — a
missing zero check is a real bug to look for.
Count zeros — LZCNT / TZCNT
LZCNT counts leading zeros, TZCNT counts trailing zeros.
They are the well-defined modern replacements for BSR/BSF:
- For a non-zero input,
TZCNTequalsBSF, andLZCNTequals(width-1) - BSR. - For a zero input they return the operand width (32 or 64) instead of being
undefined, and set
CF. Much safer. - Encoding quirk:
LZCNT/TZCNTareBSR/BSFwith anF3(REP) prefix. On a CPU without BMI/ABM support the prefix is ignored and the instruction runs asBSR/BSF— silently different behaviour on the zero case. Worth knowing when reversing code that must run on old hardware.
Population count — POPCNT
POPCNT dst, src counts the number of set bits (the Hamming weight).
popcnt eax, ecx ; eax = number of 1-bits in ecxReverse-engineering notes
- These decompile to recognisable intrinsics:
BSF/TZCNT→__builtin_ctz/_tzcnt;BSR/LZCNT→__builtin_clz/_lzcnt;POPCNT→__builtin_popcount/_mm_popcnt. BSRis the standard way to compute an integer log2 / find the highest power of two — common in allocators (size-class buckets), hash-table sizing, and bignum normalisation.TZCNT/BSFover a bitmap, often inside a loop that then clears the lowest bit withx & (x-1)(blsr), is the canonical "iterate over set bits" pattern — used everywhere from scheduler run-queues to chess engines.- A lone
POPCNTin otherwise integer-heavy code can hint at checksums, error-correcting codes, or similarity/Hamming-distance computations.
See also: BT / BTS / BTR / BTC · AND / OR / NOT · Shift & rotate.