You are on page 1of 5

Diseccin de Hola Mundo

Proceso de creacin de ejecutables en un Sistema Operativo


Material complementario para las asignaturas de Programacin I y Sistemas
Operativos
Preparado por Gabriel Astudillo Muoz
Escuela de Ingeniera Civil Informtica
Universidad de Valparaso

1 Resumen
Este documento tiene como objetivo mostrar la interaccin entre los distintos softwares que permiten
generar un ejecutable y el Sistema Operativo. Para realizar esto, se utiliza la herramienta GCC [2] y el
sistema operativo Linux/Debian 2.6

2 Proceso de Compilacin
La compilacin de un programa genera cierta cantidad de archivos [1], los que, es su mayora, no son de
importancia para el programador que est enfocado en generar soluciones en lenguajes de alto nivel [3].
Ejemplos de estos archivos intermedios que pasan desapercibidos son los cdigos assembler (.s) y los
cdigo objeto (.o). El proceso completo de compilacin, se muestra en la figura 1.
Cdigo Cdigo Cdigo
Fuente Fuente Fuente
.c .c .c

Compilador Bibliotecas Bibliotecas Bibliotecas


.h .h .h

Cdigo Cdigo Cdigo


Assembler Assembler Assembler
.s .s .s

Ensamblador
Cdigo Cdigo Cdigo
Objetvo Objetvo Objetvo
.o .o .o

Libreras
Linker del
sistema
(enlazador)

Ejecutable

Figura 1

