¿Puedo cambiar 'rpath' en un binario ya compilado?

92

Tengo un ejecutable antiguo que está programado para el montón de desechos, pero aún no está disponible. Se basa en algunas bibliotecas que se han eliminado de mi entorno, pero tengo algunas bibliotecas auxiliares en algún lugar donde funciona bien. Me gustaría apuntar este ejecutable a estos stub libs. Sí, podría configurar LD_LIBRARY_PATH, pero este ejecutable se llama desde muchos scripts, y muchos usuarios, y me encantaría arreglarlo en un solo lugar.

No tengo fuente para esto y sería difícil conseguirlo. Estaba pensando: ¿puedo editar este archivo, usando un editor compatible con ELF y agregar un PATH simple a rpath para que llegue a las nuevas bibliotecas? ¿Es esto posible, o una vez que crea un binario ELF, arregla las cosas en las ubicaciones y no se pueden mover?

Rich Homolka
fuente
3
Envuélvalo en un shellscript que establezca LD_LIBRARY_PATH y llame al binario. Coloque el script de shell en un lugar que esté en la RUTA de las personas que llaman.
wildplasser
LD_LIBRARY_PATH es heredado por procesos secundarios. Puede que no quieras eso.
Será el
1
@ Sí, eso y ya dije que no quiero hacer eso. :)
Rich Homolka

Respuestas:

78

Hay una herramienta llamada chrpathque puede hacer esto; probablemente esté disponible en los paquetes de su distribución.

TomH
fuente
9
Solo una nota para los usuarios de Mac, install_name_toolpueden hacer esto con la -rpathbandera
Kevin Tonon
10
Si obtiene el error : <binary>: no rpath or runpath tag found., no puede usar chrpathpara reemplazarlo, pero puede usar patchelfen este caso:patchelf --set-rpath /path/to/libaries <binary>
phyatt
Prefiero chrpath si es posible ya que, aunque es más universal, patchelf tiene un error de larga data que infla drásticamente el tamaño de sus bibliotecas / ejecutables.
taranaki
158

Existe una herramienta más universal que la chrpathllamada patchelf. Originalmente fue creado para su uso en la creación de paquetes para Nix y NixOS (sistema de empaquetado y distribución GNU / Linux).

En caso de que no haya rpath en un binario (aquí llamado rdsamp), chrpathfalla:

chrpath -r '$ORIGIN/../lib64' rdsamp 
rdsamp: no rpath or runpath tag found.

Por otra parte,

patchelf --set-rpath '$ORIGIN/../lib64' rdsamp

tiene éxito muy bien.

user7610
fuente
9
Especialmente, patchelfes capaz de agregar un rpath a un binario que aún no contiene un rpath, donde chrpathsolo parece poder modificar una entrada ya presente.
maxschlepzig
4
Como nota general, vale la pena comprender la sutil distinción entre rpathy runpath. Básicamente, uno puede anular LD_LIBRARY_PATHy el otro no. Para obtener más información, consulte blog.tremily.us/posts/rpath
Stuart Berg
6
Lo molesto es que ambos chrpathy patchelfson descuidados con su terminología. Por ejemplo, el patchelfcomando que se muestra arriba cambiará, runpathpero no a rpathmenos que también proporcione la --force-rpathopción.
Stuart Berg
10
@superbatfish Sí, pero la diferencia generalmente no importa. Esta entrada del CHANGELOG de lo patchelfexplica: " --set-rpath, --shrink-rpathy --print-rpathahora prefiero DT_RUNPATHsobre DT_RPATH, que es obsoleto. Al actualizar, si ambos están presentes, ambos se actualizan. Si solo está presente DT_RPATH, se convierte a DT_RUNPATHmenos que --force-rpathse especifique. Si ninguno está presente , DT_RUNPATHse agrega a a menos que --force-rpathse especifique, en cuyo caso DT_RPATHse agrega a ". El nombre de la opción probablemente se mantuvo sin cambios por razones de compatibilidad.
user7610
2
Con mucho, la mejor respuesta, ¡debería ser la respuesta aceptada!
Kenneth Hoste
12

Como dijo @ user7610, el camino correcto es la patchelfherramienta.

Pero, siento que puedo dar una respuesta más completa, cubriendo todos los comandos que uno necesita para hacer exactamente eso.

Para obtener un artículo completo sobre el tema, haga clic aquí.

En primer lugar, muchos desarrolladores hablan RPATH, pero en realidad quieren decir RUNPATH. Se trata de dos secciones dinámicas opcionales diferentes y el cargador las maneja de manera muy diferente. Puedes leer más sobre la diferencia entre ellos en el enlace que mencioné antes.

Por ahora, solo recuerda:

  • Si RUNPATHestá configurado, RPATHse ignora
  • RPATH está en desuso y debe evitarse
  • RUNPATH se prefiere porque puede ser anulado por LD_LIBRARY_PATH

Ver la RUTA R [UN] actual

readelf -d <path-to-elf> | egrep "RPATH|RUNPATH"

Borrar la RUTA R [UN]

patchelf --remove-rpath <path-to-elf>

Notas:

  • Elimina tanto RPATHyRUNPATH

Agregar valores a R [UN] PATH

patchelf [--force-rpath] --set-rpath "<desired-rpath>" <path-to-elf>

Notas:

  • <desired-path> es una lista de directorios separados por comas, por ejemplo: /my/libs:/my/other/libs
  • Si especifica --force-rpath, establece RPATH, de lo contrario estableceRUNPATH
Daniel Trugman
fuente
1
-Wl,-R,<desired-rpath> -Wl,--enable-new-dtagsconjuntos DT_RUNPATH, y ese es el que la mayoría de la gente debería usar. RUNPATHpuede ser anulado por LD_LIBRARY_PATH, por lo que la gente no debería usar --force-rpath.
jww
@jww Veo que no agregué un comentario sobre la desaprobación de RPATH, así que agregué uno justo ahora. ¡Gracias!
Daniel Trugman
Tenga en cuenta que el ejemplo <desired-path>utiliza dos puntos; debe ser una coma (es decir :) /my/libs,/my/other/libs.
Alan De Smet
@AlanDeSmet, no sé sobre la coma, pero los dos puntos funcionan para mí.
Daniel Trugman
0

Esto funcionó para mí, reemplazando XORIGIN con $ ORIGIN.

chrpath -r '\$\ORIGIN/../lib64' httpd

vikram kedlaya
fuente