2010-01-22 5 views
32

Recuerdo haber visto una forma de utilizar el ensamblado extendido de gcc en línea para leer un valor de registro y almacenarlo en una variable de C. No puedo, por mi vida, recordar cómo formar la declaración de ASM. Cualquier ayuda es muy apreciada.Lectura de un valor de registro en una variable de C

+1

Y ¿cómo saber lo que está en EBX cuando el código C comienza a ejecutar? – florin

Respuesta

0

¿No es this lo que estás buscando?

Sintaxis:

asm ("fsinx %1,%0" : "=f" (result) : "f" (angle)); 
+0

Te das cuenta de que leerá una variable, calculará el seno y luego almacenará el resultado en una segunda variable. –

+0

@Samuel: ese fue un ejemplo de la sintaxis solamente. –

+0

Downvoted porque este es un ejemplo de cómo usar el ensamblaje extendido en GCC, no cómo obtener el valor de un registro específico en una variable específica, que es lo que solicitó OP. Al especificar los registros usando '% 0' y'% 1', GCC elegirá el registro en cuestión en su nombre. No hay garantía de que elija el registro que está esperando. –

5

no sé acerca de gcc, pero en VS esta es la forma:

int data = 0; 
__asm 
{ 
    mov ebx, 30 
    mov data, ebx 
} 
cout<<data; 

Esencialmente, se trasladaron los datos en ebx a la variable de data.

+0

x86-only, por supuesto. Los compiladores de Microsoft para x64 e Itanium no son compatibles con el ensamblaje en línea. – ephemient

+0

Creo que el conjunto se traducirá a mov ebx, 30 mov dword ptr [data], ebx – Sridarshan

+2

¿Por qué no simplemente 'mov data, 30'? – Houssni

17

Aquí es una manera de conseguir EBX:

int main() 
{ 
    int i; 
    asm("\t movl %%ebx,%0" : "=r"(i)); 
    return i + 1; 
} 

El resultado:

main: 
    subl $4, %esp 
    #APP 
      movl %ebx,%eax 
    #NO_APP 
    incl %eax 
    addl $4, %esp 
    ret 


Editar:

El "= r" (i) es una restricción de salida, diciéndole al compilador que la primera salida (% 0) es un registro que debe colocarse en la variable "i". En este nivel de optimización (-O5), la variable i nunca se almacena en la memoria, sino que se mantiene en el registro eax, que también es el registro del valor de retorno.

+1

Usaría la restricción '= rm' en lugar de' = r'. El optimizador del compilador intentará elegir la mejor ruta. Si el ensamblador en línea pasó a estar en una situación de falta de registro, '= r' puede obligarlo a generar un código inferior al óptimo. '= rm' le daría al optimizador la oportunidad de usar una referencia de memoria si resulta ser la mejor opción. En este ejemplo simple no será un problema, pero si el código está en una situación más compleja, entonces podría ser beneficioso dar opciones al compilador. –

2

Esto moverá el registro del puntero de la pila a la variable sp.

intptr_t sp; 
asm ("movl %%esp, %0" : "=r" (sp)); 

basta con sustituir 'esp' con el actual registro que está interesado en (pero asegúrese de no perder el %%) y 'sp' con su variable.

28

Yendo en una dirección diferente que otras respuestas hasta ahora, ya que no estoy seguro de lo que quieres.

GCC Manual § 5.40 Variables in Specified Registers

register int *foo asm ("a5"); 

Aquí a5 es el nombre del registro que se debe utilizar y hellip;

Naturalmente, el nombre del registro depende de la CPU, pero esto no es un problema, ya que los registros específicos son más útiles con las instrucciones explícitas del ensamblador (consulte Extended Asm). Ambas cosas generalmente requieren que usted condicionalice su programa de acuerdo con el tipo de CPU.

La definición de dicha variable de registro no reserva el registro; permanece disponible para otros usos en lugares donde el control de flujo determina que el valor de la variable no es en vivo.

GCC Manual § 3.18 Options for Code Generation Conventions

-ffixed-reg

Tratar el registro llamado reg como un registro fijo; el código generado nunca debería referirse a él (excepto tal vez como un puntero de pila, puntero de marco o en algún otro rol fijo).

Esto puede replicar la respuesta de Richard en una manera más sencilla,

int main() { 
    register int i asm("ebx"); 
    return i + 1; 
} 

aunque esto es más bien insignificante, ya que no tiene idea de lo que hay en el registro ebx.

Si la combinación de ambos, con la elaboración de este gcc -ffixed-ebx,

#include <stdio.h> 
register int counter asm("ebx"); 
void check(int n) { 
    if (!(n % 2 && n % 3 && n % 5)) counter++; 
} 
int main() { 
    int i; 
    counter = 0; 
    for (i = 1; i <= 100; i++) check(i); 
    printf("%d Hamming numbers between 1 and 100\n", counter); 
    return 0; 
} 

puede asegurarse de que una variable C utiliza siempre reside en un registro para el acceso rápido y tampoco obtendrá una paliza por otro código generado. (Convenientemente, ebx es destinatario de la llamada de guardado bajo x86 habituales convenciones de llamada, por lo que incluso si se clobbered mediante llamadas a otras funciones compiladas sin -ffixed-*, se debe conseguir restaurado también.)

Por otro lado, esto definitivamente no es portátil, y generalmente tampoco es un beneficio de rendimiento, ya que está restringiendo la libertad del compilador.

Cuestiones relacionadas