2010-12-27 14 views
5

Durante la lectura a través de algún código fuente en un proyecto GNU, me encontré con este pedazo de ensamblado en línea:Ayuda instrucción comprensión DIV en x86 ensamblador en línea

__asm__ (
    "divq %4" 
    : "=a" (q), "=d" (r) 
    : "0" (n0), "1" (n1), "rm" (d) 
); 

Aquí las variables q, r, n0, n1, y d son enteros de 64 bits. Conozco lo suficiente para saber qué hace esto, pero hay algunos detalles de los que no estoy seguro.

lo que entiendo:

Estamos dividiendo el contenido del registro RAX por d, colocando el cociente en q, y colocando el resto en r.

Lo que no entiendo

  1. ¿Por qué hay tres entradas aquí? Solo tenemos que ingresar un dividendo y un divisor, entonces, ¿qué uso podría haber para 3 entradas?
  2. No puedo decir cuál de las entradas es el dividendo. De manera más general, no veo nada realmente cargado en el registro RAX , entonces, ¿cómo sabe qué dividir por qué?
+1

+1 pregunta bien formateada. Me gustan las secciones "lo que entiendo" y "lo que no entiendo". –

Respuesta

4

En la especificación operandos de entrada:

: "0" (n0), "1" (n1), "rm" (d) 

registros "0" y "1" se ven obligados a rax y rdx debido a la especificación de salida:

: "=a" (q), "=d" (r) 

Y la familia div instrucción quiere el numerador en RDX:RAX. El divisor puede estar en un registro de propósito general (no utilizado, es decir, no RAX o RDX) o memoria, que se especifica mediante la restricción "rm". Registra RDX, RAX, y el operando del divisor compone las 3 entradas.

Así que esto terminará realizando la división: n1:n0/d donde n1:n0 es una cantidad cargada en rdx:rax.

+0

¿entiendo correctamente que esto se puede usar para dividir un entero de 128 bits por un entero de 64 bits? Sabía que esto era posible para la versión de registro de 32 bits, pero nunca pensé que también sería válida para la versión de 64 bits. –

+1

@Jens: eso es correcto.Pero recuerde que (como las operaciones de división de operandos más pequeños) si el cociente termina siendo demasiado grande para el registro de destino 'rax' obtendrá una excepción de división. –

+1

La forma más rápida de probar este caso es simplemente asegurarse de que 'rdx' sea menor que el divisor, en cuyo caso la división es segura. –

0

Al observar correctamente la familia div trabaja en los registros fijos a y d, rax y rdx para divq. El registro a obtiene su entrada de n0 que tiene un alias al 0º registro, es decir, a. n1 es una entrada ficticia con alias a d, probablemente solo para garantizar que este registro no se utilice para otros fines.

Cuestiones relacionadas