¿Por qué EDX debería ser 0 antes de usar la instrucción DIV?
Me di cuenta cuando EDX contiene algún valor predeterminado aleatorio como 00401000, y luego uso una instrucción DIV como esta:
mov eax,10
mov ebx,5
div ebx
provoca un ERROR DE DESBORDAMIENTO DE ENTERO. Sin embargo, si lo configuro edx
en 0 y hago lo mismo, funciona. Creí que usar div
daría como resultado que el cociente se sobrescribiera eax
y el resto se sobrescribiera.edx
.
Obtener este ERROR DE DESBORDAMIENTO DE INTEGER realmente me confunde.
Qué hacer
Para 32 bits / 32 bits => división de 32 bits: extienda con cero o signo el dividendo de 32 bits de EAX a EDX:EAX de 64 bits.
Para 16 bits, AX en DX:AX con cwd
o xor-cero.
- sin firmar:
XOR EDX,EDX
entoncesDIV divisor
- firmado:
CDQ
entoncesIDIV divisor
Consulte también ¿Cuándo y por qué firmamos extend y usamos cdq con mul/div?
Por qué (TL; DR)
Para DIV
, los registros EDX
y EAX
forman un único valor de 64 bits (a menudo mostrado como EDX:EAX
), que luego se divide, en este caso, por EBX
.
Entonces, si EAX
= 10
o hex A
y EDX
es, digamos, 20
o hex 14
, entonces juntos forman el valor de 64 bits hex 14 0000 000A
o decimal 85899345930
. Si se divide por 5
, el resultado es 17179869186
o hexadecimal
4 0000 0002
, que es un valor que no cabe en 32 bits .
Es por eso que obtienes un desbordamiento de enteros.
Sin embargo, si EDX
fuera solo 1
, dividiría hex 1 0000 000A
por 5
, lo que da como resultado hex
3333 3335
. Ese no es el valor que deseaba, pero no provoca un desbordamiento de enteros.
Para dividir realmente un registro de 32 bits EAX
por otro registro de 32 bits, tenga cuidado de que la parte superior del valor de 64 bits formado por EDX:EAX
sea 0
.
Por lo tanto, antes de una sola división, generalmente debes configurarlo EDX
en 0
.
(O para la división con signo, cdq
extender EAX
el signo EDX:EAX
antes idiv
)
Pero EDX
no siempre tiene que ser así 0
. Simplemente no puede ser tan grande como para que el resultado provoque un desbordamiento.
Un ejemplo de mi BigInteger
código:
Después de una división con DIV
, el cociente está en EAX
y el resto en EDX
. Para dividir algo como a BigInteger
, que consta de una matriz de many DWORDS
, entre 10
(por ejemplo, para convertir el valor a una cadena decimal), haga algo como lo siguiente:
; 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
Después de ese ciclo, el valor representado por toda la matriz (es decir, por BigInteger
) se divide por 10
y EDX
contiene el resto de esa división.
FWIW, en el ensamblador que uso (el ensamblador integrado de Delphi), las etiquetas que comienzan con @
son locales de la función, es decir, no interfieren con etiquetas con nombres iguales en otras funciones.
La instrucción DIV divide EDX:EAX por el r/m32 que sigue a la instrucción DIV. Por lo tanto, si no establece EDX en cero, el valor que está utilizando se vuelve extremadamente grande.
Confianza que ayuda