Back to Technology

x86 Assembly Series Part 10: Integer Arithmetic & Bitwise Operations

February 6, 2026 Wasil Zafar 32 min read

Master integer arithmetic (ADD, SUB, MUL, IMUL, DIV, IDIV), bitwise operations (AND, OR, XOR, NOT), shift and rotate instructions, and understanding carry/overflow flags for robust numeric code.

Table of Contents

  1. Addition & Subtraction
  2. Multiplication
  3. Division
  4. Bitwise Operations
  5. Shifts & Rotates
  6. Flags & Overflow Detection

Addition & Subtraction

ADD, SUB, ADC, SBB

add rax, rbx        ; RAX = RAX + RBX
add rax, 100        ; RAX = RAX + 100
sub rcx, rdx        ; RCX = RCX - RDX

; Multi-precision addition (128-bit)
add rax, [low64]    ; Add low 64 bits
adc rdx, [high64]   ; Add high 64 bits with carry

; Multi-precision subtraction
sub rax, [low64]
sbb rdx, [high64]   ; Subtract with borrow
Diagram showing ADD, SUB, ADC, and SBB instruction flow with carry and borrow flags
ADD and SUB modify all arithmetic flags, while ADC and SBB incorporate the carry/borrow flag for multi-precision arithmetic

INC, DEC, NEG

