2011-11-25 13 views
8

Tengo dos macros, una está escrita en ensamblaje y la otra en C. La segunda macro usa la primera macro. Sin embargo, también quiero escribir la segunda macro en ensamblaje con volátil, para poder controlar su ubicación en el código. Y tenga en cuenta que tid es un valor de tiempo de ejecución, no una constante como n.Cómo escribo todo esto en el ensamblado

¿Cuál es una buena manera de escribir eso en el montaje? Además, ¿es posible controlar la colocación de un código C como ensamblado con volátiles?

#define SAVE_SP(n) __asm__ __volatile__ ("movq %rsp, msp"#n";" \ 
    "movq ts"#n", %rsp;" \ 
    ) 

#define SAVE_STACK_POINTER(tid) \ 
    switch(tid) \ 
    { \ 
     case 0: \ 
      SAVE_SP(0); \ 
      break; \ 
     case 1: \ 
      SAVE_SP(1); \ 
      break; \ 
     case 2: \ 
      SAVE_SP(2); \ 
      break; \ 
     case 3: \ 
      SAVE_SP(3); \ 
      break; \ 
    } 
+0

tid es un valor de tiempo de ejecución, no una constante como n. – MetallicPriest

+0

(No importa, eso no tenía sentido) –

+1

¿Es posible almacenar los valores 'tsp ' y 'msp ' en una matriz? –

Respuesta

6

Puede pedir gcc su idea de cómo escribir el código en ensamblador: gcc -S foo.c o gcc -Wa,-alh=foo.s -c foo.c. Es posible que desee mejorar los resultados, por supuesto. Necesitará hacer un poco de más: use %0 para el parámetro que pasa para el fragmento de ensamblaje y declare los registros que ha destruido. Busque Assembler Instructions with C Expression Operands in the GCC manual si no está familiarizado. Así es como podría verse esto (advertencia, mecanografiado directamente en el navegador y realmente no se conoce la sintaxis de ensamblaje x86).

#define SAVE_STACK_POINTER(tid) __asm__ __volatile__ (" \ 
     cmpl $0, %0         \n\ 
     je .SAVE_STACK_POINTER_0      \n\ 
     cmpl $1, %0         \n\ 
     je .SAVE_STACK_POINTER_1      \n\ 
     cmpl $2, %0         \n\ 
     je .SAVE_STACK_POINTER_2      \n\ 
     cmpl $3, %0         \n\ 
     je .SAVE_STACK_POINTER_3      \n\ 
     jmp .SAVE_STACK_POINTER_done     \n\ 
     .SAVE_STACK_POINTER_0:       \n\ 
     movq %%rsp, msp0        \n\ 
     movq ts0, %%rsp        \n\ 
     jmp SAVE_STACK_POINTER_done     \n\ 
     .SAVE_STACK_POINTER_1:       \n\ 
     movq %%rsp, msp1        \n\ 
     movq ts1, %%rsp        \n\ 
     jmp SAVE_STACK_POINTER_done     \n\ 
     .SAVE_STACK_POINTER_2:       \n\ 
     movq %%rsp, msp2        \n\ 
     movq ts2, %%rsp        \n\ 
     jmp SAVE_STACK_POINTER_done     \n\ 
     .SAVE_STACK_POINTER_3:       \n\ 
     movq %%rsp, msp3        \n\ 
     movq ts3, %%rsp        \n\ 
     .SAVE_STACK_POINTER_done:      \n\ 
    " : : "r" (tid)) 

Un método más elaborado que implicaría averiguar cuántos bytes cada movq - movq - bloque jmp toma (nota: no lo he comprobado, utilizo 8) y hacer un salto calculado en ella; algo así como

__asm__("      \n\ 
    movl %0, %eax    \n\ 
    mul 8, %eax     \n\ 
    add 4, %eax     \n\ 
    jmp . + %eax     \n\ 
    movq %%rsp, msp0    \n\ 
    movq ts0, %%rsp    \n\ 
    jmp .SAVE_STACK_POINTER_done \n\ 
    … 
    .SAVE_STACK_POINTER_done:  \n\ 
" : : "r" (tid) : "%eax") 
1

Suponiendo que está utilizando gcc, se podría tratar de utilizar una extensión de GNU para asignar el registro del puntero de pila a una variable C:

static register int stack_pointer0 asm("msp0"); 

void myfn() { 
    ...... 
    saved_stack_pointer = stack_pointer0; 
    ...... 
} 

bien, que probablemente no hacer lo que hizo tu código original (no estaba claro para mí cuál era el objetivo), pero deberías ser capaz de descubrir el resto de eso.

Creo que tengo la sintaxis correcta, pero me disculpo si no. Sé que esto funciona para los registros generales, y estoy bastante seguro de que GCC sabe qué hacer para los registros especiales, pero nunca se sabe.

Espero que ayude.

Cuestiones relacionadas