assembly - registers - ¿Por qué EDX debe ser 0 antes de usar la instrucción DIV?
lenguaje ensamblador x86 (2)
Esta pregunta ya tiene una respuesta aquí:
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
causa un ERROR DE DESBORDAMIENTO INTEGER. Sin embargo, si configuro edx
en 0 y hago lo mismo, funciona. Creía que usar div
daría como resultado que el cociente sobrescribiera eax
y el resto sobrescribiera edx
.
Obtener este INTEGER OVERFLOW ERROR realmente me confunde.
La instrucción DIV divide EDX: EAX por la 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
Para DIV
, los registros EDX
y EAX
forman un único valor de 64 bits (a menudo se muestra como EDX:EAX
), que luego se divide, en este caso, por EBX
.
Entonces, si EAX
= 10
o hex A
y EDX
son, digamos 20
o hex 14
, juntos forman el valor de 64 bits hex 14 0000 000A
o decimal 85899345930
. Si esto está dividido 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 el hexágono 1 0000 000A
por 5
, lo que da como resultado el hex 3333 3335
. Ese no es el valor que quería, pero no causa un desbordamiento de enteros.
Para dividir realmente el registro de 32 bits de 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 debe establecer EDX
en 0
.
(O para la división firmada, cdq
para firmar extender EAX
a EDX:EAX
antes de idiv
)
Pero EDX
no siempre tiene que ser 0
. Simplemente no puede ser tan grande que el resultado cause un desbordamiento.
Un ejemplo de mi código BigInteger
:
Después de una división con DIV
, el cociente está en EAX
y el resto está en EDX
. Para dividir algo así como un BigInteger
, que consiste en una matriz de muchas DWORDS
, por 10
(por ejemplo, para convertir el valor en una cadena decimal), haga algo como lo siguiente:
; ECX contains number of "limbs" (DWORDs) to divide by 10
XOR EDX,EDX
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 bucle, el valor representado por la matriz completa (es decir, por el BigInteger
) se divide por 10
, y EDX
contiene el resto de esa división.
FWIW, en mi ensamblador, las etiquetas que comienzan con @
son locales para la función, es decir, no interfieren con las etiquetas igualmente nombradas en otras funciones.