为什么在使用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
,寄存器EDX
和EAX
形成一个单一的64位值(通常显示为EDX:EAX
),然后被划分,在这种情况下, EBX
。
所以如果 EAX
= 10
或十六进制 A
和 EDX
是 20
或十六进制 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
。
(或者对于带符号的除法,cdq
将 EAX
符号扩展到 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
)表示的值除以 10
,EDX
包含该除法的余数。
FWIW,在我使用的汇编程序中(Delphi 的内置汇编程序),以 @
开头的标签是函数的局部标签,即它们不是干扰其他函数中的同名标签。
我注意到 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
,寄存器EDX
和EAX
形成一个单一的64位值(通常显示为EDX:EAX
),然后被划分,在这种情况下, EBX
。
所以如果 EAX
= 10
或十六进制 A
和 EDX
是 20
或十六进制 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
。
(或者对于带符号的除法,cdq
将 EAX
符号扩展到 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
)表示的值除以 10
,EDX
包含该除法的余数。
FWIW,在我使用的汇编程序中(Delphi 的内置汇编程序),以 @
开头的标签是函数的局部标签,即它们不是干扰其他函数中的同名标签。