tutorial registers lenguaje language instruction ensamblador assembly x86

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.