Publi

Compilando y linkando a mano con GCC

GCC compila y linka automáticamente, nos devuelve un ejecutable directamente:

$ gcc -o ejecutable fuente.c

pero en realidad, aparte de pre-procesar y compilar, enlaza algunas bibliotecas del sistema para que nuestro ejecutable funcione bien. Sólo por jugar un poco, veamos, más o menos (depende del sistema) cómo obtener el ejecutable a mano, es decir, compilamos por un lado, y linkamos por otro.

Primero, creamos un programa sencillo, un hello.c que contenga lo siguiente:

1
2
3
4
5
6
7
8
#include <stdio.h>

int main(int argc, char *argv[])
{
   printf("Hola mundo!!\n");

   return 0;
}

Ahora obtenemos el fichero objeto, nuestro código compilado de la siguiente manera:

$ gcc -c hello.c

Veremos que se ha generado el fichero hello.o ; éste fichero aún no lo podremos ejecutar, ya que no tenemos las librerías del sistema necesarias para ello.

Ahora obtendremos el fichero ejecutable con el linkador:

ld -o hello -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc/i686-pc-linux-gnu/4.2.3/crtbegin.o -L/usr/lib/gcc/i686-pc-linux-gnu/4.2.3 hello.o /usr/lib/gcc/i686-pc-linux-gnu/4.2.3/crtend.o /usr/lib/crtn.o -lc

Debemos cambiar /usr/lib/gcc/i686-pc-linux-gnu/4.2.3 por la ruta correspondiente en nuestro equipo; los archivos necesarios se encontrarán en en el directorio de GCC, tras seleccionar la arquitectura y SO correspondiente (en mi caso i686-pc-linux-gnu), y dentro de ese directorio encontraremos otro correspondiente a la versión de GCC (en mi caso la 4.2.3).

Más o menos lo que vemos en el proceso de linkado es lo siguiente:

  • -o hello : es el nombre del ejecutable
  • -m elf_i386 : es el tipo de ejecutable y la arquitectura. También puede ser elf_x86_64 si tenemos las bibliotecas necesarias.
  • -dynamic-linker /lib/ld-linux.so.2: es el cargador dinámico
  • /usr/lib/crt1.o /usr/lib/crti.o: son dos objetos encargados de la inicialización de memoria del programa
  • /usr/lib/gcc/i686-pc-linux-gnu/4.2.3/crtbegin.o : indica cómo tiene que empezar el programa.
  • /usr/lib/gcc/i686-pc-linux-gnu/4.2.3/crtend.o : indica cómo tiene que terminar el programa
  • hello.o : es el objeto de nuestro programa.
  • -L/usr/lib/gcc/i686-pc-linux-gnu/4.2.3 : hacemos que el linkador busque bibliotecas en el directorio indicado.
  • /usr/lib/crtn.o : realiza tareas de limpieza de memoria.
  • -lc: incluye la librería de C estándar.

Los archivos que empiezan por crt* normalmente se encargan de poner los datos que nos entran en su sitio; parece que el hecho de coger los parámetros que nos pasan por la línea de comandos y colocarlos en memoria para que nuestro programa los lea es tarea fácil, y que luego nuestro programa devuelva una respuesta; y además, los programas no se ejecutan siempre en la misma posición de memoria, depende de la memoria que haya libre, eso lo suele controlar el S.O. pero nuestros ejecutables tienen que estar preparados… en definitiva, hay muchos agentes involucrados.

Una vez hecho esto, tenemos nuestro hola mundo preparado para ser ejecutado.

Debo agradecer a Carlos, que me dio la idea de escribir este artículo.

También podría interesarte...

There are 2 comments left Ir a comentario

  1. Pingback: Bitacoras.com /

  2. Pingback: BlogESfera.com /

Leave a Reply