Assembly movzx和cwd-它们可以互换吗?

Assembly movzx和cwd-它们可以互换吗?,assembly,x86,Assembly,X86,我有以下两段代码片段: mov ax, word [wNum2] cwd div word [wNum3] mov [wAns16], dx 第一个生成正确的答案,第二个将给出100左右的答案,除非我取消注释cwd 我的问题是,我认为movzx会为我将一切归零,这将使cwd不再需要。我是否完全误解了它们的工作原理?有人能带我看一下这些代码片段吗?简单的结果可能是等价的,也可能是不等价的,这取决于值。对国家的描述 通过符号扩展将寄存器AX、EAX或RAX中的操作数大小加倍(取决于操作数大小),并

我有以下两段代码片段:

mov ax, word [wNum2]
cwd
div word [wNum3]
mov [wAns16], dx
第一个生成正确的答案,第二个将给出100左右的答案,除非我取消注释cwd


我的问题是,我认为movzx会为我将一切归零,这将使cwd不再需要。我是否完全误解了它们的工作原理?有人能带我看一下这些代码片段吗?

简单的结果可能是等价的,也可能是不等价的,这取决于值。对国家的描述

通过符号扩展将寄存器AX、EAX或RAX中的操作数大小加倍(取决于操作数大小),并将结果分别存储在寄存器DX:AX、EDX:EAX或RDX:RAX中。CWD指令将AX寄存器中值的符号(位15)复制到DX寄存器中的每个位位置

因此,如果
AX
中的值低于32767(最大15位),则其结果相当于
MOVZX
(零扩展)和
MOVSX
(符号扩展)。但是,如果该值更大,它将只相当于
MOVSX
。通常
MOVZX
将与
DIV
(无符号除法)结合使用,
MOVSX
将与
IDIV
(有符号除法)结合使用

但仍然存在将结果存储在何处的问题:
CWD
将32位结果存储在两个16位寄存器
DX:AX
,而
MOV?X
指令将其存储在32位寄存器
EAX

这会对以下说明产生影响。代码的第一部分使用
DX:AX
中的32位值作为输入,而第二种方法假定
EAX
是16位
DIV
的输入:

F7 /6   DIV r/m16   M   Valid   Valid   Unsigned divide DX:AX by r/m16, with result stored in AX ← Quotient, DX ← Remainder. 

这使得结果不可预测,因为
DX
未定义,
EAX
的上半部分在除法中未使用。

否,MOVZX是零扩展,不是符号。CWD符号将AX扩展为DX:AX(就像您希望在IDIV之前,而不是在DIV之前)

movSx-eax,word[wNum2]
是执行
mov-ax,mem
+CWDE而不是CWD的更有效的方法。(如果已知输入在被视为有符号时是非负的,则符号和零扩展做相同的事情)

有一个cbw/cwde/cdqe和等效movsx指令表,以及cwd/cdq/cqo的功能(和等效mov/sar)

在无符号
div
之前,这些东西都不是您想要的:使用
xor edx,edx
将DX(32/16=>16位除法的高半输入)归零

另见


为了避免写入部分寄存器的错误依赖性,在最新的CPU上,最有效的方法是执行movzx加载,只将16位值加载到AX中,而不合并到以前的RAX/EAX值中。类似地,xor归零(通常)不被认为是部分寄存器上的一种归零习惯用法,因此即使只读取数据的下半部分,也需要32位操作数大小

   movzx eax, word [wNum2]      ; zere extend only to avoid false dep from merging into EAX
   xor   edx, edx               ; high half dividend = DX = 0
   div   word [wNum3]
   mov   [wAns16], dx           ; store remainder from DX, not EDX

您将32位EDX存储到
[wAns16]
中的代码可能是一个bug,假设在您踩下它之后的任何东西之前只有2字节的空间。

您可能应该提到,您通常希望在
div
之前进行零扩展(即
xor EDX,EDX
),并且只在
idiv
之前进行符号扩展。和
   movzx eax, word [wNum2]      ; zere extend only to avoid false dep from merging into EAX
   xor   edx, edx               ; high half dividend = DX = 0
   div   word [wNum3]
   mov   [wAns16], dx           ; store remainder from DX, not EDX