What assembly instructions are used for multiplication and division, and what registers do they require?
Full multiply and divide implicitly use the %rdx:%rax register pair as a 128-bit value — and division requires you to set up %rdx first (with cqo/zeroing) or it produces garbage or a fault.
* %rdx:%rax is one 128-bit pair: multiply fills it, divide consumes it — so set up %rdx first (cqto for signed, zero for unsigned) or you fault. *
These are the most special-cased arithmetic instructions because their operands are hard-wired to specific registers.
Multiplication comes in two flavors. The single-operand form produces a full 128-bit product in %rdx:%rax; the two- or three-operand imul truncates to 64 bits:
mul %rbx # %rdx:%rax = %rax * %rbx (unsigned, full)
imul %rbx, %rax # %rax = %rax * %rbx (signed, truncated)
imul $5, %rbx, %rax # %rax = %rbx * 5 (three-operand)
Division divides the 128-bit %rdx:%rax by the operand, leaving the quotient in %rax and remainder in %rdx. The dangerous part is the setup of %rdx:
cqo # sign-extend %rax into %rdx:%rax (for SIGNED division)
idiv %rbx # signed divide
mov $0, %rdx # clear %rdx (for UNSIGNED division)
div %rbx # unsigned divide
Warning: forgetting to set up %rdx, or dividing by zero, raises a CPU exception — a frequent crash in hand-written assembly.
Go deeper:
Felix Cloutier — MUL — the MUL reference showing the RDX:RAX product pair.
Felix Cloutier — DIV — the DIV reference showing the RDX:RAX dividend and quotient/remainder.