I hav these two code snippets:
mov ax, word [wNum2]
cwd
div word [wNum3]
mov [wAns16], dx
movzx eax, word [wNum2]
;cwd
div word [wNum3]
mov [wAns16], edx
The first produces the correct answer, the second will give me an answer that is a hundred or so off unless I uncomment cwd.
My question is that I thought movzx would zero everything out for me, and that would make cwd un-needed. Have I completely misunderstood how they work? Can someone walk me through these code snippets?
The bare result can be equivalent or not - that depends on the value. The description of CWD states
Doubles the size of the operand in register AX, EAX, or RAX (depending on the operand size) by means of sign extension and stores the result in registers DX:AX, EDX:EAX, or RDX:RAX, respectively. The CWD instruction copies the sign (bit 15) of the value in the AX register into every bit position in the DX register.
So if the value in AX
is lower than 32,767 (15 bit MAX), the result of it is equivalent to MOVZX
(zero extend) and MOVSX
(sign extend). But if the value is greater, it would only be equivalent to MOVSX
. Usually MOVZX
would be used in combination with DIV
(unsigned division) and MOVSX
in combination with IDIV
(signed division).
But there remains the problem of where the result will be stored:
CWD
stores the 32-bit result in two 16-bit registers DX:AX
, while the MOV?X
instructions store it in the 32-bit register EAX
.
This has consequences on the following DIV
instruction. The first part of your code uses the 32-bit value in DX:AX
as input, while the second approach assumes EAX
to be the input of a 16-bit DIV
:
F7 /6 DIV r/m16 M Valid Valid Unsigned divide DX:AX by r/m16, with result stored in AX ← Quotient, DX ← Remainder.
which makes the result unpredictable, because DX
is undefined and the higher half of EAX
is unused in the division.
You should probably mention that you normally want to zero-extend before
div
(i.e.xor edx,edx
), and only sign-extend beforeidiv
. When and why do we sign extend and use cdq with mul/div? and Why should EDX be 0 before using the DIV instruction?