102.3 Lección 1
Certificación: |
LPIC-1 |
---|---|
Versión: |
5.0 |
Tema: |
102 Instalación de Linux y Administración de Paquetes |
Objetivo: |
102.3 Administrar bibliotecas compartidas |
Lección: |
1 de 1 |
Introducción
En esta lección discutiremos sobre bibliotecas compartidas (shared libraries), también conocidas como objetos compartidos (shared objects): partes de código compilado y reutilizable como funciones o clases, que varios programas utilizan de manera recurrente.
Para comenzar, explicaremos qué son las bibliotecas compartidas, cómo identificarlas y dónde se encuentran. A continuación, veremos cómo configurar sus ubicaciones de almacenamiento. Finalmente, mostraremos cómo buscar las bibliotecas compartidas de las que depende un programa en particular.
Concepto de bibliotecas compartidas
Al igual que sus contrapartes físicas, las bibliotecas de software son colecciones de código que están destinadas a ser utilizadas por muchos programas diferentes; así como las bibliotecas físicas guardan libros y otros recursos para ser utilizados por muchas personas diferentes.
Para construir un archivo ejecutable a partir del código fuente de un programa, son necesarios dos pasos importantes. Primero, el compilador convierte el código fuente en código de máquina que se almacena en los llamados object files. En segundo lugar, el linker combina los archivos de objetos y los vincula a las bibliotecas para generar el archivo ejecutable final. Este enlace puede hacerse statically (estáticamente) o dynamically (dinámicamente). Dependiendo del método que utilicemos, hablaremos de bibliotecas estáticas o, en caso de vinculación dinámica, de bibliotecas compartidas. Expliquemos sus diferencias.
- Bibliotecas estáticas
-
Una biblioteca estática se fusiona con el programa en el momento del enlace. Una copia del código de la biblioteca se incrusta en el programa y se convierte en parte de él. Por lo tanto, el programa no tiene dependencias de la biblioteca en tiempo de ejecución porque el programa ya contiene el código de la biblioteca. No tener dependencias puede verse como una ventaja, ya que no tiene que preocuparse por asegurarse de que las bibliotecas utilizadas siempre estén disponibles. En el lado negativo, los programas vinculados estáticamente son más pesados.
- Bibliotecas compartidas (o dinámicas)
-
En el caso de las bibliotecas compartidas, el enlazador simplemente se encarga de que el programa haga referencia a las bibliotecas correctamente. Sin embargo, el vinculador no copia ningún código de biblioteca en el archivo del programa. Sin embargo, en tiempo de ejecución, la biblioteca compartida debe estar disponible para satisfacer las dependencias del programa. Este es un enfoque económico para administrar los recursos del sistema, ya que ayuda a reducir el tamaño de los archivos de programa y solo se carga una copia de la biblioteca en la memoria, incluso cuando es utilizada por varios programas.
Convenciones de nomenclatura de archivos de objetos compartidos
El nombre de una biblioteca compartida, también conocida como soname, sigue un patrón que se compone de tres elementos:
-
Nombre de la biblioteca (normalmente precedido por
lib
) -
so
(que significa “objeto compartido”) -
Número de versión de la biblioteca
Por ejemplo: libpthread.so.0
Por el contrario, los nombres de las bibliotecas estáticas terminan en .a
, p. ej. libpthread.a
.
Note
|
Debido a que los archivos que contienen bibliotecas compartidas deben estar disponibles cuando se ejecuta el programa, la mayoría de los sistemas Linux contienen bibliotecas compartidas. Dado que las bibliotecas estáticas solo se requieren en un archivo dedicado cuando se vincula un programa, es posible que no estén presentes en un sistema de usuario final. |
glibc
(biblioteca GNU C) es un buen ejemplo de una biblioteca compartida. En un sistema Debian GNU/Linux 9.9, su archivo se llama libc.so.6
. Tales nombres de archivo bastante generales son normalmente enlaces simbólicos que apuntan al archivo real que contiene una biblioteca, cuyo nombre contiene el número de versión exacto. En el caso de glibc
, este enlace simbólico se ve así:
$ ls -l /lib/x86_64-linux-gnu/libc.so.6 lrwxrwxrwx 1 root root 12 feb 6 22:17 /lib/x86_64-linux-gnu/libc.so.6 -> libc-2.24.so
Este patrón de hacer referencia a archivos de biblioteca compartida nombrados por una versión específica por nombres de archivo más generales es una práctica común.
Otros ejemplos de bibliotecas compartidas incluyen libreadline
(que permite a los usuarios editar líneas de comando a medida que se escriben e incluye soporte para los modos de edición Emacs y vi), libcrypt
(que contiene funciones relacionadas con el cifrado, el hash y la codificación) , o libcurl
(que es una biblioteca de transferencia de archivos multiprotocolo).
Las ubicaciones comunes para las bibliotecas compartidas en un sistema Linux son:
-
/lib
-
/lib32
-
/lib64
-
/usr/lib
-
/usr/local/lib
Note
|
El concepto de bibliotecas compartidas no es exclusivo de Linux. En Windows, por ejemplo, se denominan DLL, que significa dynamic linked libraries (bibliotecas vinculadas dinámicamente). |
Configuración de rutas de bibliotecas compartidas
Las referencias contenidas en los programas vinculados dinámicamente se resuelven mediante el vinculador dinámico (ld.so
o ld-linux.so
) cuando se ejecuta el programa. El vinculador dinámico busca bibliotecas en varios directorios. Estos directorios están especificados por la ruta de la biblioteca. La ruta de la biblioteca se configura en el directorio /etc
, es decir, en el archivo /etc/ld.so.conf
y, más común hoy en día, en archivos que residen en el directorio /etc/ld.so.conf.d
. Normalmente, el primero incluye una sola línea include
para los archivos *.conf
en el segundo:
$ cat /etc/ld.so.conf include /etc/ld.so.conf.d/*.conf
El directorio /etc/ld.so.conf.d
contiene archivos *.conf
:
$ ls /etc/ld.so.conf.d/ libc.conf x86_64-linux-gnu.conf
Estos archivos *.conf
deben incluir las rutas absolutas a los directorios de las bibliotecas compartidas:
$ cat /etc/ld.so.conf.d/x86_64-linux-gnu.conf # Multiarch support /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu
El comando ldconfig
se encarga de leer estos archivos de configuración, creando el conjunto de enlaces simbólicos antes mencionados que ayudan a localizar las bibliotecas individuales y finalmente a actualizar el archivo de caché /etc/ld.so.cache
. Por lo tanto, ldconfig
debe ejecutarse cada vez que se agregan o actualizan archivos de configuración.
Las opciones útiles para ldconfig
son:
-v
,--verbose
-
Muestra los números de versión de la biblioteca, el nombre de cada directorio y los enlaces que se crean:
$ sudo ldconfig -v /usr/local/lib: /lib/x86_64-linux-gnu: libnss_myhostname.so.2 -> libnss_myhostname.so.2 libfuse.so.2 -> libfuse.so.2.9.7 libidn.so.11 -> libidn.so.11.6.16 libnss_mdns4.so.2 -> libnss_mdns4.so.2 libparted.so.2 -> libparted.so.2.0.1 (...)
Así podemos ver, por ejemplo, cómo se vincula
libfuse.so.2
con el archivo de objeto compartido reallibfuse.so.2.9.7
. -p
,--print-cache
-
Imprime las listas de directorios y bibliotecas candidatas almacenadas en la caché actual:
$ sudo ldconfig -p 1094 libs found in the cache `/etc/ld.so.cache' libzvbi.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi.so.0 libzvbi-chains.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi-chains.so.0 libzmq.so.5 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzmq.so.5 libzeitgeist-2.0.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzeitgeist-2.0.so.0 (...)
Observe cómo la cache usa el nombre completo del soname en el enlace:
$ sudo ldconfig -p |grep libfuse libfuse.so.2 (libc6,x86-64) => /lib/x86_64-linux-gnu/libfuse.so.2
Si hacemos una lista larga de /lib/x86_64-linux-gnu/libfuse.so.2
, encontraremos la referencia al archivo de objeto compartido real libfuse.so.2.9.7
que está almacenado en el mismo directorio:
$ ls -l /lib/x86_64-linux-gnu/libfuse.so.2 lrwxrwxrwx 1 root root 16 Aug 21 2018 /lib/x86_64-linux-gnu/libfuse.so.2 -> libfuse.so.2.9.7
Note
|
Como requiere acceso de escritura a |
Además de los archivos de configuración descritos anteriormente, la variable de entorno LD_LIBRARY_PATH
se puede usar para agregar nuevas rutas para bibliotecas compartidas temporalmente. Está formado por un conjunto de directorios separados por dos puntos (:
) donde se buscan las bibliotecas. Para agregar, por ejemplo, /usr/local/mylib
a la ruta de la biblioteca en la sesión de shell actual, puede teclear:
$ LD_LIBRARY_PATH=/usr/local/mylib
Ahora puede verificar su valor:
$ echo $LD_LIBRARY_PATH /usr/local/mylib
Para agregar /usr/local/mylib
a la ruta de la biblioteca en la sesión de shell actual y exportarlo a todos los procesos secundarios generados desde ese shell, debe usar el siguiente comando:
$ export LD_LIBRARY_PATH=/usr/local/mylib
Para eliminar la variable de entorno LD_LIBRARY_PATH
, simplemente utilice el siguiente comando:
$ unset LD_LIBRARY_PATH
Para que los cambios sean permanentes, usar el siguiente comando.
export LD_LIBRARY_PATH=/usr/local/mylib
en uno de los scripts de inicialización de Bash como /etc/bash.bashrc
o ~/.bashrc
.
Note
|
|
Buscando las dependencias de un ejecutable particular
Para buscar las bibliotecas compartidas requeridas por un programa específico, use el comando ldd
seguido de la ruta absoluta al programa. El resultado muestra la ruta del archivo de la biblioteca compartida, así como la dirección de memoria hexadecimal en la que se carga:
$ ldd /usr/bin/git linux-vdso.so.1 => (0x00007ffcbb310000) libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f18241eb000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f1823fd1000) libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f1823db6000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f1823b99000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f1823991000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f18235c7000) /lib64/ld-linux-x86-64.so.2 (0x00007f182445b000)
Del mismo modo, usamos ldd
para buscar las dependencias de un objeto compartido:
$ ldd /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2 (0x00007fbfed578000) linux-vdso.so.1 (0x00007fffb7bf5000)
Con la opción -u
(o --unused
) ldd
imprime las dependencias directas no utilizadas (si existen):
$ ldd -u /usr/bin/git Unused direct dependencies: /lib/x86_64-linux-gnu/libz.so.1 /lib/x86_64-linux-gnu/libpthread.so.0 /lib/x86_64-linux-gnu/librt.so.1
La razón de las dependencias no utilizadas está relacionada con las opciones utilizadas por el vinculador al construir el binario. Aunque el programa no necesita una biblioteca no utilizada, todavía estaba vinculado y etiquetado como NEEDED
en la información sobre el archivo objeto. Puede investigar esto usando comandos como readelf
u objdump
, que pronto usará en el ejercicio de exploración.
Ejercicios Guiados
-
Divida los siguientes nombres de bibliotecas compartidas en sus partes:
Nombre completo del archivo Nombre de la biblioteca so sufijo Número de versión linux-vdso.so.1
libprocps.so.6
libdl.so.2
libc.so.6
libsystemd.so.0
ld-linux-x86-64.so.2
-
Ha desarrollado un software y desea agregar un nuevo directorio de biblioteca compartida a su sistema (
/opt/lib/mylib
). Escriba su ruta absoluta en un archivo llamadomylib.conf
.-
¿En qué directorio debe almacenar este archivo?
-
¿Qué comando debe ejecutar para que los cambios sean totalmente efectivos?
-
-
¿Qué comando usaría para listar las bibliotecas compartidas requeridas por
kill
?
Ejercicios Exploratorios
-
objdump
es una utilidad de línea de comandos que muestra información de archivos de objetos. Compruebe si está instalado en su sistema conwhich objdump
. Si no es así, instálelo.-
Use
objdump
con-p
(o--private-headers
) ygrep
para imprimir las dependencias deglibc
: -
Use
objdump
con-p
(o--private-headers
) ygrep
para imprimir el soname deglibc
: -
Use
objdump
con-p
(o--private-headers
) ygrep
para imprimir las dependencias de Bash:
-
Resumen
En esta lección aprendimos:
-
¿Qué es una biblioteca compartida (o dinámica)?
-
Las diferencias entre bibliotecas compartidas y estáticas.
-
Los nombres de las bibliotecas compartidas (sonames).
-
Las ubicaciones preferidas para bibliotecas compartidas en un sistema Linux, como
/lib
o/usr/lib
. -
El propósito del enlazador dinámico
ld.so
(old-linux.so
). -
¿Cómo configurar rutas compartidas de la biblioteca mediante archivos en
/etc/
comold.so.conf
o los del directoriold.so.conf.d
? -
¿Cómo configurar rutas de biblioteca compartidas mediante la variable de entorno
LD_LIBRARY_PATH
? -
¿Cómo buscar dependencias de bibliotecas ejecutables y compartidas?
Comandos utilizados en esta lección:
ls
-
Lista el contenido de un directorio.
cat
-
Concatena archivos e imprime en la salida estándar.
sudo
-
Hace que el superusuario ejecute el comando con privilegios administrativos.
ldconfig
-
Configura enlaces de tiempo de ejecución del vinculador dinámico.
echo
-
Muestra el valor de la variable de entorno.
export
-
Valor de exportación de la variable de entorno a shells secundarios.
unset
-
Elimina variables de entorno.
ldd
-
Imprime dependencias de objetos compartidos de un programa.
readelf
-
Muestra información sobre archivos ELF (ELF significa executable and linkable format).
objdump
-
Imprime información de archivos de objetos.
Respuestas a los ejercicios guiados
-
Divida los siguientes nombres de bibliotecas compartidas en sus partes:
Nombre completo del archivo Nombre de la biblioteca so sufijo Número de versión linux-vdso.so.1
linux-vdso
so
1
libprocps.so.6
libprocps
so
6
libdl.so.2
libdl
so
2
libc.so.6
libc
so
6
libsystemd.so.0
libsystemd
so
0
ld-linux-x86-64.so.2
ld-linux-x86-64
so
2
-
Ha desarrollado un software y desea agregar un nuevo directorio de biblioteca compartida a su sistema (
/opt/lib/mylib
). Escriba su ruta absoluta en un archivo llamadomylib.conf
.-
¿En qué directorio debe almacenar este archivo?
/etc/ld.so.conf.d
-
¿Qué comando debe ejecutar para que los cambios sean totalmente efectivos?
ldconfig
-
-
¿Qué comando usaría para listar las bibliotecas compartidas requeridas por
kill
?ldd /bin/kill
Respuestas a ejercicios exploratorios
-
objdump
es una utilidad de línea de comandos que muestra información de archivos de objetos. Compruebe si está instalado en su sistema conwhich objdump
. Si no es así, instálelo.-
Use
objdump
con el-p
(o--private-headers
) ygrep
para imprimir las dependencias deglibc
:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep NEEDED
-
Use
objdump
con el-p
(o--private-headers
) ygrep
para imprimir el soname deglibc
:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep SONAME
-
Use
objdump
con el-p
(o--private-headers
) ygrep
para imprimir las dependencias de Bash:objdump -p /bin/bash | grep NEEDED
-