program make lets how create compiler c assembly compiler-construction x86

make - Conjunto X86: manejo de la instrucción IDIV



lets make an interpreter (2)

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

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

De acuerdo con http://www.cs.virginia.edu/~evans/cs216/guides/x86.html , idivq% rbx debería 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!


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

  • rax contiene los 64 bits más bajos del dividendo.
  • rdx contiene los 64 bits superiores del dividendo.

Cuando el cociente no se ajusta a 64 bits, arrojará esa excepción de coma flotante.

Entonces, lo que debes hacer es cero rdx :

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

Si está tratando con enteros con signo, también necesita firmar extender rax a rdx:rax , eso significa copiar el rax signo de rax a cada bit de rdx y se logra con cqo alias cqto:

movq %rdx, %rbx cqo idivq %rbx


La primera parte de la respuesta de Mysticials es correcta, idiv realiza 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 tiene variables firmadas , debe firmar extender rax a rdx:rax . Hay una instrucción específica para esto, cqto ( convertir 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