装配师由0AH

时间:2017-04-25 09:33:27

标签: assembly hex

我在汇编386工作,我在一个循环中继续将数字除以0Ah我一直得到一个我无法理解的结果是我的代码:

MOV EAX,94Ch
MOV ten,0Ah;ten is of size DD that i've defined 
XOR ECX,ECX
L1:
CMP EAX,0;check if the number is zero
JE somewhere
DIV ten
INC CL
JMP L1

EAX 17h 并且我除以 0Ah 时,我得到 CCCF 当我应该得到EAX中的 2 。 为什么会那样?

1 个答案:

答案 0 :(得分:1)

DIV指令有点棘手,要理解它,您需要仔细查看the documentation

首先,请注意您的代码正在执行32位除法。我知道的方式是你有DIV ten,而ten是一个DWORD(因为你用DD声明了它)。 DWORD是32位。

从上面链接的文档中,我们可以看到32位除法将EDX:EAX除以操作数(在本例中为ten)。它将商存储在EAX中,余数存储在EDX

好的,等一下 - 什么是EDX:EAX?这是使用两个32位寄存器存储64位值的方法的表示法。高DWORD位于EDX,低DWORD位于EAX。将它们组合在一起,就可以获得64位的值。

希望您现在明白为什么您的归零EDX解决方案有效,以及为什么没有这样做会得到错误的结果。除法实际上隐含地使用EDX寄存器作为被除数的一部分,因此如果它包含垃圾,则除法的结果将是错误的。

现在您已经理解了这个问题,您可以记住这个简单的规则:每当使用DIV指令进行32位除法时,总是将{{ 1}}注册。归零寄存器的惯用且最有效的方法当然是with the XOR instruction


请注意,签名除法(IDIV)会出现类似的问题,但在这种情况下,您不需要将EDX清零。您需要以尊重符号位的方式扩展EDX中的值。 CDQ instruction为您执行此操作:它将EAX签名延伸到EAX,为EDX:EAX做好准备。要学习的另一个简单规则 - IDIV实际上应始终位于CDQ之前。

最后一点免费优化建议:

IDIV

相当于:

CMP EAX, 0

但是后者组装到更少的字节代码(因为它不使用立即操作数)并且在许多情况下更快(因为它的尺寸较小以及它更可能与宏的融合后续分支指令,例如 TEST EAX, EAX )。

那么另一条规则(汇编编程不是很有趣吗?):在测试寄存器是否为0时,使用JE按位与自身进行比较。

您希望查看内存位置是否为0(不先将其加载到寄存器中)时,唯一一次使用TEST