2011-05-02 26 views
6

Actualmente estoy tratando de llamar a una función C genérica desde el ensamblaje en línea de GCC (mala idea, lo sé, pero estoy aburrido hoy ...).Ensamblaje en línea de GCC - Mover float a XMM0 antes de llamar a

Mi sistema operativo es Mac OS X, 64bits, por lo que la convención de llamada es System V, es decir, argumentos 0-6 se pasan a través de los rdi, rsi, rdx, rcx, r8 y r9 registros. Otros argumentos son empujados a la pila.

Conozco la firma de la función, así que puedo adivinar el tipo de devolución y el tipo de los argumentos. Con esa información, puedo colocar los argumentos en los registros correctos.

Todo funciona muy bien con tipos enteros, pero tengo un problema con los valores de coma flotante.

Los valores de punto flotante se deben pasar a través de los registros xmm0 - xmm7.

El problema es básicamente el siguiente. Tengo una variable C del tipo float. Necesito mover esa variable en, digamos, el registro xmm0, usando el ensamblado en línea de GCC.

imaginar el siguiente código:

#include <stdio.h> 

void foo(int x) 
{ 
    printf("X: %i\n", x); 
} 

int main(void) 
{ 
    int x = 42; 

    __asm__ 
    (
     "mov %[x], %%rdi;" 
     "call _foo;" 
     : 
     : [ x ] "m" (x) 
    ); 

    return 0; 
} 

La función foo se llama, con 42 como parámetro. Funciona ...

Ahora intento lo mismo con un argumento flotante. Solo tengo que usar movss en lugar de mov, y funciona.

El problema viene cuando intento llamar a dos funciones:

#include <stdio.h> 

void foo(int a) 
{ 
    printf("A: %i\n", a); 
} 

void bar(float b) 
{ 
    printf("B: %f\n", b); 
} 

int main(void) 
{ 
    int a = 42; 
    float b = 42; 

    __asm__ 
    (
     "mov %[a], %%rdi;" 
     "call _foo;" 
     "movss %[b], %%xmm0;" 
     "call _bar;" 
     : 
     : [ a ] "m" (a), 
      [ b ] "m" (b) 
    ); 

    return 0; 
} 

La función de tomar el argumento de flotación recibir 0. No entiendo por qué. que no toque la pila, así que no hay que hacer la limpieza ...

Si llamo a las funciones directamente desde C, GCC produce lo siguiente:

movl $42, -4(%rbp) 
movl $0x42280000, %eax 
movl %eax, -8(%rbp) 
movl -4(%rbp), %edi 
call _foo 
movss -8(%rbp), %xmm0 
call _bar 

No entiendo la diferencia ... Cualquier ayuda será muy apreciada:)

tenga un buen día, todo

EDITAR

a lo solicitado, aquí está la salida ASM cuando se utiliza ensamblado en línea:

movl $42, -4(%rbp) 
movl $0x42280000, %eax 
movl %eax, -8(%rbp) 
mov -4(%rbp), %rdi; 
call _foo; 
movl -8(%rbp), %eax; 
movl %eax, -4(%rbp); 
movss -4(%rbp), %xmm0; 
call _bar; 

Edit2

Conforme a lo solicitado, aquí está la salida GDB:

0x100000e9e <main+4>: movl $0x2a,-0x4(%rbp) 
0x100000ea5 <main+11>: mov $0x42280000,%eax 
0x100000eaa <main+16>: mov %eax,-0x8(%rbp) 
0x100000ead <main+19>: mov -0x4(%rbp),%rdi 
0x100000eb1 <main+23>: callq 0x100000e54 <foo> 
0x100000eb6 <main+28>: movss -0x8(%rbp),%xmm0 
0x100000ebb <main+33>: callq 0x100000e75 <bar> 
+0

Publique el asm generado por 'gcc' (use' gcc -S '). –

+0

La parte importante ya está en la parte inferior de la publicación. Dime si necesitas algún otro código ...:) Gracias – Macmade

+0

Pensé que el ensamblaje en la parte inferior de la publicación es lo que generó gcc al usar C para llamar a 'foo()' y 'bar()'. Lo que me gustaría ver es lo que genera gcc cuando usa el ensamblado en línea para llamar a esas funciones. –

Respuesta

7

Me tomó un tiempo, pero me descubrió esto. En la salida que usa el ensamblaje en línea, gcc usa compensaciones negativas de rbp para almacenar los valores.Sin embargo, dado que no conoce las llamadas de función en el ensamblaje en línea, no cree que llame a ninguna función. Por lo tanto, pone las variables en la zona roja y no cambia rsp para dejar espacio para las variables. Cuando llama a foo, la dirección de retorno se envía a la pila, sobrescribiendo las variables almacenadas y proporcionándole una variable incorrecta.

Si, en cualquier punto de la función principal fuera del ensamblado, llamó a una función, entonces gcc cambiaría la pila para conservar las variables. Por ejemplo, si agrega foo(-1); a la parte superior de la página principal, funcionaría.

+1

Buena captura: supongo que tiene algo que ver con la zona roja, pero no con suficiente experiencia con el ensamblaje x64 y sin una cama de prueba para decirlo con certeza (o para decir exactamente qué). –

+0

Wow ... ¡Gracias por la respuesta, es perfectamente correcto! – Macmade

+1

Me derrotaron cinco minutos :(Solo tienes que mirar al principio de main para ver que rsp == rbp y así los argumentos se sobrescriben con la dirección de devolución. – hirschhornsalz

Cuestiones relacionadas