Warm tip: This article is reproduced from stackoverflow.com, please click
assembly x86

movzx and cwd

发布于 2020-04-07 23:20:21

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?

Questioner
zapshe
Viewed
58
zx485 2020-02-01 11:38

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.