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.