inc rax             ; RAX = RAX + 1 (doesn't affect CF)
dec rbx             ; RBX = RBX - 1 (doesn't affect CF)
neg rcx             ; RCX = -RCX (two's complement)

Multiplication

MUL (Unsigned Multiplication)

Important: MUL uses implicit operands. For 64-bit: RAX × operand → RDX:RAX (128-bit result).

x86 Assembly Mastery

Your 25-step learning path • Currently on Step 11
Development Environment, Tooling & Workflow
IDEs, debuggers, build tools, workflow setup
Assembly Language Fundamentals & Toolchain Setup
Syntax basics, assemblers, linkers, object files
x86 CPU Architecture Overview
Instruction pipeline, execution units, microarchitecture
Registers – Complete Deep Dive
GPRs, segment, control, flags, MSRs
Instruction Encoding & Binary Layout
Opcode bytes, ModR/M, SIB, prefixes, encoding schemes
NASM Syntax, Directives & Macros
Sections, labels, EQU, %macro, conditional assembly
Complete Assembler Comparison
NASM vs MASM vs GAS vs FASM, syntax differences
Memory Addressing Modes
Direct, indirect, indexed, base+displacement, RIP-relative
Stack Internals & Calling Conventions
Push/pop, stack frames, cdecl, System V ABI, fastcall
Control Flow & Procedures
Jumps, loops, conditionals, CALL/RET, function design
11
Integer, Bitwise & Arithmetic Operations
ADD, SUB, MUL, DIV, AND, OR, XOR, shifts, rotates
You Are Here
12
Floating Point & SIMD Foundations
x87 FPU, IEEE 754, SSE scalar, precision control
13
SIMD, Vectorization & Performance
SSE, AVX, AVX-512, data-parallel processing
14
System Calls, Interrupts & Privilege Transitions
INT, SYSCALL, IDT, ring transitions, exception handling
15
Debugging & Reverse Engineering
GDB, breakpoints, disassembly, binary analysis, IDA
16
Linking, Relocation & Loader Behavior
ELF/PE formats, symbol resolution, dynamic linking, GOT/PLT
17
x86-64 Long Mode & Advanced Features
64-bit extensions, RIP addressing, canonical addresses
18
Assembly + C/C++ Interoperability
Inline assembly, calling C from ASM, ABI compliance
19
Memory Protection & Security Concepts
DEP, ASLR, stack canaries, ROP, mitigations
20
Bootloaders & Bare-Metal Programming
BIOS/UEFI, MBR, real mode, protected mode transition
21
Kernel-Level Assembly
Context switching, interrupt handlers, TSS, GDT/LDT
22
Complete Emulator & Simulator Guide
QEMU, Bochs, instruction-level simulation, debugging VMs
23
Advanced Optimization & CPU Internals
Pipeline hazards, branch prediction, cache optimization, ILP
24
Real-World Assembly Projects
Shellcode, drivers, cryptography, signal processing
25
Assembly Mastery Capstone
Final project, comprehensive review, advanced techniques
; 64-bit unsigned multiplication
mov rax, 1000
mov rbx, 2000
mul rbx             ; RDX:RAX = RAX * RBX
                    ; RAX = low 64 bits, RDX = high 64 bits
Diagram of MUL instruction showing implicit RDX:RAX 128-bit result
MUL uses implicit operands — the 64-bit result is split across RDX (high) and RAX (low) for full 128-bit precision

IMUL (Signed Multiplication)

; Three forms of IMUL
imul rbx            ; RDX:RAX = RAX * RBX (one operand)
imul rax, rbx       ; RAX = RAX * RBX (two operands)
imul rax, rbx, 10   ; RAX = RBX * 10 (three operands)

Division

DIV (Unsigned Division)

; 64-bit: RDX:RAX / operand → RAX (quotient), RDX (remainder)
xor rdx, rdx        ; Clear RDX for 64-bit dividend
mov rax, 100
mov rbx, 7
div rbx             ; RAX = 100/7 = 14, RDX = 100%7 = 2
Diagram of DIV instruction showing RDX:RAX dividend split into quotient and remainder
DIV divides the 128-bit value in RDX:RAX by the operand, storing the quotient in RAX and remainder in RDX

IDIV (Signed Division)

; Must sign-extend RAX into RDX:RAX first
mov rax, -100
cqo                 ; Sign-extend RAX into RDX:RAX
mov rbx, 7
idiv rbx            ; RAX = -14, RDX = -2

Bitwise Operations

AND, OR, XOR, NOT

and rax, rbx        ; RAX = RAX & RBX
or  rax, rbx        ; RAX = RAX | RBX
xor rax, rbx        ; RAX = RAX ^ RBX
not rax             ; RAX = ~RAX (one's complement)

; Common idioms
xor rax, rax        ; Clear register (faster than mov rax, 0)
and rax, 0x0F       ; Mask lower nibble
or  rax, 0x80       ; Set bit 7
Visual representation of AND, OR, XOR, and NOT bitwise operations on binary values
Bitwise operations process each bit independently — AND masks, OR sets, XOR toggles, and NOT inverts all bits

Common Bit Tricks

OperationCodeEffect
Test if power of 2test rax, rax-1 ; jz is_power_of_2 (needs LEA trick)n & (n-1) == 0
Isolate lowest set bitblsi rax, rbx or and rax, -raxe.g., 0b10110 → 0b00010
Clear lowest set bitblsr rax, rbx or and rax, rax-1e.g., 0b10110 → 0b10100
Swap values (no temp)xor a,b; xor b,a; xor a,bXOR swap trick
Set nth bitbts rax, n or or rax, (1 << n)Set specific bit
Clear nth bitbtr rax, nClear specific bit
Toggle nth bitbtc rax, n or xor rax, (1 << n)Flip specific bit
Count set bitspopcnt rax, rbxPopulation count (needs CPU support)
Find first set bitbsf rax, rbxBit scan forward (from LSB)
Find last set bitbsr rax, rbxBit scan reverse (from MSB)
; Check if number is power of 2
is_power_of_two:
    test rdi, rdi           ; Check if zero
    jz .not_power           ; 0 is not a power of 2
    lea rax, [rdi - 1]      ; rax = n - 1
    test rdi, rax           ; n & (n-1)
    jnz .not_power          ; If non-zero, not power of 2
    mov eax, 1              ; Is power of 2
    ret
.not_power:
    xor eax, eax
    ret

; Count trailing zeros (position of lowest set bit)
count_trailing_zeros:
    bsf rax, rdi            ; Bit scan forward
    jnz .found
    mov eax, 64             ; If input was 0, return 64
.found:
    ret

Exercise: Extract Bit Field

Extract bits 4-7 from a register (4-bit field):

; Extract bits 4-7 from RDI into RAX
extract_bits_4_7:
    mov rax, rdi
    shr rax, 4              ; Shift field to bit 0
    and rax, 0x0F           ; Mask to keep only 4 bits
    ret

Shifts & Rotates

shl rax, 1          ; Shift left (multiply by 2)
shr rax, 1          ; Shift right logical (unsigned divide by 2)
sar rax, 1          ; Shift right arithmetic (signed divide by 2)
rol rax, 1          ; Rotate left
ror rax, 1          ; Rotate right

; Fast multiplication by power of 2
shl rax, 3          ; RAX = RAX * 8

Flags & Overflow Detection

Arithmetic operations set CPU flags that indicate result characteristics:

CPU RFLAGS register layout highlighting ZF, SF, CF, OF, PF, and AF flag positions
The RFLAGS register contains status flags set by arithmetic operations — CF and OF are critical for detecting unsigned and signed overflow
FlagNameSet WhenUse For
ZFZero FlagResult is zeroEquality checks, loop termination
SFSign FlagResult is negative (MSB=1)Signed comparisons
CFCarry FlagUnsigned overflow/borrowMulti-precision arithmetic, unsigned checks
OFOverflow FlagSigned overflowSigned arithmetic error detection
PFParity FlagEven number of 1-bits in low byteRarely used (legacy)
AFAuxiliary FlagBCD carry from bit 3 to bit 4BCD arithmetic (legacy)

Overflow vs Carry

Key Distinction:

CF (Carry) - Unsigned overflow:
  0xFFFFFFFF + 1 = 0x00000000 with CF=1
  (Unsigned: 4294967295 + 1 wraps to 0)

OF (Overflow) - Signed overflow:
  0x7FFFFFFF + 1 = 0x80000000 with OF=1
  (Signed: 2147483647 + 1 wraps to -2147483648)
; Detect unsigned overflow
add rax, rbx
jc .unsigned_overflow       ; CF=1 means overflow

; Detect signed overflow
add rax, rbx
jo .signed_overflow         ; OF=1 means overflow

; Safe addition with overflow check
safe_add_unsigned:
    add rdi, rsi
    jc .overflow_error
    mov rax, rdi
    ret
.overflow_error:
    mov rax, -1              ; Return error code
    ret

; Multi-precision 128-bit addition (using CF)
; RDX:RAX += RCX:RBX
add rax, rbx                ; Add low 64 bits
adc rdx, rcx                ; Add high 64 bits + carry
Which Flag to Check?
  • Unsigned arithmetic: Check CF (Carry Flag)
  • Signed arithmetic: Check OF (Overflow Flag)
  • Subtraction/comparison: CF indicates borrow (A < B unsigned)

Exercise: Saturating Addition

Implement unsigned addition that saturates at MAX instead of wrapping:

; saturate_add(a, b): returns min(a+b, 0xFFFFFFFFFFFFFFFF)
saturate_add:
    mov rax, rdi
    add rax, rsi            ; rax = a + b
    sbb rcx, rcx            ; rcx = 0 if no carry, -1 if carry
    or rax, rcx             ; If overflow, rax becomes all 1s (MAX)
    ret