The destination register of mul
and div
is not rax
, it's rdx:rax
. This is because both instructions return two results; mul
returns a double-width result and div
returns both quotient and remainder (after taking a double-width input).
The x86 instruction encoding scheme only permits two operands to be encoded in legacy instructions (div
and mul
are old, dating back to the 8086). Having only one operand permits the bits dedicated to the other operand to be used as an extension to the opcode, making it possible to encode more instructions. As the div
and mul
instructions are not used too often and as one operand has to be hard-coded anyway, hard-coding the second one was seen as a good tradeoff.
This ties into the auxillary instructions cbw
, cwd
, cwde
, cdq
, cdqe
, and cqo
used for preparing operands to the div
instruction.
Note that later, additional forms of the imul
instruction were introduced, permitting the use of two modr/m operands for the common cases of single word (as opposed to double-word) multiplication (80386) and multiplication by constant (80186). Even later, BMI2 introduced a VEX-encoded mulx
instruction permitting three freely chosable operands of which one source operand can be a memory operand.