2012-04-27 20 views
21

Actualmente estoy escribiendo un compilador de C simple, que toma un archivo .c como entrada y genera código de ensamblado (sintaxis T de X86, AT &). Todo está bien, pero cuando trato de ejecutar una instrucción IDIVQ, obtengo una excepción de coma flotante. Aquí está mi entrada:Conjunto X86 - Manejo de la instrucción IDIV

int mymain(int x){ 
    int d; 
    int e; 
    d = 3; 
    e = 6/d; 
    return e; 
} 

Y aquí está mi código generado:

mymain: 
.LFB1: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    movq %rsp, %rbp 
    .cfi_offset 6, -16 
    .cfi_def_cfa_register 6 
    movq %rdi, -40(%rbp) 
    movq $3, -8(%rbp) 
    movq $6, %rax 
    movq -8(%rbp), %rdx 
    movq %rdx, %rbx 
    idivq %rbx 
    movq %rax, -16(%rbp) 
    movq -16(%rbp), %rax 
    leave 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE1: 
    .size mymain, .-mymain 

Según http://www.cs.virginia.edu/~evans/cs216/guides/x86.html, idivq% RBX debe producir 6/d (el cociente) en % rax. Pero recibo una excepción de coma flotante, y parece que no puedo encontrar el problema.

¡Cualquier ayuda será muy apreciada!

+0

No relacionado con esta pregunta, pero ¿debería estar haciendo 'movq% rdi, -40 (% rbp)' sin haber ajustado el registro 'esp'? ¿O está bien debido a la 'zona roja' x64? –

Respuesta

23

El La primera parte de la respuesta de Mysticials es correcta, idiv tiene una división de 128/64 bits, por lo que el valor de rdx, que contiene los 64 bits superiores del dividendo, no debe contener un valor aleatorio. Pero una extensión cero es el camino equivocado por recorrer.

Como usted tiene firmados las variables, es necesario extender signorax a rdx:rax. Hay una instrucción específica para esto, cqto (convert quad a oct) en AT & T y cqo en sintaxis Intel. Las versiones más recientes de AFAIK de gas aceptan ambos nombres.

movq %rdx, %rbx 
cqto     # sign extend rax to rdx:rax 
idivq %rbx 
+0

+1 Es curioso cómo pasé por alto la parte firmada. – Mysticial

+0

De hecho, estaba ejecutando mis pruebas y encontré un error al manejar los valores firmados. No he visto esta instrucción antes, pero parece resolver el problema ahora. ¡Gracias! –

+0

@Mysticial sucede incluso con los mejores :-) – hirschhornsalz

11

La instrucción idivq divide un entero de 128 bits (rdx:rax) por el operando.

  • rax contiene los 64 bits inferiores del dividendo.
  • rdx contiene los 64 bits superiores del dividendo.

Cuando el cociente no cabe en 64 bits, arrojará esa excepción de coma flotante.

Así que lo que hay que hacer es cero rdx:

movq %rdx, %rbx 
xorq %rdx, %rdx # zero "rdx" 
idivq %rbx 

Si usted está tratando con enteros con signo, también hay que firmar extender rax a rdx:rax, que significa copiar el bit rax signo a cada bit de rdx y se lleva a cabo con CQO alias cqto:

movq %rdx, %rbx 
cqo 
idivq %rbx 
+5

Zeroing rdx funcionará con números positivos, pero en caso de rax negativo probablemente se necesita rdx = -1 ... ¿No es así? – marekb

+5

Creo que marekb tiene razón, ¿no debería la instrucción 'xorq' ser una instrucción' cqo' para firmar extender 'rax' en' rdx: rax'? –

+0

En este caso, con mecanografía firmada: creo que sí. –

Cuestiones relacionadas