¿Por qué EDX debería ser 0 antes de usar la instrucción DIV?

Resuelto Kanna Kim asked hace 8 años • 2 respuestas

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 edxen 0 y hago lo mismo, funciona. Creí que usar divdaría como resultado que el cociente se sobrescribiera eaxy el resto se sobrescribiera.edx .

Obtener este ERROR DE DESBORDAMIENTO DE INTEGER realmente me confunde.

Kanna Kim avatar Jul 17 '16 06:07 Kanna Kim
Aceptado

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 cwdo xor-cero.

  • sin firmar: XOR EDX,EDXentoncesDIV divisor
  • firmado: CDQentoncesIDIV 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 EDXy EAXforman un único valor de 64 bits (a menudo mostrado como EDX:EAX), que luego se divide, en este caso, por EBX.

Entonces, si EAX= 10o hex Ay EDXes, digamos, 20o hex 14, entonces juntos forman el valor de 64 bits hex 14 0000 000Ao decimal 85899345930. Si se divide por 5, el resultado es 17179869186o 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 EDXfuera solo 1, dividiría hex 1 0000 000Apor 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 EAXpor otro registro de 32 bits, tenga cuidado de que la parte superior del valor de 64 bits formado por EDX:EAXsea 0.

Por lo tanto, antes de una sola división, generalmente debes configurarlo EDXen 0.

(O para la división con signo, cdqextender EAXel signo EDX:EAXantes idiv)


Pero EDXno siempre tiene que ser así 0. Simplemente no puede ser tan grande como para que el resultado provoque un desbordamiento.

Un ejemplo de mi BigIntegercódigo:

Después de una división con DIV, el cociente está en EAXy 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 10y EDXcontiene 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.

Rudy Velthuis avatar Jul 17 '2016 00:07 Rudy Velthuis

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

quasar66 avatar Jul 16 '2016 23:07 quasar66