Procesadores de 32 bits Integración de C y Assembler Formas de realizar llamadas Uso de Call y Ret Uso de Enter y Leave en conjunto con Call y Ret Preparación del stack Establecer un segmento para stack. Cargar el selecto de segmento en SS usando las instrucciones MOV, POP, o LSS. Cargar el puntero al stack en ESP usando MOV, POP, o LSS. La instrucción LSS puede utilizarse para cargar SS y ESP en una sóla operación. Considerar la alineación del stack. Funciones en Assembler invocadas desde C Se utilizan a las instrucciones Enter y Leave. Estas adecuan el stack para la ejecución de la retina en assembler. El resultado de la función se obtiene en EAX Ejemplo: Suma.c extern int suma_asm(int a, int b); #include <unistd.h> #include <stdio.h> int main (void) { int r=0; int s=4; int t=5; printf("Calculando...\n"); r=suma_asm(s,t); printf("El resultado es: %d\n",r); return(0) } extern int suma_asm(int a, int b); La sentencia extern le indica al compilador que la llamada a la función suma_asm se obtendrá de otro código objeto. La función devolverá una entero, EAX. La función necesita dos enteros como argumentos, estos de almacenarán en la pila. suma_asm.asm Hace la conexión con extern GLOBAL suma_asm %define sumando1 ebp+8 %define sumando2 ebp+12 suma_asm: Etiqueta que marca el comienzo enter 8,0 mov eax,[sumando1] Adecua el stack, ebp y mov ebx,[sumando2] reserva dos dobles words Para uso interno de la rutina add eax,ebx leave Restablece el stack y ebp, ret a partir del valor de ebp Instrucción ENTER n,0 Push EBP EBP ← ESP ESP ← ESP - n Instrucción LEAVE ESP ← EBP Pop EBP Compilado de C y Assembler Assembler: nasm -f elf suma_asm.asm -l suma_asm.lst C: gcc -c suma.c Ambos generan código objeto, que se conjuga con: gcc -g suma.o suma_asm.o -o suma El archivo Makefile $ cat Makefile suma: suma.obj suma_asm.obj gcc -ggdb suma.o suma_asm.o -o suma suma.obj: suma.c gcc -ggdb -c suma.c suma_asm.obj: suma_asm.asm nasm -f elf -g suma_asm.asm -l suma_asm.lst Invocando al Makefile Se lo invoca con el comando make y una etiqueta. En ausencia de etiqueta tomará la primera que encuentra en el Makefile, en nuestro caso suma: Luego de la etiqueta van los requisitos para ejecutar la etiqueta En el caso de suma: requiere de las etiquetas suma.obj y suma_asm.obj Sintaxis de Makefile A su vez la etiqueta suma.obj requiere del archivo suma.c Si lo tiene ejecuta lo que está debajo de la etiqueta, estas líneas deben comenzar con tabulador, en este caso gcc -ggdb -c suma.c La opción -c de gcc genera sólo código objeto de nombre suma.o La opción -ggdb generación información para el gdb Sintaxis de Makefile A su vez la etiqueta suma_asm.obj requiere del archivo suma_asm.asm Si lo tiene ejecuta lo que está debajo de la etiqueta, estas líneas deben comenzar con tabulador, en este caso: nasm -f elf -g suma_asm.asm -l suma_asm.lst La opción -f de nasm genera sólo código objeto de nombre suma_asm.obj en formato elf La opción -g genera información para el gdb Sintaxis de Makefile Ahora que la etiqueta suma: tiene sus requisitos, se ejecutará: gcc -ggdb suma.o suma_asm.o -o suma Vincula ambos objetos manteniendo la información para el gdb Ejecutando make $ make gcc -c suma.c nasm -f elf suma_asm.asm -l suma_asm.lst gcc -g suma.o suma_asm.o -o suma (gdb) disas main 0x080483f4 <main+0>: push %ebp 0x080483f5 <main+1>: mov %esp,%ebp 0x080483f7 <main+3>: and $0xfffffff0,%esp 0x080483fa <main+6>: sub $0x20,%esp Salva ebp, lo alinea con esp con esto queda listo para la instrucción LEAVE Alinea esp a 16 Deja espacio para variables locales y parámetros (gdb) disas main (2) 0x080483fd <main+9>: 0x08048405 <main+17>: movl $0x14,0x18(%esp) 0x0804840d <main+25>: movl $0xb,0x1c(%esp) int r=0; int s=20; int t=11; movl $0x0,0x14(%esp) (gdb) disas main (3) 0x08048415 <main+33>: movl $0x8048530,(%esp) 0x0804841c <main+40>: call 0x8048330 <puts@plt> printf("Calculando...\n"); (gdb) disas main (4) 0x08048421 <main+45>: mov 0x1c(%esp),%eax 0x08048425 <main+49>: mov %eax,0x4(%esp) 0x08048429 <main+53>: mov 0x18(%esp),%eax 0x0804842d <main+57>: mov %eax,(%esp) 0x08048430 <main+60>: call 0x8048460 <suma_asm> 0x08048435 <main+65>: mov r=suma_asm(s,t); %eax,0x14(%esp) (gdb) disas main (5) 0x08048439 <main+69>: mov $0x804853e,%eax 0x0804843e <main+74>: mov 0x14(%esp),%edx 0x08048442 <main+78>: mov %edx,0x4(%esp) 0x08048446 <main+82>: mov %eax,(%esp) 0x08048449 <main+85>: call 0x8048320 <printf@plt> printf("El resultado es: %d\n",r); (gdb) disas main (6) 0x0804844e <main+90>: mov 0x08048453 <main+95>: leave 0x08048454 <main+96>: ret return(0) $0x0,%eax Referencias Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 1: Basic Architecture, Capítulo 6 http://www.nasm.us/doc/ http://gcc.gnu.org/onlinedocs/ Paquetes recomendados: gcc gcc-doc nasm make make-doc gdb ddd