GNU/Linux >> Tutoriales Linux >  >> Linux

Múltiples bibliotecas glibc en un solo host

Esta pregunta es vieja, las otras respuestas son viejas. La respuesta de "Employed Russian" es muy buena e informativa, pero solo funciona si tiene el código fuente. Si no lo hace, las alternativas en ese entonces eran muy complicadas. Afortunadamente hoy en día tenemos una solución sencilla a este problema (como comenta en una de sus respuestas), utilizando patchelf. Todo lo que tienes que hacer es:

$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp

Y después de eso, puedes simplemente ejecutar tu archivo:

$ ./myapp

No es necesario chroot o editar binarios manualmente, afortunadamente. Pero recuerde hacer una copia de seguridad de su binario antes de parchearlo, si no está seguro de lo que está haciendo, porque modifica su archivo binario. Después de parchearlo, no puede restaurar la ruta anterior a interpreter/rpath. Si no funciona, tendrá que seguir parchándolo hasta que encuentre la ruta que realmente funcione... Bueno, no tiene que ser un proceso de prueba y error. Por ejemplo, en el ejemplo de OP, necesitaba GLIBC_2.3 , para que pueda encontrar fácilmente qué lib proporciona esa versión usando strings :

$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3

En teoría, el primer grep vendría vacío porque el sistema libc no tiene la versión que él quiere, y el segundo debería generar GLIBC_2.3 porque tiene la versión myapp está usando, por lo que sabemos que podemos patchelf nuestro binario usando esa ruta. Si obtiene una falla de segmentación, lea la nota al final.

Cuando intenta ejecutar un binario en Linux, el binario intenta cargar el enlazador, luego las bibliotecas, y todas deberían estar en la ruta y/o en el lugar correcto. Si su problema es con el enlazador y desea averiguar qué ruta está buscando su binario, puede averiguarlo con este comando:

$ readelf -l myapp | grep interpreter
  [Requesting program interpreter: /lib/ld-linux.so.2]                                                                                                                                                                                   

Si su problema es con las bibliotecas, los comandos que le darán las bibliotecas que se están utilizando son:

$ readelf -d myapp | grep Shared
$ ldd myapp 

Esto mostrará una lista de las bibliotecas que necesita su binario, pero probablemente ya conozca las problemáticas, ya que ya están generando errores como en el caso de OP.

"pachelf" funciona para muchos problemas diferentes que puede encontrar al intentar ejecutar un programa, relacionados con estos 2 problemas. Por ejemplo, si obtienes:ELF file OS ABI invalid , se puede solucionar configurando un nuevo cargador (el --set-interpreter parte del comando) como explico aquí. Otro ejemplo es el problema de obtener No such file or directory cuando ejecuta un archivo que está allí y es ejecutable, como se ejemplifica aquí. En ese caso particular, a OP le faltaba un enlace al cargador, pero tal vez en su caso no tenga acceso de root y no pueda crear el enlace. Establecer un nuevo intérprete resolvería su problema.

¡Gracias a Employee Russian y Michael Pankov por la información y la solución!

Nota por falla de segmentación:podría estar en el caso donde myapp usa varias bibliotecas, y la mayoría de ellas están bien, pero algunas no; entonces tu patchelf a un nuevo directorio, y obtienes un error de segmentación. Cuando patchelf su binario, cambia la ruta de varias bibliotecas, incluso si algunas estaban originalmente en una ruta diferente. Echa un vistazo a mi ejemplo a continuación:

$ ldd myapp
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by ./myapp)
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./myapp)
        linux-vdso.so.1 =>  (0x00007fffb167c000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a9aad2000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9a9a8ce000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a9a6af000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9a9a3ab000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a99fe6000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f9a9adeb000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9a99dcf000)

Tenga en cuenta que la mayoría de las bibliotecas están en /lib/x86_64-linux-gnu/ pero el problemático (libstdc++.so.6 ) está en /usr/lib/x86_64-linux-gnu . Después de parchear myapp para apuntar a /path/to/mylibs , Tengo falla de segmentación. Por alguna razón, las librerías no son totalmente compatibles con el binario. Desde myapp no me quejé de las bibliotecas originales, las copié de /lib/x86_64-linux-gnu/ a /path/to/mylibs2 , y también copié libstdc++.so.6 de /path/to/mylibs allá. Luego lo parcheé a /path/to/mylibs2 y myapp funciona ahora Si su binario usa diferentes bibliotecas y tiene diferentes versiones, es posible que no pueda solucionar su situación. :( Pero si es posible, mezclar libs podría ser el camino. No es lo ideal, pero tal vez funcionará. ¡Buena suerte!


Use LD_PRELOAD:coloque su biblioteca en algún lugar fuera de los directorios man lib y ejecute:

LD_PRELOAD='mylibc.so anotherlib.so' program

Ver:el artículo de Wikipedia


En primer lugar, la dependencia más importante de cada programa enlazado dinámicamente es el enlazador. Todas las bibliotecas deben coincidir con la versión del enlazador.

Tomemos un ejemplo simple:tengo el nuevo sistema ubuntu donde ejecuto algún programa (en mi caso es el compilador D - ldc2). Me gustaría ejecutarlo en el viejo CentOS, pero debido a la antigua biblioteca glibc es imposible. tengo

ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)

