Publi

Enlazado dinámico en C (dynamic linking) I: Introducción

Algo que nos abre un mundo de posibilidades a la hora de realizar nuestros programas es la forma de enlazar los archivos objeto en nuestro binario definitivo. Ésta puede ser dinámica o estática.

La forma estática es la que se utiliza desde el primer momento que se empieza a programar: hemos creado varios archivos .c y queremos utilizar funciones de otro archivo dentro del archivo principal, con el objetivo de dividir el código en partes y no trabajar desde el mismo archivo. El resultado es que todos los archivos .c se compilan en varios archivo .o y luego todos se unen para formar un archivo ejecutable. Este ejecutable contendrá todas las funciones y símbolos de todos los archivos fuente.

También tenemos la posibilidad de enlazar dinámicamente los diferentes objetos en nuestro ejecutable y esto nos abre muchas posibilidades:

  • No tenemos que meterlo todo dentro del ejecutable, el cual puede crecer mucho
  • No tenemos por qué compilarlo todo siempre en tiempo de desarrollo
  • Una mejor modularización de nuestro código
  • Nos permite reutilizar código en forma de bibliotecas, código que puede ser reutilizado en varios proyectos (nuestros y de otras personas).
  • Si arreglamos un bug en una biblioteca, todos los programas que la utilicen se beneficiarán del cambio (también podemos inutilizar algunos programas si no hacemos bien las cosas…)
  • Nos permite utilizar bibliotecas implementadas por otras personas
  • Nos permite ocultar parte de nuestro código y distribuir complementos binarios
  • Damos facilidades para utilizar nuestras bibliotecas a otros desarrolladores, abstrayéndolos de lo que no necesitan conocer para utilizarlas
  • Permite la creación de plugins para nuestras aplicaciones
  • … y muchas cosas más.

Carga estática de bibliotecas dinámicas

Las bibliotecas dinámicas, estos objetos compartidos (Shared Objects, cuya extensión es .so) pueden ser cargados de forma estática y de forma dinámica.
La carga estática tenemos que especificarla en tiempo de compilación, debemos hacerla añadiendo la biblioteca que queremos incluir al compilar (y luego en la ejecución tendremos que decirle donde están esas bibliotecas si no están en la ruta indicada para eso.

Para hacer la prueba, vamos a crear una biblioteca llamada pitagoras, que calculará la longitud de la hipotenusa a partir de las longitudes de los catetos con el Teorema de Pitágoras. Su código fuente será:
libpitagoras.h

1
2
3
4
5
6
7
8
9
/* @(#)libpitagoras.h
 */


#ifndef _LIBPITAGORAS_H
#define _LIBPITAGORAS_H 1

float pitagoras(float c1, float c2);

#endif /* _LIBPITAGORAS_H */

libpitagoras.c

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

float pitagoras(float c1, float c2)
{
  return sqrt(c1*c1+ c2*c2);
}

Es importante que el archivo contenga “lib” delante para que GCC lo reconozca como una biblioteca a la hora de realizar el enlace. Ahora vamos a hacer un programa principal que utilice la función pitagoras():

mainpi.c

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <stdlib.h>
#include "libpitagoras.h"

void saludo();

int main(int argc, char *argv[])
{
  printf("La hipotenusa es: %f\n", pitagoras(3, 4));

  return 0;
}

Para compilar, tenemos que hacerlo de una forma especial, utilizando las directivas -fPIC y -shared. La primera, creará un código independiente de posición (no tendrá que colocarse en una posición determinada de la memoria para poder ser utilizado) y la segunda creará un objeto compartido (.so). Lo haremos de la siguiente manera:

$ gcc -c -fPIC libpitagoras.c
$ gcc -shared -o libpitagoras.so libpitagoras.o -lm

En la primera línea creamos el archivo objeto (con -c), en la segunda, crearemos el objeto compartido y le añadiremos la biblioteca matemática -lm, necesaria para hacer la raíz cuadrada (sqrt). Si no añadimos -lm compilará igual, pero fallará al compilar el ejecutable porque no se ha logrado encontrar el código de sqrt. Aunque también lo podemos hacer todo junto, sólo estaba dividido en pasos para poder ver el proceso completo, pero así es más rápido:

$ gcc -fPIC -shared -o libpitagoras.so libpitagoras.c -lm

Ahora para compilar el ejecutable hacemos:

$ gcc -o mainpi mainpi.c -L. -lpitagoras

Con esta línea creamos el ejecutable mainpi, le decimos con -L dónde debe buscar la biblioteca, normalmente se buscará en /lib y /usr/lib, pero en este ejemplo lo encontramos en el mismo directorio del programa, por eso ponemos un punto. Luego incluiremos -lpitagoras que leerá nuestro archivo .so para ver que todo está en orden, pero en realidad se leerá en tiempo de ejecución el código del shared object; para demostrar esto, podemos hacer cualquier cambio en la biblioteca pitágoras (por ejemplo poner un printf()), recompilar la biblioteca y ejecutar de nuevo el programa principal (claro está, sin compilarlo). Al ejecutarlo, veremos el cambio que hemos realizado.

Foto: Mixtribe Photo (Flickr). CC-A a 01/03/2013

También podría interesarte...

There are 2 comments left Ir a comentario

  1. Pingback: Enlazado dinámico en C (dynamic linking) II: Carga dinámica de shared objects | Poesía Binaria /

  2. Pingback: Bitacoras.com /

Leave a Reply