Arquitectura y Tecnologı́a de Ordenadores Personales (IS37 - II37) Ingenierı́a Técnica en Informática de Sistemas - Ingenierı́a Informática Práctica 3. Paso de parámetros entre C y ensamblador en Linux. 1. Objetivos Con el desarrollo de esta práctica se podrá analizar el formato de los ficheros en lenguaje ensamblador, su comunicación con programas en C y el procedimiento para mezclar ficheros en ambos lenguajes. 2. Introducción Si bien la programación en ensamblador puede resultar tediosa y compleja por tratarse de un lenguaje de muy bajo nivel, puede ser útil e incluso necesaria para acelerar ciertas funciones, para tener un control riguroso sobre el código que queremos ejecutar, para acceder a recursos del ordenador a muy bajo nivel o por el mero hecho de estudiar el código ensamblador en sı́. Como el desarrollo de aplicaciones enteramente en ensamblador no suele ser necesario, esta práctica se va a centrar en la inclusión de subrutinas en ensamblador llamadas desde programas en C. Por ello el paso de parámetros y la recuperación de los resultados devueltos por las funciones son dos de los aspectos más importantes a tener en cuenta. 3. Uso del compilador gcc Para incluir ficheros en ensamblador al compilar nuestros programas, basta con indicar el nombre del fichero con la extensión .s o .S en la lı́nea de comandos. Por ejemplo, para ejecutar la prueba de mistrlen se utilizarı́a la orden gcc -o mistrlen mistrlen.c mistrlen.s entonces el compilador invoca automáticamente al ensamblador as para generar el módulo objeto correspondiente que luego es enlazado de la forma habitual para generar el ejecutable. Para generar código en ensamblador en lugar de un ejecutable –más bien, de un fichero objeto pues el ejecutable incluye el código de librerı́as que no aparecen en el ensamblador generado por el compilador– se invoca el compilador con la opción -S. El código generado depende del nivel de optimización elegido, que se indica con la opción -On donde n es el nivel de optimización. Por ejemplo gcc -S -O2 programa.c 4. Paso de parámetros en C Cada lenguaje de programación tiene sus propios mecanismos para el paso de parámetros entre subrutinas, y para la devolución de valores desde éstas. En el lenguaje C y utilizando la pila para el paso de parámetros, una función de la forma funcion(par1, par2, par3 ... parn) apiları́a en primer lugar el parámtro n, luego el n-1, etcétera, y por último el parámetro 1 antes de realizar la llamada a la subrutina. Una vez dentro de la subrutina, si se sigue el procedimiento habitual de apilar el frame pointer ebp y luego copiar en él el valor del puntero a pila –mediante movl esp, ebp– se tiene que durante la ejecución de la subrutina el estado de la pila es el siguiente: parámetro n parámetro n - 1 ... parámetro 3 parámetro 2 parámetro 1 dir. retorno ebp anterior ← ← ← ← ← ← ← 4n+4(ebp) 4(n-1)+4(ebp) ... 16(ebp) 12(ebp) 8(ebp) 4(ebp) 0(ebp) si el tamaño de los parámetros es de 32 bits. Además, en direcciones por debajo de ebp se crean los almacenamientos para las variables locales de la subrutina, que comenzarı́an en -4(ebp) hacia direcciones decrecientes. En el caso de que la rutina devuelva un valor, éste se pasará en el registro eax. Todos los demás registros de la arquitectura se deben preservar si van a ser modificados, apilándolos antes de ser usados y desapilándolos al final. 5. Trabajo a desarrollar 1. Estudiad los ejemplos de programación en ensamblador disponibles en la página web, prestando especial atención a la estructura de la pila, el paso de parámetros y la programación en ensamblador. Compilad y ejecutad los ejemplos mistrlen e itohex. En la página de la asignatura se pueden encontrar los distintos manuales del ensamblador de la arquitectura. 2. Observar el código ensamblador generado por el compilador gcc con la opción -S y distintos niveles de optimización en los programas de prueba anteriores. 3. Estudiad los ejemplos que usan las extensiones MMX y SSE mediante los ejemplos itommhex, itommhex2p y las distintas versiones de ssefiltro –este último tarda casi un minuto en ejecutarse. 4. Compilad y probad el programa registros. Estudiad, consultando los manuales de la arquitectura, los valores de los registros, en especial los de segmento y flags. Comprobad cómo dos procesos ejecutándose a la vez lo hacen en las mismas direcciones lógicas. 5. Realizad un pequeño programa que reciba dos parámetros enteros y devuelva un valor del mismo tipo, calculado como se desee en función de los parámetros.