Supongamos que el disassembler me ayuda a ver una función foo que me interesa entender o usar en mi programa de C.

foo:
push   %ebp                    ; prologue
mov    %esp,%ebp               ; prologue
mov    0x8(%ebp),%eax          ; inst A
imul   0x8(%ebp),%eax          ; inst B
pop    %ebp                    ; epilogue
ret                            ; return

He idenfiticado las instrucciones que pertenecen al prólogo, i.e. preparación para el stack frame y epílogo, devolución del stack frame y return. Nota que ambas usan un parámetro que le llega a la función (%ebp + 0x8).

Si desearamos probar está función desde un programa en C, i.e. pasarle el parámetro y monitorear el resultado, podemos hacerlo usando comandos inline de assembly. En otras palabras, podemos insertar las instrucciones de assembly directamente en nuestro código de C y hacer que se ejecuten durante una función, usando los valores de nuestras variables de alto nivel.

A continuación una función main en lenguaje C que hace uso de las instrucciones que extraimos del código que estamos analizando.

int main() {

    int val1, val2;

    printf( "Enter an integer: " );
    scanf( "%d", &val1);

 __asm__ (
    "mov    %1,%%eax;"   // inst A 
    "imul %1, %%eax ;"   // inst B
    "mov %%eax, %0 ;"
    :"=r"(val2) 
    :"r"(val1) 
    :"%eax"
    );

    printf( "%d\n", val2 );

    return 0 ;
}

Observaciones:

  1. El bloque de instrucciones debe comenzar con __asm__( y terminar en );
  2. Para el compilador gcc las instrucciones de assembly deben estar en formato AT&T.
  3. Cada instrucción de assembly debe terminar en con semicolon (;) y estar entre comillas dobles.
  4. Se le debe añadir un % adicional a los nombres de los registros, e.g. usamos %%eax en vez de %eax.
  5. Las últimas tres líneas (las que comienzan con :) se utilizan para especificar en estricto orden: (1) los operandos de output, (2) operandos de input y (3) los registros alterados.

    • El operando de output de este ejemplo: "=r"(val2) significa que deseamos que el resultado de cierta(s) instrucciones de assembly se esciba en la variable val2. Siendo val2 la primera variable que mencionamos en esta sección su símbolo de referencia es %0.
    • El operando de input de este ejemplo: "r"(val1) significa que deseamos que algunas instrucciones de assembly lean el valor de val1. Siendo val1 la segunda variable que mencionamos en esta sección su símbolo de referencia será %1.
    • Estamos estableciendo que el registro "%eax" será moficiado por las instrucciones de assembly.
  6. Nota que la instrucción original mov 0x8(%ebp),%eax ahora dice "mov %1,%%eax;". El 0x8(%ebp) ha sido sustituido por un %1 que establece que lo que se moverá a %eax es el valor de la variable val1.

https://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C-C