问题描述
我注意到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
thenDIV divisor
- signed:
CDQ
thenIDIV divisor
另请参见何时以及为什么我们在mul/div上签名extend并使用cdq?
对于 DIV
,寄存器EDX
和EAX
形成一个单一的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
或十六进制A
和EDX
为20
或十六进制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 hex4 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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!