为什么在使用DIV指令之前EDX必须为0? [英] Why should EDX be 0 before using the DIV instruction?

查看:138
本文介绍了为什么在使用DIV指令之前EDX必须为0?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I noticed when EDX contains some random default value like 00401000, and I then use a DIV instruction like this:

mov eax,10
mov ebx,5
div ebx

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

it causes an INTEGER OVERFLOW ERROR. However, if I set edx to 0 and do the same thing it works. I believed that using div would result in the quotient overwriting eax and the remainder overwriting edx.

收到此整数溢出错误确实使我感到困惑.

Getting this INTEGER OVERFLOW ERROR really confuses me.

推荐答案

怎么办

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

What to do

For 32-bit / 32-bit => 32-bit division: zero- or sign-extend the 32-bit dividend from EAX into 64-bit EDX:EAX.
For 16-bit, AX into DX:AX with cwd or xor-zeroing.

  • 未签名:XOR EDX,EDX然后是DIV divisor
  • 签名:CDQ然后IDIV divisor
  • unsigned: XOR EDX,EDX then DIV divisor
  • signed: CDQ then IDIV divisor

另请参见何时以及为什么我们在mul/div上签名extend并使用cdq?

对于 DIV ,寄存器EDXEAX形成一个单一的64位值(通常显示为EDX:EAX),然后在这种情况下除以EBX.

For DIV, the registers EDX and EAX form one single 64 bit value (often shown as EDX:EAX), which is then divided, in this case, by EBX.

因此,如果EAX = 10或十六进制AEDX20或十六进制14,则它们一起形成64位值十六进制14 0000 000A或十进制85899345930 .如果将其除以5,则结果为17179869186或十六进制
4 0000 0002,该值不适合32位.

So if EAX = 10 or hex A and EDX is, say 20 or hex 14, then together they form the 64 bit value hex 14 0000 000A or decimal 85899345930. If this is divided by 5, the result is 17179869186 or hex
4 0000 0002, which is a value that does not fit in 32 bits.

这就是为什么会出现整数溢出的原因.

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

If, however, EDX were only 1, you would divide hex 1 0000 000A by 5, which results in hex
3333 3335. That is not the value you wanted, but it does not cause an integer overflow.

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

To really divide 32 bit register EAX by another 32 bit register, take care that the top of the 64 bit value formed by EDX:EAX is 0.

因此,之前,您应该通常EDX设置为0.

So, before a single division, you should generally set EDX to 0.

(或对于带符号的除法,cdq用来在idiv之前将EAX扩展为EDX:EAX)

(Or for signed division, cdq to sign extend EAX into EDX:EAX before idiv)

但是EDX不一定总是必须是0.结果导致溢出可能不会太大.

But EDX does not have always have to be 0. It can just not be that big that the result causes an overflow.

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

One example from my BigInteger code:

除以DIV后,商在EAX中,其余部分在EDX中.要将由许多DWORDS数组组成的BigInteger之类的内容除以10(例如,将值转换为十进制字符串),您可以执行以下操作:

After a division with DIV, the quotient is in EAX and the remainder is in EDX. To divide something like a BigInteger, which consists of an array of many DWORDS, by 10 (for instance to convert the value to a decimal string), you do something like the following:

    ; 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包含该除法的其余部分.

After that loop, the value represented by the entire array (i.e. by the BigInteger) is divided by 10, and EDX contains the remainder of that division.

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

FWIW, in the assembler I use (Delphi's built-in assembler), labels starting with @ are local to the function, i.e. they don't interfere with equally named labels in other functions.

这篇关于为什么在使用DIV指令之前EDX必须为0?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