3 Compilador GCC
GCC es el Gnu C Collection [2]. Posee un conjunto de compiladores, entre los que se encuentran C, C++,
Java, entre otros. El comando gcc es un programa que llama a los distintos programas que permiten
generar el ejecutable deseado.
3.1 Proceso de Compilacin
El proceso de compilacin en C consiste en cuatro etapas: Preprocesado, Compilacin, Ensamblado y
Enlazado.
En el preprocesado, el preprocesador (cpp1) examina los archivos fuente en busca de declaraciones que
comiencen por el smbolo #. Cuando son de tipo #include <archivo>, localiza el archivo indicado
y lo aade al programa. Luego busca y sustituye todas las macros (#define). Una vez realizadas todas
las sustituciones, gcc invoca al compilador.
En la compilacin, el compilador (cc1) toma el cdigo generado por el preprocesador y lo convierte en
cdigo en lenguaje ensamblador.
En el ensamblado, el ensamblador (as) toma el cdigo anterior y lo transforma en cdigo objeto.

1
El preprocesador es llamado a travs de la opcin -E de gcc.
Finalmente, en el enlazado, el programa ld(1)2 lo enlaza a todas las libreras necesarias para que el
cdigo objetivo se puede ejecutar en el sistema operativo. En esta etapa, el linker (ld) es llamado a travs
de otro programa de apoyo (wrapper), llamado collect23.
Prepocesador (cpp)
Busca declaraciones (#) .h
#include : incluye archivo
(1) #define: sustituye Macros

Cdigo
gcc
Fuente Cdigo Fuente
Sin declaraciones #
.i
(2)
.c .h
Compilador (cc1)

Cdigo Assembler
.S

(3)
Ensamblador (as)

Cdigo Objeto
.o

(4)
libreras
Linker (collect1) externas y de
sistema

Ejecutable

Figura 2 Proceso de generacin de un ejecutable en C.

3.2 Detalle del proceso de Compilacin


Para ver en detalle el proceso de compilacin, se tomar el cdigo fuente de la Figura 3.

holaMundo.c

#include <stdio.h>
#include "global.h"
global.h
main(){
printf("Hola Mundo, %d\n", INI);
} #define INI 2013

Figura 3 Figura 4

Para compilar el cdigo fuente mencionado, se utilizar el modo verbose (-v). Una vez finalizado el
proceso, se puede utilizar el ejecutable generado. Los archivos intermedio son eliminados.
$ gcc -v holaMundo.c -o holaMundo
Using built-in specs.
[...]
gcc version 4.9.2 (Debian 4.9.2-10)
COLLECT_GCC_OPTIONS='-v' '-o' 'holamundo' '-mtune=generic' '-march=i586'
/usr/lib/gcc/i586-linux-gnu/4.9/cc1 -quiet -v -imultiarch i386-linux-gnu holamundo.c -quiet -
dumpbase holamundo.c -mtune=generic -march=i586 -auxbase holamundo -version -o /tmp/ccMxaSyP.s
[...]
COLLECT_GCC_OPTIONS='-v' '-o' 'holamundo' '-mtune=generic' '-march=i586'
as -v --32 -o /tmp/cciMVjMx.o /tmp/ccMxaSyP.s
GNU assembler version 2.25 (i586-linux-gnu) using BFD version (GNU Binutils for Debian) 2.25
COMPILER_PATH=/usr/lib/gcc/i586-linux-gnu/4.9/:/usr/lib/gcc/i586-linux-
gnu/4.9/:/usr/lib/gcc/i586-linux-gnu/:/usr/lib/gcc/i586-linux-gnu/4.9/:/usr/lib/gcc/i586-linux-
gnu/
LIBRARY_PATH=/usr/lib/gcc/i586-linux-gnu/4.9/:/usr/lib/gcc/i586-linux-gnu/4.9/../../../i386-
linux-gnu/:/usr/lib/gcc/i586-linux-gnu/4.9/../../../../lib/:/lib/i386-linux-
gnu/:/lib/../lib/:/usr/lib/i386-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/i586-linux-
gnu/4.9/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'holamundo' '-mtune=generic' '-march=i586'
/usr/lib/gcc/i586-linux-gnu/4.9/collect2 -plugin /usr/lib/gcc/i586-linux-
gnu/4.9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/i586-linux-gnu/4.9/lto-wrapper -plugin-opt=-
fresolution=/tmp/ccgDJsce.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -
plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --
sysroot=/ --build-id --eh-frame-hdr -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-
linux.so.2 -o holamundo /usr/lib/gcc/i586-linux-gnu/4.9/../../../i386-linux-gnu/crt1.o
/usr/lib/gcc/i586-linux-gnu/4.9/../../../i386-linux-gnu/crti.o /usr/lib/gcc/i586-linux-
gnu/4.9/crtbegin.o -L/usr/lib/gcc/i586-linux-gnu/4.9 -L/usr/lib/gcc/i586-linux-
gnu/4.9/../../../i386-linux-gnu -L/usr/lib/gcc/i586-linux-gnu/4.9/../../../../lib -L/lib/i386-
linux-gnu -L/lib/../lib -L/usr/lib/i386-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/i586-linux-

2
El linker ld es una herramienta del Sistema Operativo.
3
El programa collect2 es una herramienta provista por gcc.
gnu/4.9/../../.. /tmp/cciMVjMx.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -
lgcc_s --no-as-needed /usr/lib/gcc/i586-linux-gnu/4.9/crtend.o /usr/lib/gcc/i586-linux-
gnu/4.9/../../../i386-linux-gnu/crtn.o/usr/lib/gcc/i486-linux-gnu/4.4.5/crtend.o
/usr/lib/gcc/i486-linux-gnu/4.4.5/../../../../lib/crtn.o

Figura 5 Visualizacin de los distinos pasos en la generacin de un ejecutable.

Para visualizar los archivos intermedios, hay que compilar con la opcin save-temps, tal como se
muestra en la figura 6.
% gcc -save-temps -o holaMundo holaMundo.c
% ls -l
total 80
-rw-r--r-- 1 user staff 16 Mar 8 12:44 global.h
-rwxr-xr-x 1 user staff 8756 Mar 8 13:33 holaMundo
-rw-r--r-- 1 user staff 84 Mar 8 12:46 holaMundo.c
-rw-r--r-- 1 user staff 10601 Mar 8 13:33 holaMundo.i
-rw-r--r-- 1 user staff 740 Mar 8 13:33 holaMundo.o
-rw-r--r-- 1 user staff 1271 Mar 8 13:33 holaMundo.s
%

Figura 6

Tal como se menciona en la seccin anterior, revisando las ltimas lneas el archivo holamundo.i
(ver figura 7), se puede observar que es ste archivo el que contiene el cdigo fuente que se compila.
$ tail holaMundo.i
[...]
extern void funlockfile (FILE *__stream) __attribute__
((__nothrow__));
# 916 "/usr/include/stdio.h" 3 4

# 2 "holaMundo.c" 2
# 1 "global.h" 1
# 3 "holaMundo.c" 2

main(){
printf("Hola Mundo, %d\n", 2013);
exit(0);
}
$

Figura 7

As mismo, se puede ver el contenido del archivo holaMundo.s, que contiene el cdigo assembler
del programa. El cdigo assembler se visualiza en la figura 8.
$ more holaMundo.s
.file "holaMundo.c"
.section .rodata
.LC0:
.string "Hola Mundo: %d\n"
.text
.globl main
.type main, @function
main:
.LFB2:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
subl $8, %esp
pushl $2013
pushl $.LC0
call printf
addl $16, %esp
subl $12, %esp
pushl $0
call exit
.LFE2:
.size main, .-main
.ident "GCC: (Debian 4.9.2-10) 4.9.2"
.section .note.GNU-stack,"",@progbits

Figura 8 Cdigo assembler del programa holaMundo.c


Tal como se puede observar en la Figura 8, el programa llama a las funciones (en realidad son
SYSCALLS [4] o llamadas a sistema o llamadas al kernel) printf y exit. stas no estn
definidas en el cdigo del programa. Debido a esto, es que en el proceso de ligado, el linker debe asociar
dichas llamadas al cdigo de la librera respectiva.

4 El proceso de creacin de un ejecutable paso a paso


Para obtener en forma manual los archivos de la
Preprocesamiento: gcc -E holaMundo.c -o holaMundo.i
Compilacin: gcc -S holamundo.i -o holamundo.s
Ensamblado: as holaMundo.s o holaMundo.o
Ligado: ld o su herramienta de apoyo (wrapper) collect2 . Las libreras y rutas mnimas para
una correcta creacin del ejecutable se muestra en la Figura 9. El resultado de este comando es el
mismo que se obtiene a travs del wrapper collect2, mostrado en la Figura 5.
ld -dynamic-linker /lib/ld-linux.so.2 \
/usr/lib/i386-linux-gnu/crt1.o \
/usr/lib/i386-linux-gnu/crti.o \
-L/usr/lib/i386-linux-gnu -lc \
/usr/lib/i386-linux-gnu/crtn.o \
holamundo.o -o holamundo
Figura 9

Debido a que un ejecutable requiere muchas funciones externas del sistema y de libreras de C,
es preferible utilizar el comando gcc:
$ gcc holamundo.o o holamundo.
Observacin:
gcc -E llama internamente al preprocesador cpp.
gcc -S llama internamente al compilador cc1.
Las herramientas cc1 y collect2 se encuentran en el directorio
/usr/lib/gcc/i586-linux-gnu/<version>/ .

5 Creacin de un ejecutable sin las libreras de C


Partiendo del siguiente cdigo (suponiendo que est almacenado en el archivo holamundo.c):
int main(){
puts("Hola Mundo!");
return(0);
}
, se puede obtener el cdigo assembler a travs de gcc S holamundo.c -o holamundo.s:
.file "holamundo.c"
.section .rodata
.LC0:
.string "Hola Mundo!"
.text
.globl main
.type main, @function
main:
.LFB0:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
subl $12, %esp
pushl $.LC0
call puts
addl $16, %esp
movl $0, %eax
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret
.LFE0:
.size main, .-main
.ident "GCC: (Debian 4.9.2-10) 4.9.2"
.section .note.GNU-stack,"",@progbits
Necesariamente, este cdigo assembler generar un cdigo objeto que debe ser ligado con las libreras de
la libc. El siguiente cdigo muestra una solucin similar, pero que no necesita ser ligado con la libc,
ya que utiliza directamente las funciones del kernel a travs de llamadas a sistema (SYSCALLS)
.text
.globl _start

_start:
movl $len,%edx # third argument: message length
movl $msg,%ecx # second argument:
# pointer to message to write
movl $1,%ebx # first argument: file handle (stdout)
movl $4,%eax # system call number (sys_write)
int $0x80 # call kernel

movl $0, %ebx #exit code


movl $1, %eax #system call number (sys_exit)
int $0x80 #call kernel

msg:
.ascii "Hello, world\n"
len = . - msg
Para crear el ejecutable, se debe ensamblar y ligar de la siguiente manera:
$ as holamundo.s -o holamundo.o
$ ld -s holamundo.o -o holamundo
$ ./holamundo

6 Bibliografa
[1] Operating system concepts, Abraham Silberschatz, Peter Baer Galvin, Greg Gagne, 6 ed.
[2] http://gcc.gnu.org
[3] Estructura y diseo de computadores, David A. Patterson, John L. Hennessy, 2004.
[4] Programacin Avanzada en Unix, Jos Canosa, Mc Graw Hill, 2000.