在使用DIV指令之前,为什么EDX应为0?

时间:2016-07-16 23:36:34

标签: assembly x86 integer-division

我注意到EDX包含一些随机默认值,如00401000,然后我使用这样的DIV指令:

mov eax,10
mov ebx,5
div ebx

导致INTEGER OVERFLOW ERROR。但是,如果我将edx设置为0并执行相同的操作。我相信使用div会导致商覆盖eax,其余覆盖edx

获得此INTEGER OVERFLOW ERROR确实让我感到困惑。

2 个答案:

答案 0 :(得分:7)

怎么做

对于32位/ 32位=> 32位除法:将32位被从EAX归零或符号扩展为64位EDX:EAX。
对于16位,AX进入DX:具有cwd或xor-zeroing的AX。

  • 未签名:XOR EDX,EDX然后DIV divisor
  • 已签名:CDQ然后IDIV divisor

另见When and why do we sign extend and use cdq with mul/div?

为什么(TL; DR)

对于DIV,寄存器EDXEAX形成一个64位的值(通常显示为EDX:EAX),然后将其划分,在本例中为EBX

因此,如果EAX = 10或十六进制AEDX20或十六进制14,那么它们一起形成64位值十六进制14 0000 000A或十进制85899345930。如果除以5,则结果为17179869186或十六进制 4 0000 0002这是一个不适合32位的值

这就是你得到整数溢出的原因。

但是,如果EDX仅为1,则您可以将1 0000 000A除以5,这会产生十六进制为3333 3335。这不是您想要的值,但它不会导致整数溢出。

要真正将32位寄存器EAX除以另一个32位寄存器,请注意EDX:EAX形成的64位值的顶部为0

所以,之前一个部门,你应该 EDX设置为0

(或者对于已签名的部门,cdqEAX之前将EDX:EAX扩展为idiv

EDX并非总是0。结果导致溢出可能不会那么大。

我的BigInteger代码中的一个示例:

在使用DIV进行除法后,该商位于EAX,余数位于EDX。要将BigInteger(由DWORDS组成的数组10除以 ; ECX contains number of "limbs" (DWORDs) to divide by 10 XOR EDX,EDX ; before start of loop, set EDX to 0 MOV EBX,10 LEA ESI,[EDI + 4*ECX - 4] ; now points to top element of array @DivLoop: MOV EAX,[ESI] DIV EBX ; divide EDX:EAX by EBX. After that, ; quotient in EAX, remainder in EDX MOV [ESI],EAX SUB ESI,4 ; remainder in EDX is re-used as top DWORD... DEC ECX ; ... for the next iteration, and is NOT set to 0. JNE @DivLoop (例如将值转换为十进制字符串),您可以执行以下操作:

BigInteger

在该循环之后,整个数组表示的值(即10)除以EDX@包含该除法的余数。

FWIW,在我使用的汇编程序(Delphi的内置汇编程序)中,以... gem 'sweet-alert' gem 'sweet-alert-confirm' ... 开头的标签是函数的本地标签,即它们不会干扰同名其他功能中的标签。

答案 1 :(得分:1)

DIV指令将EDX:EAX除以DIV指令后面的r / m32。因此,如果您未能将EDX设置为零,则您使用的值将变得非常大。

信任帮助