Puis-je changer 'rpath' dans un binaire déjà compilé?

92

J'ai un ancien exécutable qui est prévu pour le tas de ferraille, mais il n'est pas encore là. Il repose sur des bibliothèques qui ont été supprimées de mon environnement, mais j'ai des bibliothèques stub quelque part où cela fonctionne correctement. J'aimerais pointer cet exécutable vers ces bibliothèques stub. Oui, je pourrais définir LD_LIBRARY_PATH, mais cet exécutable est appelé à partir de nombreux scripts, et de nombreux utilisateurs et j'aimerais le réparer en un seul endroit.

Je n'ai pas de source pour cela et il serait difficile de l'obtenir. Je pensais - puis-je modifier ce fichier, en utilisant un éditeur compatible ELF, et ajouter un simple PATH à rpath pour qu'il atteigne les nouvelles bibliothèques? Est-ce possible, ou une fois que vous créez un binaire ELF, vous corrigez les choses aux emplacements et ils ne peuvent pas être déplacés?

Rich Homolka
la source
3
Enveloppez-le dans un shellscript qui définit LD_LIBRARY_PATH et appelle le binaire. Placez le script shell dans un endroit qui se trouve dans le PATH des appelants.
wildplasser
LD_LIBRARY_PATH est hérité par les processus enfants. Vous pourriez ne pas vouloir cela.
Sera
1
@will ouais ça et j'ai déjà dit que je ne voulais pas faire ça. :)
Rich Homolka

Réponses:

78

Il existe un outil appelé chrpathqui peut le faire - il est probablement disponible dans les packages de votre distribution.

TomH
la source
9
Juste une note pour les utilisateurs de mac, install_name_toolpeut le faire avec le -rpathdrapeau
Kevin Tonon
10
Si vous obtenez l'erreur <binary>: no rpath or runpath tag found.chrpathpatchelfpatchelf --set-rpath /path/to/libaries <binary>
:,
Je préfère chrpath si possible car, bien qu'il soit plus universel, patchelf a un bogue de longue date qui gonfle considérablement la taille de vos bibliothèques / exécutables.
taranaki
157

Il existe un outil plus universel que celui chrpathappelé patchelf. Il a été créé à l'origine pour être utilisé dans la création de paquets pour Nix et NixOS (système d'empaquetage et distribution GNU / Linux).

Dans le cas où il n'y a pas de rpath dans un binaire (ici appelé rdsamp), chrpathéchoue:

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

D'autre part,

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

réussit très bien.

user7610
la source
9
Surtout, patchelfest capable d'ajouter un rpath à un binaire qui ne contient pas encore de rpath - où chrpathseulement semblent pouvoir modifier une entrée déjà présente.
maxschlepzig
4
De manière générale, il vaut la peine de comprendre la distinction subtile entre rpathet runpath. En gros, l'un peut passer outre LD_LIBRARY_PATHet l'autre non. Pour plus de détails, voir blog.tremily.us/posts/rpath
Stuart Berg
6
La chose ennuyeuse est que les deux chrpathet patchelfsont bâclés avec leur terminologie. Par exemple, la patchelfcommande indiquée ci-dessus changera, runpathmais pas à rpathmoins que vous ne fournissiez également l' --force-rpathoption.
Stuart Berg
10
@superbatfish Oui, mais la différence n'a généralement pas d'importance. Cette entrée du CHANGELOG de l' patchelfexplique: " --set-rpath, --shrink-rpathet --print-rpathpréfère maintenant DT_RUNPATHà DT_RPATH, qui est obsolète. Lors de la mise à jour, si les deux sont présents, les deux sont mis à jour. Si seul DT_RPATH est présent, il est converti en DT_RUNPATHsauf si --force-rpathspécifié. Si aucun n'est présent , a DT_RUNPATHest ajouté sauf indication --force-rpathcontraire, auquel cas a DT_RPATHest ajouté. " Le nom de l'option n'a probablement pas été modifié pour des raisons de compatibilité.
user7610
2
De loin la meilleure réponse, cela devrait être la réponse acceptée à la place!
Kenneth Hoste
12

Tout comme @ user7610 l'a dit, la bonne façon de procéder est l' patchelfoutil.

Mais je pense que je peux donner une réponse plus complète, couvrant toutes les commandes dont on a besoin pour faire exactement cela.

Pour un article complet sur le sujet, cliquez ici

Tout d'abord, de nombreux développeurs en parlent RPATH, mais ils veulent dire RUNPATH. Ce sont deux sections dynamiques optionnelles différentes, et le chargeur les gère très différemment. Vous pouvez en savoir plus sur la différence entre eux dans le lien que j'ai mentionné précédemment.

Pour l'instant, rappelez-vous simplement:

  • Si RUNPATHest défini, RPATHest ignoré
  • RPATH est obsolète et doit être évité
  • RUNPATH est préférable car il peut être remplacé par LD_LIBRARY_PATH

Voir le R [UN] PATH actuel

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

Effacer le CHEMIN R [UN]

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

Remarques:

  • Supprime à la fois RPATHetRUNPATH

Ajouter des valeurs à R [UN] PATH

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

Remarques:

  • <desired-path> est une liste de répertoires séparés par des virgules, par exemple: /my/libs:/my/other/libs
  • Si vous spécifiez --force-rpath, définit RPATH, sinon définitRUNPATH
Daniel Trugman
la source
1
-Wl,-R,<desired-rpath> -Wl,--enable-new-dtagsensembles DT_RUNPATH, et c'est celui que la plupart des gens devraient utiliser. RUNPATHpeut être remplacé par LD_LIBRARY_PATH, donc les gens ne devraient pas utiliser --force-rpath.
jww
@jww Je vois que je n'ai pas ajouté de commentaire sur la dépréciation de RPATH, alors j'en ai ajouté un tout à l'heure. Merci!
Daniel Trugman
Notez que l'exemple <desired-path>utilise un deux-points; ce devrait être une virgule (c'est-à-dire:) /my/libs,/my/other/libs.
Alan De Smet
@AlanDeSmet, je ne connais pas la virgule, mais les deux points fonctionnent pour moi.
Daniel Trugman
0

Cela a fonctionné pour moi, en remplaçant XORIGIN par $ ORIGIN.

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

vikram kedlaya
la source