不,MOVZX是零扩展,而不是符号。CWD符号扩展AX到DX:AX(就像你在IDIV之前想要的那样,而不是DIV)。 movSx eax, word [wNum2]是执行mov ax,mem + CWDE 的更有效的方法,而不是CWD。(如果您的输入在被视为有符号时是非负的,则符号和零扩展做同样的事情)。 What does cltq do in assembly?有一个cbw/cwde/cdqe和等效的movsx指令的表,以及cwd/cdq/cqo做什么(和等效的mov/sar)。
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
2条答案
按热度按时间qncylg1j1#
裸结果可以是等价的,也可以不是--这取决于值。
通过符号扩展将寄存器AX、EAX或RAX(取决于操作数大小)中的操作数大小加倍,并将结果分别存储在寄存器DX:AX、EDX:EAX或RDX:RAX中。CWD指令将AX寄存器中的值的符号(位15)复制到DX寄存器中的每个位位置。
所以如果
AX
中的值小于或等于32767(15位MAX),其结果相当于MOVZX
(零延伸)和MOVSX
(sign extend)。但如果该值大于32,通常MOVZX
与DIV
(无符号除法)结合使用,MOVSX
与IDIV
(有符号除法)结合使用。但仍存在将结果存储在何处的问题:
CWD
将32位结果存储在两个16位寄存器DX:AX
中,而MOV?X
指令将其存储在32位寄存器EAX
中。这会对下面的
DIV
指令产生影响。代码的第一部分使用DX:AX
中的32位值作为输入,而第二种方法假设EAX
是16位DIV
的输入:字符串
这使得结果不可预测,因为
DX
是未定义的,并且EAX
的高半部分在除法中未使用。tp5buhyn2#
不,MOVZX是零扩展,而不是符号。CWD符号扩展AX到DX:AX(就像你在IDIV之前想要的那样,而不是DIV)。
movSx eax, word [wNum2]
是执行mov ax,mem
+ CWDE 的更有效的方法,而不是CWD。(如果您的输入在被视为有符号时是非负的,则符号和零扩展做同样的事情)。What does cltq do in assembly?有一个cbw/cwde/cdqe和等效的movsx指令的表,以及cwd/cdq/cqo做什么(和等效的mov/sar)。
**在无符号
div
**之前,这些都不是你想要的:使用xor edx,edx
将DX置零,32/16 => 16位除法的高半输入。参见When and why do we sign extend and use cdq with mul/div?
为了避免写入部分寄存器时产生的假依赖,在最新的CPU上,最有效的方法是执行movzx加载,只是为了将16位值放入AX中,而不合并到RAX/EAX的前一个值中。同样,XOR置零(通常?)不被认为是部分寄存器上的置零习惯用法,因此即使只读取操作数的低半部分,也需要32位操作数大小。
字符串
您的代码将32位EDX存储到
[wAns16]
中可能是一个错误,假设在您访问它之后的任何内容之前只有2个字节的空间。