Instructions
x86-64DIV / 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 size | Dividend | Quotient | Remainder |
|---|---|---|---|
| 8-bit | AX | AL | AH |
| 16-bit | DX:AX | AX | DX |
| 32-bit | EDX:EAX | EAX | EDX |
| 64-bit | RDX:RAX | RAX | RDX |
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): useCDQ/CQOto sign-extend the accumulator into the high half. - Unsigned (
DIV): zero the high half, almost always withxor edx, edx.
; unsigned: u / v
xor edx, edx
mov eax, u
div ecx ; EAX = u/v, EDX = u%vSeeing 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/idivfor division by a constant — these instructions are slow (tens of cycles). Instead they emit a magic-number multiply: animul/mulby a reciprocal followed by ashr/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/idivin 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/IDIVraise#DE(divide error) on divide-by-zero and on quotient overflow (e.g.INT_MIN / -1). On Linux this surfaces asSIGFPE— a handy crash to recognise.
See also: IMUL / MUL · Sign extension.
Try it — Virtual CPU
open full playground →- 1 mov eax, 100
- 2 mov ecx, 7
- 3 cdq
- 4 idiv ecx
- 5