11 — Bitwise Operations¶
Bitwise operations are fundamental to assembly programming. You use them to manipulate individual bits, pack/unpack data, implement fast arithmetic, and work with hardware registers and flags.
The Core Operations¶
AND — Clear Bits (Masking)¶
Use AND to extract or clear specific bits:
and rax, 0x0F ; keep only the low nibble (bits 0-3)
and rax, 0xFF ; keep only the low byte
and rax, ~1 ; clear bit 0 (round down to even)
Truth table for a single bit:
OR — Set Bits¶
Use OR to set specific bits:
or rax, 0x01 ; set bit 0
or rax, 0x20 ; set bit 5 (converts uppercase ASCII to lowercase)
or rax, rbx ; combine flags
Truth table:
XOR — Toggle Bits¶
Use XOR to toggle bits, or to zero a register:
xor rax, rax ; rax = 0 (idiom: faster than mov rax, 0)
xor rax, 0xFF ; toggle the low byte
xor rax, rbx ; toggle bits where rbx has 1s
Truth table:
NOT — Complement¶
Shift Instructions¶
SHL — Shift Left Logical (multiply by 2ⁿ)¶
Bits shifted out go into CF. Zeros fill from the right.
SHR — Shift Right Logical (unsigned divide by 2ⁿ)¶
Zeros fill from the left. The original sign bit is NOT preserved.
SAR — Shift Right Arithmetic (signed divide by 2ⁿ)¶
The sign bit (MSB) is replicated — negative numbers stay negative.
ROL / ROR — Rotate Left / Right¶
No bits are lost in a rotation — they wrap around.
Shift Amount¶
The shift amount can be: - An immediate (compile-time constant) - The CL register (low byte of RCX) for dynamic shifts
Bit Manipulation Idioms¶
Test a Specific Bit¶
Set a Specific Bit¶
Clear a Specific Bit¶
Toggle a Specific Bit¶
Extract a Bit Field¶
To extract bits [hi:lo] (a range of bits):
; Extract bits 11:8 from RAX (4 bits)
mov rbx, rax
shr rbx, 8 ; shift right to bring target bits to position 0
and rbx, 0x0F ; mask to keep only 4 bits
Count Trailing Zeros (BSF)¶
Count Leading Zeros (BSR)¶
POPCNT — Population Count (count 1-bits)¶
LZCNT / TZCNT (BMI1)¶
Fast Arithmetic Using Shifts¶
Multiplying and dividing by powers of 2 with shifts is faster than MUL/DIV:
; Multiply by 2
shl rax, 1 ; rax *= 2
; Multiply by 8
shl rax, 3 ; rax *= 8
; Multiply by 5 (using LEA)
lea rax, [rax + rax*4] ; rax = rax + rax*4 = rax*5
; Multiply by 9
lea rax, [rax + rax*8] ; rax*9
; Divide by 4 (unsigned)
shr rax, 2
; Divide by 4 (signed)
sar rax, 2
Packing and Unpacking Data¶
Assembly often works with packed data (multiple values in one register).
Pack Two Bytes into One Word¶
; Pack: high byte = al, low byte = bl → ax
mov ah, al ; ah = al
mov al, bl ; al = bl
; ax now contains both values
Pack with Shifts¶
; Pack two 32-bit values into a 64-bit register
; rax = (high << 32) | low
mov eax, dword [low_val] ; eax = low (zero-extends to rax)
mov rbx, qword [high_val]
shl rbx, 32
or rax, rbx ; rax = high:low
Unpack¶
; Unpack: high 32 bits of rax into rbx
mov rbx, rax
shr rbx, 32 ; rbx = high 32 bits
and eax, 0xFFFFFFFF ; eax = low 32 bits (or use movzx)
XOR Swap (Without Temporary Register)¶
; Swap rax and rbx without a temp register
xor rax, rbx ; rax = rax ^ rbx
xor rbx, rax ; rbx = (rax^rbx) ^ rbx = rax
xor rax, rbx ; rax = (rax^rbx) ^ rax = rbx
Curiosity, not recommended — use
xchgor a temp register in practice.
Complete Example: Byte Manipulation¶
; bits.asm — various bit manipulation examples
section .text
global _start
_start:
mov rax, 0xDEADBEEF12345678
; Extract byte 3 (0-indexed from right): value = 0x56
mov rbx, rax
shr rbx, 24 ; shift byte 3 to position 0
and rbx, 0xFF ; rbx = 0x56
; Set bit 0 of rax
or rax, 1
; Clear bits 7:4 (low nibble of second byte)
and rax, ~(0xF0) ; clear bits 7:4
; Toggle bit 31
xor rax, (1 << 31)
; Count set bits in rbx
popcnt rcx, rbx
; Is rax even? (bit 0 == 0?)
test rax, 1
jnz .odd
; rax is even
.odd:
mov rax, 60
xor rdi, rdi
syscall
Key Takeaways¶
| Goal | Instruction Pattern |
|---|---|
| Zero a register | xor rax, rax |
| Test if zero | test rax, rax |
| Test bit N | test rax, (1 << N) |
| Set bit N | or rax, (1 << N) |
| Clear bit N | and rax, ~(1 << N) |
| Toggle bit N | xor rax, (1 << N) |
| Extract low N bits | and rax, (1 << N) - 1 |
| Multiply by 2ⁿ | shl rax, N |
| Unsigned divide by 2ⁿ | shr rax, N |
| Signed divide by 2ⁿ | sar rax, N |
| Count set bits | popcnt rax, rbx |