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:
- El bloque de instrucciones debe comenzar con
__asm__(
y terminar en);
- Para el compilador
gcc
las instrucciones de assembly deben estar en formato AT&T. - Cada instrucción de assembly debe terminar en con semicolon (
;
) y estar entre comillas dobles. - Se le debe añadir un
%
adicional a los nombres de los registros, e.g. usamos%%eax
en vez de%eax
. -
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 variableval2
. Siendoval2
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 deval1
. Siendoval1
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.
- El operando de output de este ejemplo:
-
Nota que la instrucción original
mov 0x8(%ebp),%eax
ahora dice"mov %1,%%eax;"
. El0x8(%ebp)
ha sido sustituido por un%1
que establece que lo que se moverá a%eax
es el valor de la variableval1
.
https://www.codeproject.com/Articles/15971/Using-Inline-Assembly-in-C-C