Tengo que copiar todas las dependencias de ubuntu a centos. El método correcto es el siguiente:

Primero, verifiquemos todas las dependencias:

ldd ldc2-1.5.0-linux-x86_64/bin/ldc2 
    linux-vdso.so.1 =>  (0x00007ffebad3f000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000)

linux-vdso.so.1 no es una biblioteca real y no nos tiene que importar.

/lib64/ld-linux-x86-64.so.2 es el enlazador, que utiliza Linux para enlazar el ejecutable con todas las bibliotecas dinámicas.

El resto de los archivos son bibliotecas reales y todos ellos junto con el enlazador deben copiarse en algún lugar de los centos.

Supongamos que todas las bibliotecas y el enlazador están en el directorio "/mylibs".

ld-linux-x86-64.so.2, como ya he dicho, es el enlazador. No es una biblioteca dinámica sino un ejecutable estático. Puede ejecutarlo y ver que incluso tiene algunos parámetros, por ejemplo, --library-path (regresaré a él).

En Linux, el programa enlazado dinámicamente se puede iniciar solo por su nombre, por ejemplo,

/bin/ldc2

Linux carga dicho programa en la RAM y verifica qué enlazador está configurado para él. Por lo general, en un sistema de 64 bits, es /lib64/ld-linux-x86-64.so.2 (en su sistema de archivos es un enlace simbólico al ejecutable real). Luego, Linux ejecuta el enlazador y carga bibliotecas dinámicas.

También puedes cambiar esto un poco y hacer ese truco:

/mylibs/ld-linux-x86-64.so.2 /bin/ldc2

Es el método para obligar a Linux a usar un enlazador específico.

Y ahora podemos volver al parámetro anterior mencionado --library-path

/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2

Ejecutará ldc2 y cargará bibliotecas dinámicas desde /mylibs.

Este es el método para llamar al ejecutable con las bibliotecas elegidas (no las predeterminadas del sistema).


Es muy posible tener múltiples versiones de glibc en el mismo sistema (lo hacemos todos los días).

Sin embargo, debe saber que glibc consta de muchas piezas (más de 200 bibliotecas compartidas) que deben coincidir. Una de las piezas es ld-linux.so.2, y debe haga coincidir libc.so.6, o verá los errores que está viendo.

La ruta absoluta a ld-linux.so.2 está codificada en el ejecutable en el momento del enlace, y no se puede cambiar fácilmente una vez que se realiza el enlace (Actualización:se puede hacer con patchelf; consulte esta respuesta a continuación).

Para crear un ejecutable que funcione con la nueva glibc, haga lo siguiente:

g++ main.o -o myapp ... \
   -Wl,--rpath=/path/to/newglibc \
   -Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2

El -rpath La opción del enlazador hará que el cargador de tiempo de ejecución busque bibliotecas en /path/to/newglibc (para que no tenga que configurar LD_LIBRARY_PATH antes de ejecutarlo), y el -dynamic-linker la opción "horneará" la ruta para corregir ld-linux.so.2 en la aplicación.

Si no puede volver a vincular el myapp aplicación (por ejemplo, porque es un binario de terceros), no todo está perdido, pero se vuelve más complicado. Una solución es establecer un chroot adecuado ambiente para ello. Otra posibilidad es usar rtldi y un editor binario. Actualización:o puedes usar patchelf.


Linux
  1. Aloja varios sitios web en contenedores Docker

  2. Cómo ejecutar un solo comando en múltiples sistemas remotos a la vez

  3. ¿Cómo cambiar el nombre de varios archivos en un solo comando o secuencia de comandos en Unix?

  4. Ssh – ¿Múltiples entradas similares en Ssh Config?

  5. ¿Cómo alojar varios dominios?

Cómo alojar múltiples sitios en una sola instalación de Wordpress en Ubuntu 14.04

Cómo alojar múltiples sitios en una sola instalación de Wordpress en CentOS 7

Cómo ejecutar múltiples comandos de Linux en un solo comando

Aloje múltiples sitios web en un solo servidor con Apache en Ubuntu 18.04

Cómo unir varias páginas PDF en una sola página

¿Cómo cambiar el nombre de varios archivos en un solo comando o secuencia de comandos en Unix?