Skip to content

Instructions

x86-64

DIV / IDIV

Integer division: DIV is unsigned, IDIV is signed. Both read an implicit double-width dividend and return quotient and remainder in fixed registers — and both can fault.

x86-64 has a single division primitive in two flavours: DIV (unsigned) and IDIV (signed). Unlike most arithmetic, division uses implicit operands — the dividend is always the accumulator pair, and the results land in fixed registers.

Implicit operands

The dividend is twice the width of the divisor. The single explicit operand is the divisor; quotient and remainder are written back to the accumulator pair.

Divisor sizeDividendQuotientRemainder
8-bitAXALAH
16-bitDX:AXAXDX
32-bitEDX:EAXEAXEDX
64-bitRDX:RAXRAXRDX
asm
mov eax, 100      ; dividend low half
mov ecx, 7        ; divisor
cdq               ; sign-extend EAX into EDX  (EDX:EAX = 100)
idiv ecx          ; EAX = 14 (quotient), EDX = 2 (remainder)

You must set up the high half first

This is the single most common mistake when reading or hand-writing division: EDX (or RDX) is part of the dividend, so it must be initialised before the divide.

  • Signed (IDIV): use CDQ/CQO to sign-extend the accumulator into the high half.
  • Unsigned (DIV): zero the high half, almost always with xor edx, edx.
asm
; unsigned: u / v
xor edx, edx
mov eax, u
div ecx           ; EAX = u/v, EDX = u%v

Seeing xor edx, edx immediately before a div is the signature of an unsigned divide; cdq/cqo before idiv marks a signed one.

Reverse-engineering notes

  • Compilers avoid div/idiv for division by a constant — these instructions are slow (tens of cycles). Instead they emit a magic-number multiply: an imul/mul by a reciprocal followed by a shr/sar. If you see a weird-looking constant multiplied in and then shifted, you're almost certainly looking at a hidden division. (See IMUL / MUL.)
  • A leftover div/idiv in the binary usually means division by a runtime value the compiler couldn't precompute.
  • % (modulo) is the same instruction — the compiler just reads the remainder register (edx/rdx) instead of the quotient.
  • DIV/IDIV raise #DE (divide error) on divide-by-zero and on quotient overflow (e.g. INT_MIN / -1). On Linux this surfaces as SIGFPE — a handy crash to recognise.

See also: IMUL / MUL · Sign extension.

Try it — Virtual CPU

open full playground →
  1. 1 mov eax, 100
  2. 2 mov ecx, 7
  3. 3 cdq
  4. 4 idiv ecx
  5. 5
step 0
Loading emulator…