LD.SO(8) Manual del Programador de Linux LD.SO(8)

ld.so, ld-linux.so - enlazador/cargador dinámico

El enlazador dinámico puede ejecutarse bien indirectamente, al ejecutar un programa o biblioteca enlazado dinámicamente (en cuyo caso no pueden pasarse opciones en la línea de órdenes al enlazador dinámico y, en el caso del formato ELF, se ejecuta el enlazador dinámico que se encuentra almacenado en la sección .interp del programa), bien directamente ejecutando:

/lib/ld-linux.so.* [OPCIONES] [PROGRAMA [ARGUMENTOS]]

Los programas ld.so y ld-linux.so* encuentran y cargan las bibliotecas compartidas requeridas por un programa, preparan al programa para ejecutarse y lo ejecutan.

Los ficheros binarios en Linux requieren enlace dinámico (enlace en tiempo de ejecución) a menos que se dé la opción - static a ld(1) durante la compilación.

El programa ld.so maneja ficheros binarios con el formato a.out, un formato usado hace tiempo. El programa ld-linux.so* maneja el formato ELF (/lib/ld-linux.so.1 para libc5, /lib/ld-linux.so.2 para glibc2), más moderno. Por lo demás, ambos tienen el mismo comportamiento y usan los mismos ficheros de configuración y programas (ldd(1), ldconfig(8) y /etc/ld.so.conf).

Cuando se resuelven las dependencias de objetos compartidos, el enlazador dinámico empieza por comprobar cada dependencia para ver si contiene alguna barra (lo cual puede ocurrir si, al enlazar, definimos una ruta que contenía alguna). Si se encuentra una barra, la cadena se interpreta como un nombre de ruta (puede ser absoluto o relativo) y se cargará el objeto compartido con dicha ruta.

Si la dependencia del objeto compartido no contiene ninguna barra, ésta se buscara en este orden:

