Práctica de Laboratorio: Software Julián Viejo Cortés Jorge Juan Chico Marzo 2008
Índice de contenidos 1. Introducción...2 2. Ejemplo 1: Suma de números en ensamblador...2 3. Ejemplo 2: Suma de una lista de números en C...3 4. Ejemplo 3: Suma de dos números en C...4 5. Ejemplo 4: Hola Mundo en C...4 1
1 Introducción Esta práctica de laboratorio tiene como objetivo mostrar el funcionamiento del software a nivel de lenguaje ensamblador. Para ello, se han desarrollado una serie de ejemplos sobre un sistema Ubuntu/Linux, en concreto: Ejemplo 1: Suma de una lista de números en ensamblador. Ejemplo 2: Suma de una lista de números en C. Ejemplo 3: Suma de dos números en C. Ejemplo 4: "Hola mundo" en C. En todos los casos, se proporcionará a los alumnos el código fuente de los programas, de forma que el trabajo a realizar consiste en completar las diferentes fases. Para la realización de los ejemplos anteriores es necesario instalar una serie de herramientas que nos permitirán, entre otras tareas, compilar un programa escrito en C, generar el código ensamblador del programa, depurar dicho código usando un depurador, etc. En concreto, vamos a emplear los siguientes programas: yasm - Ensamblador para x86 y x86-64 gcc - Compilador de GNU ld - Enlazador de GNU kdbg - Depurador/debugger de KDE Además, es necesario utilizar un editor de texto plano (vi, nano, gedit, etc.) para la visualización del contenido de los archivos. En un sistema Ubuntu o similar (Debian, etc.) puede instalar estos programas escribiendo en un terminal el siguiente comando: $ sudo apt-get install build-essential yasm kdbg Aún así, es fácil adaptar estos ejemplos para ser usados con otras herramientas o sistema operativo. 2 Ejemplo 1: Suma de números en ensamblador En este primer ejemplo vamos a partir de un programa escrito en lenguaje ensamblador, teniendo los alumnos que realizar las siguientes tareas: 1. Analizar el código ensamblador proporcionado, usando un editor de texto: $ gedit suma.s 2. Ensamblar el programa (ejecutar en un terminal el siguiente comando): 2
Arquitectura de 32 bits $ yasm -f elf -g dwarf2 -o suma.o suma.s Arquitectura de 64 bits $ yasm -m amd64 -f elf -g dwarf2 -o suma.o suma.s 3. Enlazar el programa: $ ld -o suma suma.o 4. Realizar una ejecución del programa en el depurador : $ kdbg suma Abrir las ventanas de registros y memoria. Poner un punto de ruptura en la línea 21: movl $x, %ecx. Iniciar la ejecución. Ejecutar una instrucción (F10). Observar el valor de ecx y localizar este valor en la ventana de memoria. Observar que los valores almacenados corresponden a los indicados en el programa. Ejecutar paso a paso (F10) y observar cómo varían los registros y cómo se ejecuta el bucle hasta salir de él. Al finalizar, observar cómo se almacena el resultado en la dirección correspondiente. Nota: En las arquitecturas de 64 bits los registros toman nombres diferentes: rax, rbx, etc. 3 Ejemplo 2: Suma de una lista de números en C En este ejemplo, se parte de un programa escrito en lenguaje C y se pretende introducir en la lista de acciones del ejemplo anterior un nuevo proceso: el proceso de compilación. De esta forma, es necesario completar las siguientes tareas: 1. Analizar el código C proporcionado, usando un editor de texto: $ gedit suma1.c 2. Generar el código ensamblador y compararlo con el programa del ejemplo 1: $ gcc -S suma1.c 3. Compilar el programa (sólo compilar): $ gcc -c suma1.c 4. Compilar y enlazar : $ gcc -g -o suma1 suma1.c 3
5. Realizar una ejecución del programa en el depurador : $ kdbg suma1 Poner un punto de ruptura al comienzo de la función main. Iniciar la ejecución. Ejecutar una instrucción (F10). Ejecutar paso a paso (F10) y observar cómo varía el valor de las variables. Al final, observar el resultado en la ventana de salida. 4 Ejemplo 3: Suma de dos números en C Este ejemplo es análogo al anterior. Deben completarse las siguientes tareas: 1. Analizar el código C proporcionado, usando un editor de texto: $ gedit suma2.c 2. Generar el código ensamblador. Observar el código generado, localizar la función principal (main) e intentar reconocer las asignaciones de variables y operación de suma : $ gcc -S suma2.c 3. Compilar y enlazar: $ gcc -g -o suma2 suma2.c 6. Realizar una ejecución del programa en el depurador : $ kdbg suma2 Abrir la ventana de registros. Poner un punto de ruptura en la línea 3. Iniciar la ejecución. Ejecutar paso a paso (F10) y observar cómo varían los valores de las variables. Al finalizar, observar si algún registro tiene el mismo valor que la variable c. Este registro es el que se ha usado para hacer las operaciones. Cotejar esta observación con el código ensamblador generado anteriormente. 5 Ejemplo 4: Hola Mundo en C Este ejemplo es análogo a los dos anteriores. Deben completarse las siguientes tareas: 1. Analizar el código C proporcionado, usando un editor de texto: 4
$ gedit hola.c 2. Generar el código ensamblador. Observar el código generado, localizar la función principal (main) y observar la llamada a la función de la biblioteca "puts": $ gcc -S hola.c 3. Compilar y enlazar el programa: $ gcc -g -o hola hola.c 4. Ejecutar el programa en un terminal: $./hola 5. Realizar una ejecución del programa en el depurador : $ kdbg hola Poner un punto de ruptura en la línea 3. Iniciar la ejecución. Ejecutar paso a paso (F10) y observar la frase que aparece en la ventana de salida. 5