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

Why should EDX be 0 before using the DIV instruction?

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

mov eax,10
mov ebx,5
div ebx

它会导致整数溢出错误。但是,如果我将 edx 设置为 0 并执行相同的操作,它就会起作用。我相信使用 div 会导致商覆盖 eax 而余数覆盖 edx

得到这个 INTEGER OVERFLOW ERROR 真的让我很困惑。

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

信任有帮助

做什么

对于 32 位/32 位 => 32 位除法:将 32 位被除数从 EAX 零或符号扩展为 64 位 EDX:EAX。
对于 16 位,使用 cwd 或异或归零将 AX 转换为 DX:AX。

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

另见


为什么(长话短说;博士)

对于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

所以,单个除法之前,你应该一般设置EDX0

(或者对于带符号的除法,cdqEAX 符号扩展到 idiv 之前的 EDX:EAX


EDX 并不一定总是 0。结果导致溢出的程度可能不会那么大。

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

DIV除后,商在EAX,余数在EDX。要将由许多 DWORDS 组成的数组 BigInteger 除以 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)表示的值除以 10EDX 包含该除法的余数。

FWIW,在我使用的汇编程序中(Delphi 的内置汇编程序),以 @ 开头的标签是函数的局部标签,即它们不是干扰其他函数中的同名标签。