Usando el atributo dinámico de sección DT_RPATH del binario si está presente y el atributo DT_RUNPATH no existe. No se aconseja el uso de DT_RPATH.
Usando la variable de entorno LD_LIBRARY_PATH, salvo cuando se ejecute en modo seguro, en cuyo caso la variable será ignorada.
Mediante los directorios definidos en el atributo de la sección dinámica de DT_RUNPATH del binario, si existe. Sólo se buscará en estos directorios los objetos requeridos en las entradas de DT_NEEDED (dependencias directas) pero no en los descendientes de estos objetos. Éstos últimos deben tener su propia entrada DT_RUNPATH. Esto es distinto de DT_RPATH, que se usa para buscar a todos los descendientes en el árbol de dependencias.
A partir del fichero de caché /etc/ld.so.cache, que contiene una lista compilada de bibliotecas candidatas encontradas previamente en la ruta de bibliotecas ampliada. Sin embargo, si el binario fue enlazado con la opción -z nodeflib, las bibliotecas que se encuentran en las rutas predeterminadas son omitidas. Se prefieren los objetos compartidos instalados en directorios de capacidades de hardware (vea más adelante) antes que los otros.
En las rutas por defecto: /lib y /usr/lib (en algunas arquitecturas de 64 bits, las rutas por defecto para estos objetos compartidos son /lib64 y /usr/lib64. Si el binario fue enlazado con la opción -z nodeflib, se omite este paso.

En varios lugares, el enlazador expandirá los tokens de cadena dinámica:

En las variables de entorno LD_LIBRARY_PATH, LD_PRELOAD y LD_AUDIT,
en los valores de las etiquetas de sección dinámica DT_NEEDED, DT_RPATH, DT_RUNPATH, DT_AUDIT y DT_DEPAUDIT, también binarios ELF,
en varios argumentos de la orden ld.so: --audit, --library-path y --preload, por último
en el argumento del nombre de archivo de las funciones dlopen(3) y dlmopen(3).

Los tokens sustituidos con como sigue:

$ORIGIN (o el equivalente ${ORIGIN})
Esto se expandirá con el directorio que contiene el programa o los objetos compartidos. Por lo tanto, una aplicación que se encuentre en /dir/app se podría compilar con

gcc -Wl,-rpath,'$ORIGIN/../lib'

para que encuentre el objeto compartido en dir/lib pudiendo el directorio /dir estar localizado en cualquier punto del árbol de directorios. Esto evita que las aplicaciones deban instalarse en un directorios concreto sino que podrán acceder a sus objetos compartidos desde cualquier directorio.
$LIB (o su equivalente ${LIB})
Esto se interpretaría como lib o lib64 según la arquitectura (lógicamente si es x86-64 lo hará a lib64 y si es x86-32 lo hará a lib).
$PLATFORM (o su equivalente ${PLATFORM})
Esto se expandirá en una cadena de texto correspondiente al tipo de procesador del sistema (por ejemplo, "x86_64"). En algunas arquitecturas, el núcleo de Linux no proporciona una cadena de plataforma al enlazador dinámico. El valor de esta cadena se extrae de AT_PLATFORM en el vector auxiliar (consulte getauxval (3)).

Observe que los tokens de cadena dinámicas tienen que entrecomillarse correctamente cuando se definen a través de una shell para evitar que se interpreten como variables de entorno o de la propia shell.

Define el valor string para argv[0] antes de ejecutar la aplicación.
Utilice los objetos nombrados en lista como auditores. Los objetos en list ese delimitan entre si por dos puntos.
No emplee /etc/ld.so.cache.
Emplee path en lugar de la configuración de la variable de entorno LD_LIBRARY_PATH (vea más adelante). Los nombres ORIGIN, LIB y PLATFORM se entienden dirigidos a la variable LD_LIBRARY_PATH.
Ignora la información de RPATH y RUNPATH en los nombres de objeto en list. Esta opción se ignora si la ejecución se realiza en modo seguro (vea más adelante). Los objetos de la lista se separan mediante espacio o con dos puntos.
Lista todas las dependencias y cómo se resuelven.
Muestra los nombres y los valores de todos los ajustables junto con el intervalo de valores permitidos.
Carga previamente los objetos especificados en list, separados entre si por dos puntos o por espacios. Estos objetos se cargarán previamente tal como se explica más adelante en la descripción de la variable LD_PRELOAD.
Contrariamente al use de LD_PRELOAD, la opción --preload permite realizar una carga previa para un sólo ejecutable sin afectar a las cargas de otras procesos hijos de éste que ejecuten un nuevo programa.
Comprueba que el programa está enlazado dinámicamente y que el enlazador dinámico puede tratarlo.

Diversas variables de entorno influyen en el funcionamiento del enlazador.

Por razones de seguridad, cuando el enlazador determina que un binario tiene que ejecutarse en modo seguro se modificará o anulará el efecto de algunas variables de entorno. Es más, estas variables se eliminan del entorno así que el programa ni siquiera las verá. A continuación, se describen algunas de estas variables que afectan a las operaciones del propio enlazador. Otras variables de entorno gestionadas de este modo incluyen: GCONV_PATH, GETCONF_DIR, HOSTALIASES, LOCALDOMAIN, LOCPATH, MALLOC_TRACE, NIS_PATH, NLSPATH, RESOLV_HOST_CONF, RES_OPTIONS, TMPDIR y TZDIR.

Un binario se ejecuta en modo seguro si la entrada AT_SECURE en el vector auxiliar (consulte getauxval (3)) tiene un valor distinto de cero. Esta entrada puede tener un valor distinto de cero por varias razones:

  • Si difieren las ID de usuario reales y efectivas del proceso o las ID de grupo reales y efectivas. Esto suele ocurrir como resultado de la ejecución de una apliación con los bits activados de set-user-ID or set-group-ID.
  • Un proceso ejecutado por un usuario distinto al administrador ejecuta un binario que confiere alguna capacidad al mismo.
  • Es posible que un módulo de seguridad de Linux haya definido un valor distinto de cero.

Las variables de entorno más relevantes son las siguientes:

Cada objeto compartido puede informar al enlazador dinámico de la versión mínima de ABI del núcleo que requiere. (Este requisito está codificado en una sección de notas ELF que se puede ver ejecutando readelf  -n como una sección marcada como NT_GNU_ABI_TAG). Durante la ejecución, el enlazador dinámico determina la versión ABI del núcleo que se está ejecutando y rechazará cargar objetos compartidos que necesiten una versión superior.
LD_ASSUME_KERNEL puede usarse para hacer que el enlazador dinámico asuma que se está ejecutando en un sistema con una versión de ABI de núcleo diferente. Por ejemplo, la siguiente orden hace que el enlazador dinámico asuma que se está ejecutando en Linux 2.2.5 al cargar los objetos compartidos requeridos por myprog:

$ LD_ASSUME_KERNEL=2.2.5 ./myprog

En sistemas que proporcionan múltiples versiones de un objeto compartido (en diferentes directorios en la ruta de búsqueda) que tienen diferentes requisitos mínimos de versión de ABI del kernel, se puede usar LD_ASSUME_KERNEL para seleccionar la versión del objeto que se usa (dependiendo del orden de búsqueda del directorio).
Históricamente, el uso más común de la función LD_ASSUME_KERNEL era seleccionar manualmente los antiguos subprocesos POSIX de LinuxThreads en sistemas que proporcionaban tanto LinuxThreads como NPTL (que normalmente era el predeterminado); consulte pthreads (7).
Si su valor es distinto de cero, hará que el enlazador dinámico resuelva todos los símbolos al iniciarse el programa en lugar de hacerlo la primera vez que se hace referencia a ellos. Esto es especialmente útil cuando estamos usando un depurador.
Lista de directorios donde encontrar librerías ELF durante la ejecución. Los componentes de la lista estarán separados entre si o bien por punto y coma o bien por dos puntos no siendo posible usar una secuencia de escape para ninguno de ellos. Si la longitud del nombre del directorio es cero, se entenderá el directorio actual.
Esta variable se ignora en el modo de ejecución seguro.
Dentro de los nombres de ruta especificados en LD_LIBRARY_PATH, el enlazador dinámico expande los tokens $ ORIGIN, $ LIB e $ PLATFORM (o las versiones que usan llaves alrededor de los nombres) como se ha descrito anteriormente en Tokens de cadena dinámica. Por ejemplo, para buscar una biblioteca en el subdirectorio lib o lib64 dentro del directorio que contiene el programa a ejecutar:

$ LD_LIBRARY_PATH='$ORIGIN/$LIB' prog

(Observe el uso de comillas simples para evitar que la shell interprete $ORIGIN y $LIB como variables)
Una lista con una serie adicional, especificados por el usuario, de objetos compartidos ELF para ser cargados antes que todos los demás. Esto puede usarse para anular en casos concretos algunas funciones en otros objetos compartidos.
Los componentes de esta lista puede separarse entre si mediante dos puntos o mediante punto y coma. No existe una secuencia de escape para estos dos caracteres. Se buscan los objetos empleando la regla definida en DESCRIPTION, se van añadiendo al mapa de enlaces de izquierda a derecha según se especifica en la lista.
En el modo de ejecución seguro, se ignoran los nombres de ruta de precarga si contienen barras. Además, los objetos compartidos se precargan solo desde los directorios de búsqueda estándar y solo si tienen habilitado el bit set-user-ID (lo cual no es habitual).
Dentro de los nombres especificados en la lista LD_PRELOAD, el enlazador dinámico interpreta los tokens $ ORIGIN, $ LIB e $ PLATFORM (o los equivalente con llaves alrededor de los nombres) como se ha descrito anteriormente en tokens de cadena dinámica. (Véase también la explicación sobre el entrecomillado en el apartado LD_LIBRARY_PATH.)
Existen varias formas de indicar las bibliotecas que se deben precargar, siguiendo este orden:
(1)
La variable de entorno LD_PRELOAD.
(2)
Indicar en la línea de órdenes la opción --preload cuando se ejecute directamente el enlazador dinámico.
(3)
Desde el archivo /etc/ld.so.preload (explicado más adelante).
Si está definido (cualquiera que sea su valor) hará que el programa liste sus dependencias como si fuese ejecutado por ldd(1) en lugar de directamente.

Hay muchas más variables más o menos crípticas, muchas de ellas anticuadas o para uso interno.

Una lista de objetos compartidos ELF especificados por el usuario que se cargarán antes que todos los demás en un espacio de nombres de enlazador separado (es decir, uno que no interfiera en el enlazado de símbolos del proceso) Estos objetos se pueden usar para auditar la operación del enlazador dinámico. Los elementos de la lista están separados entre si por dos puntos y no existe ninguna secuencia de escape para este separador.
Se ignora LD_AUDIT en el modo de ejecución seguro.
El enlazador dinámico notificará a los objetos compartidos de auditoría en los llamados puntos de control de auditoría, por ejemplo, cargando un nuevo objeto compartido, resolviendo un símbolo o llamando a un símbolo de otro objeto compartido (llamando a una función apropiada dentro del objeto compartido de auditoría). Para obtener más información, consulte rtld-audit (7) La interfaz de auditoría es en gran medida compatible con la proporcionada en Solaris, como se describe en su Linker and Libraries Guide, en el capítulo Runtime Linker Auditing Interface.
Dentro de los nombres especificados en la lista LD_AUDIT, el enlazador dinámico interpreta los tokens $ ORIGIN, $ LIB e $ PLATFORM (o los equivalentes con llaves alrededor de los nombres) como se ha descrito anteriormente en tokens de cadena dinámica. (Véase también la explicación del entrecomillado en el apartado LD_LIBRARY_PATH.)
A partir de la versión 2.13 de glibc, en el modo de ejecución segura, los nombres de la lista de auditoría que contienen barras se ignoran y solo se cargan los objetos compartidos en los directorios de búsqueda estándar que tienen habilitado el bit set-user-ID.
Si esta variable de entorno se establece en una cadena no vacía, no actualiza GOT (tabla de compensación global) y PLT (tabla de vinculación de procedimientos) después de resolver un símbolo de función. Si con el uso de esta variable, añadimos LD_DEBUG (con las categorías bindings y symbols), se pueden observar todos los enlaces de funciones en tiempo de ejecución.
Muestra información detallada de depuración sobre el funcionamiento del enlazador dinámico. El contenido de esta variable es una o más de las siguientes categorías, separadas por dos puntos, comas o (si se entrecomilla el valor) espacios:
Si asignamos el valor help a esta variable, no se ejecutará el programa y se mostrará un mensaje de ayuda informando acerca de las categorías que se pueden definir en esta variable de entorno.
Imprime información para la depuración (salvo statistics ni unused; vea a continuación.
Muestra información sobre la definición a la que está vinculado cada símbolo.
Muestra el progreso del archivo de entrada.
Muestra las rutas de búsqueda de las librerias.
Muestra el procesamiento de reubicación.
Muestra información del alcance.
Muestra estadísticas de reubicación.
Muestra las rutas de búsqueda para cada búsqueda de símbolo.
Determina los DSO's sin usar.
Muestra las dependencias de esa versión.
Desde glibc 2.3.4, LD_DEBUG se ignora en el modo de ejecución segura, salvo que exista el archivo /etc/suid-debug (el contenido del archivo es irrelevante).
Por defecto, la salida LD_DEBUG se escribe a error estándar. Si se define LD_DEBUG_OUTPUT, la salida se escribe en el nombre de ruta especificado por su valor, con el sufijo "." (punto) seguido del ID de proceso adjunto al nombre de la ruta.
LD_DEBUG_OUTPUT se ignora en el modo de ejecución seguro.
Por defecto, cuando el enlazador busque una biblioteca compartida para encontrar algún símbolo, tomará la primera definición que encuentre.
Las versiones de glibc anteriores a 2.2, lo hacían de otro modo: si el enlazador encontraba un símbolo débil, seguiría buscando hasta encontrar uno más fuerte en el resto de bibliotecas compartidas. Si encontrase uno más fuerte, lo usaría.En caso de no encontrar otro más fuerte, usaría la definición del débil.
El antiguo comportamiento de glibc no era el estándar. (La práctica estandarizada es que la distinción entre símbolos débiles y fuertes debería tener efecto solo durante del enlazado estático). En glibc 2.2, el enlazador dinámico se modificó para tener el comportamiento actual, que era el comportamiento que ya proporcionaban la mayoría de las otras implementaciones.
Si se define la variable de entorno LD_DYNAMIC_WEAK (con cualquier valor) se tendrá el antiguo comportamiento glibc (no estándar), mediante el cual un símbolo débil en una biblioteca compartida puede ser anulado por un símbolo fuerte posteriormente descubierto en otra biblioteca compartida. (Observe que incluso cuando se establece esta variable, un símbolo fuerte en una biblioteca compartida no anulará una definición débil del mismo símbolo en el programa principal).
A partir de glibc 2.3.4, LD_DYNAMIC_WEAK se ignora en el modo de ejecución seguro.
Máscara para las capacidades hardware.
Ruta donde se encuentra el binario.
A partir de glibc 2.4, LD_ORIGIN_PATH se ignora en el modo de ejecución seguro.
Definir a 0 para deshabilitar la protección del puntero. Cualquier otro valor habilita la protección del puntero (lo hará por defecto). La protección de punteros es un mecanismo de seguridad mediante el cual se alteran de forma semi-aleatoria el código almacenado en la memoria del programa grabable (devuelven direcciones guardads por setjmp(3) o punteros de función utilizados por varios componentes internos de glibc) para dificultar que un atacante puede usarlos si se produce un desbordamiento de búfer o un ataque a la pila. Desde la versión 2.23 de glibc, LD_POINTER_GUARD ya no se puede deshabilitar la protección de punteros.
El nombre de un objeto compartido (único) que se va a perfilar, especificado como nombre de ruta o como soname. La salida del perfilado se agrega al archivo cuyo nombre es: "$ LD_PROFILE_OUTPUT / $ LD_PROFILE .profile".
A partir de glibc 2.2.5, LD_PROFILE se ignora en el modo de ejecución seguro.
Directorio donde se debe escribir la salida de LD_PROFILE. Si esta variable no está definida, o está definida como una cadena vacía, se toma por defecto /var/tmp.
LD_PROFILE_OUTPUT se ignora en el modo de ejecución segura; en su lugar, siempre se usa /var/profile. (Este detalle es relevante sólo en versiones anteriores de glibc 2.2.5, en las posteriores, LD_PROFILE también se ignora en el modo de ejecución segura).
Si esta variable de entorno está definida (con cualquier valor), muestra la matriz auxiliar enviada desde el núcleo (vea también getauxval (3)).
A partir de glibc 2.3.4, LD_SHOW_AUXV se ignora en el modo de ejecución seguro.
Si se define esta variable de entorno, se hará un seguimiento de la vinculación previa del objeto cuyo nombre está asignado a esta variable de entorno. (Utilice ldd (1) para ver los objetos que se pueden rastrear.) Si no se reconoce el nombre del objeto, se rastrea toda la actividad de preenlace.
De forma predeterminada (es decir, si esta variable no está definida), los ejecutables y los objetos compartidos preenlazados respetarán las direcciones base de sus objetos compartidos dependientes, pero los ejecutables independientes de la posición (PIE) (no vinculados previamente) y otros objetos compartidos no los respetarán. Si LD_USE_LOAD_BIAS se define con el valor 1, tanto los ejecutables como los PIE respetarán las direcciones base. Si LD_USE_LOAD_BIAS se define con el valor 0, ni los ejecutables ni los PIE respetarán las direcciones base.
A partir de glibc 2.3.3 se ignora esta variable en el modo de ejecución seguro.
Si se le asigna un valor de una cadena no vacía y si se ha establecido la variable de entorno LD_TRACE_LOADED_OBJECTS, se generará información sobre la versión del símbolo sobre el programa.
Si se le asigna como valor una cadena no nula, avisará si detecta símbolos no resueltos.
Según la guía de optimización del software Intel Silvermont, para las aplicaciones de 64 bits, el rendimiento de la predicción de ramas puede verse afectado negativamente cuando el objetivo de una rama está a más de 4 GB de distancia de ella. Si esta variable de entorno está configurada (con cualquier valor), el enlazador dinámico primero intentará mapear páginas ejecutables usando mmap (2) MAP_32BIT y volverá a mapear si ese intento falla. NB: MAP_32BIT se asignará a los 2 GB (no 4 GB) del espacio de direcciones.
Debido a que MAP_32BIT reduce el rango de direcciones disponible para que el diseño del espacio de direcciones sea aleatorio (ASLR), LD_PREFER_MAP_32BIT_EXEC siempre está deshabilitado en el modo de ejecución segura.

/lib/ld.so
enlazador/cargador dinmico
/lib/ld-linux.so.{1,2}
Enlazador/cargador dinámico ELF
/etc/ld.so.cache
Archivo que contiene una lista de directorios donde encontrar objetos compartidos y una lista ordenada de los candidatos. Consulte ldconfig(8).
/etc/ld.so.preload
Archivo que contiene una lista de objetos compartidos ELF separados entre si por espacios en blanco que se cargarán antes del programa. Vea el apartado anterior LD_PRELOAD. Si se emplean tanto LD_PRELOAD como /etc/ld.so.preload, las bibliotecas especificadas por LD_PRELOAD se precargan primero. /etc/ld.so.preload tiene efecto en todo el sistema, lo que hace que las bibliotecas especificadas se carguen previamente para todos los programas que se ejecutan en el sistema. (En general, no suele ser una opción ideal y por lo tanto, solo se emplea como una solución de emergencia, por ejemplo, como una solución temporal para un problema de configuración incorrecta de la biblioteca).
objetos compartidos

Algunos objetos compartidos se compilan utilizando instrucciones específicas de hardware que no existen en todas las CPU. Estos objetos deben instalarse en directorios cuyos nombres definan las capacidades de hardware necesarias, como /usr /lib/sse2/. El enlazador dinámico compara estos directorios con el hardware de la máquina y selecciona la versión más adecuada de un objeto compartido dado. Los directorios de capacidad de hardware se pueden conectar en cascada para combinar funciones de CPU. La lista de nombres de capacidad de hardware admitidos depende de la CPU. Actualmente se reconocen los siguientes:

ev4, ev5, ev56, ev6, ev67
loongson2e, loongson2f, octeon, octeon2
4xxmac, altivec, arch_2_05, arch_2_06, booke, cellbe, dfp, efpdouble, efpsingle, fpu, ic_snoop, mmu, notb, pa6t, power4, power5, power5+, power6x, ppc32, ppc601, ppc64, smt, spe, ucache, vsx
flush, muldiv, stbar, swap, ultra3, v9, v9v, v9v2
dfp, eimm, esan3, etf3enh, g5, highgprs, hpage, ldisp, msa, stfle, z900, z990, z9-109, z10, zarch
acpi, apic, clflush, cmov, cx8, dts, fxsr, ht, i386, i486, i586, i686, mca, mmx, mtrr, pat, pbe, pge, pn, pse36, sep, ss, sse, sse2, tm

ld(1), ldd(1), pldd(1), sprof(1), dlopen(3), getauxval(3), elf(5), capabilities(7), rtld-audit(7), ldconfig(8), sln(8)

Esta página es parte de la versión 5.13 del proyecto Linux man-pages. Puede encontrar una descripción del proyecto, información sobre cómo informar errores y la última versión de esta página en https://www.kernel.org/doc/man-pages/.

La traducción al español de esta página del manual fue creada por Juan Piernas <piernas@ditec.um.es> y Marcos Fouces <marcos@debian.org>

Esta traducción es documentación libre; lea la GNU General Public License Version 3 o posterior con respecto a las condiciones de copyright. No existe NINGUNA RESPONSABILIDAD.

Si encuentra algún error en la traducción de esta página del manual, envíe un correo electrónico a debian-l10n-spanish@lists.debian.org>..

27 Agosto 2021 GNU