问题描述
我注意到当 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 位除法:将 32 位除数从 EAX 零或符号扩展为 64 位 EDX:EAX.
对于 16 位,使用 cwd
或 xor-zeroing 将 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 除数
- 签名:
CDQ
然后IDIV除数
- unsigned:
XOR EDX,EDX
thenDIV divisor
- signed:
CDQ
thenIDIV divisor
另见当为什么我们签署扩展并使用带有 mul/div 的 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
或hex4 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
将EAX
符号扩展到idiv
之前的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
中.将诸如 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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!