9
Sep
2012

Desde un High-Level Language a un archivo ejecutable

pasaje de high level language a archivo ejecutable assembler

Professional Assembly Language – Richard Blum (2005)

La figura describe el proceso que se desarrolla para traducir código escrito en un lenguaje de alto nivel (High-Level Language) a código de máquina (contenido en un archivo binario ejecutable).

El compilador cumple la función de transformar el código escrito en el lenguaje de alto nivel a código objeto. El código objeto es código de máquina que aún no se encuentra en condiciones de ser ejecutado, por las razones que veremos más adelante. Este código depende de la arquitectura de procesador para la cuál se compile (por ejemplo IA-32, ARM, etc.).

En lenguajes como C y C++, se suele generar un archivo de código objeto por cada archivo con código de alto nivel -contando los headers y su implementación en forma conjunta-.

La mayoría de los programas se componen de múltiples archivos con código de alto nivel. Existe una relación entre estos archivos para definir estructuras complejas, reutilización de componentes, separación de funcionalidades e interacciones.

El problema es el siguiente: el compilador tomó cada uno de estos archivos de código de alto nivel y dejó como resultado múltiples archivos de código objeto desconectados entre sí. Inclusive, tenemos en estos archivos de código objeto referencias a código objeto de bibliotecas externas al programa (por ejemplo system calls). Por lo tanto, si bien el código objeto es código de máquina, no está en condiciones de ser ejecutado porque no hay referencias que permitan seguir la traza de ejecución del programa completo. Es como si tuvieramos un reloj desarmado: tenemos cada una de las partes que lo componen pero si no las juntamos, no funciona.

La tabla de símbolos es el mapa para juntar estos archivos de código objeto. Cada archivo de código objeto expone una tabla de símbolos que funciona como catálogo de los elementos que contiene. Entre estos elementos se encuentran las funciones o métodos presentes, las invocaciones a métodos de otras bibliotecas, las variables globales, las secciones del archivo, etc.

sec@martin-laptop:~/workspace/Sec1/Release/src# objdump -t Sec1.o

Sec1.o:     file format elf32-i386

SYMBOL TABLE:
00000000 l    df *ABS*	00000000 Sec1.c
00000000 l    d  .text	00000000 .text
00000000 l    d  .data	00000000 .data
00000000 l    d  .bss	00000000 .bss
00000000 l    d  .rodata.str1.1	00000000 .rodata.str1.1
00000000 l    d  .note.GNU-stack	00000000 .note.GNU-stack
00000000 l    d  .comment	00000000 .comment
00000000 g     F .text	0000000a obtener_numero_fijo
00000010 g     F .text	0000001c main
00000000         *UND*	00000000 puts

Allí podemos ver una tabla de símbolos de un código objeto sencillo. No es el objetivo en este caso explicar cada elemento presente pero podemos identificar por ejemplo que hay un símbolo con identificador 00000000 g (00000000 global), que es una función (F), que se encuentra en la sección .text del archivo (donde se encuentran las instrucciones de código objeto), que tiene un size de 0000000a (10 bytes, a nivel de código objeto) y que se llama “obtener_numero_fijo”. O sea, en ese archivo de código objeto está esa función. Si otro archivo de código objeto realizara una invocación a esa función, sabemos que la encontramos allí.

El linker es el programa que se encarga de unir todas las piezas de código objeto para construir un único ejecutable. El linker utiliza para cumplir su objetivo la información de la tabla de símbolos de cada archivo de código objeto. No solamente se unen los código objeto del programa sino que se establecen las referencias a bibliotecas externas.

Existen dos posibilidades para referencias bibliotecas externas. Cuando la referencia es estática, la biblioteca externa se incluye dentro del binario. Cuando la referencia es dinámica, la biblioteca referenciada se carga en tiempo de ejecución. Esto último permite que múltiples programas compartan código que fue cargado una única vez en memoria (shared libraries).

Escribir un comentario