Kann ich 'rpath' in einer bereits kompilierten Binärdatei ändern?

92

Ich habe eine alte ausführbare Datei, die für den Schrotthaufen geplant ist, aber sie ist noch nicht da. Es basiert auf einigen Bibliotheken, die aus meiner Umgebung entfernt wurden, aber ich habe einige Stub-Bibliotheken an einem Ort, an dem es gut funktioniert. Ich möchte diese ausführbare Datei auf diese Stub-Bibliotheken verweisen. Ja, ich könnte LD_LIBRARY_PATH setzen, aber diese ausführbare Datei wird von vielen Skripten aufgerufen, und viele Benutzer und ich würden sie gerne an einer Stelle reparieren.

Ich habe keine Quelle dafür und wäre schwer zu bekommen. Ich dachte: Kann ich diese Datei mit einem ELF-fähigen Editor bearbeiten und rpath einen einfachen Pfad hinzufügen, damit sie die neuen Bibliotheken erreicht? Ist dies möglich oder wenn Sie eine ELF-Binärdatei erstellt haben, reparieren Sie Dinge an Orten und sie können nicht verschoben werden?

Reiche Homolka
quelle
3
Wickeln Sie es in ein Shellscript, das LD_LIBRARY_PATH setzt und die Binärdatei aufruft. Platzieren Sie das Shell-Skript an einer Stelle, die sich im PFAD des Anrufers befindet.
Wildplasser
LD_LIBRARY_PATH wird von untergeordneten Prozessen geerbt. Das willst du vielleicht nicht.
Will
1
@will ja das und ich habe schon gesagt ich will das nicht machen. :)
Rich Homolka

Antworten:

78

Es gibt ein Tool namens, chrpathdas dies tun kann - es ist wahrscheinlich in den Paketen Ihrer Distribution verfügbar.

TomH
quelle
9
Nur ein Hinweis für Mac-Benutzer, install_name_toolkann dies mit der -rpathFlagge tun
Kevin Tonon
10
Wenn Sie die Fehlermeldung erhalten : <binary>: no rpath or runpath tag found., können Sie es nicht verwenden chrpath, um es zu ersetzen, aber Sie können patchelfin diesem Fall verwenden:patchelf --set-rpath /path/to/libaries <binary>
Phyatt
Ich bevorzuge chrpath, wenn möglich, da Patchelf zwar universeller ist, aber einen langjährigen Fehler aufweist, der die Größe Ihrer Bibliotheken / ausführbaren Dateien dramatisch erhöht.
Taranaki
156

Es gibt ein universelleres Werkzeug als chrpathgenannt patchelf. Es wurde ursprünglich für die Erstellung von Paketen für Nix und NixOS (Verpackungssystem und eine GNU / Linux-Distribution) erstellt.

Falls in einer Binärdatei (hier rdsamp genannt) kein Pfad vorhanden ist, chrpathschlägt Folgendes fehl:

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

Andererseits,

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

gelingt ganz gut.

user7610
quelle
9
Insbesondere patchelfist es möglich, einen Pfad zu einer Binärdatei hinzuzufügen, die noch keinen Pfad enthält - wobei chrpathnur ein bereits vorhandener Eintrag geändert werden kann.
Maxschlepzig
4
Generell lohnt es sich, die subtile Unterscheidung zwischen rpathund zu verstehen runpath. Grundsätzlich kann einer überschreiben LD_LIBRARY_PATHund der andere nicht. Weitere Informationen finden Sie unter blog.tremily.us/posts/rpath
Stuart Berg
6
Das nervige ist, dass beide chrpathund patchelfmit ihrer Terminologie schlampig sind. Der patchelfoben gezeigte Befehl ändert sich beispielsweise, runpathjedoch nur, rpathwenn Sie auch die --force-rpathOption angeben.
Stuart Berg
10
@superbatfish Ja, aber der Unterschied spielt normalerweise keine Rolle. Dieser Eintrag vom CHANGELOG von patchelferklärt es: " --set-rpath, --shrink-rpathund --print-rpathjetzt lieber DT_RUNPATHüber DT_RPATH, die veraltet ist , wenn die Aktualisierung, wenn beide vorhanden sind, beide aktualisiert werden Wenn nur DT_RPATH vorhanden ist, wird es umgewandelt.. DT_RUNPATHEs sei denn , --force-rpathangegeben Wenn keiner vorhanden ist. wird a DT_RUNPATHhinzugefügt, sofern --force-rpathnicht anders angegeben. In diesem Fall DT_RPATHwird a hinzugefügt. " Der Name der Option wurde wahrscheinlich aus Kompatibilitätsgründen unverändert beibehalten.
user7610
2
Bei weitem die beste Antwort, dies sollte stattdessen die akzeptierte Antwort sein!
Kenneth Hoste
12

Genau wie @ user7610 sagte, ist der richtige Weg der patchelf Werkzeug.

Ich bin jedoch der Meinung, dass ich eine umfassendere Antwort geben kann, die alle Befehle abdeckt, die erforderlich sind, um genau das zu tun.

Für einen umfassenden Artikel zu diesem Thema klicken Sie hier

Zunächst sprechen viele Entwickler darüber RPATH, aber sie meinen es tatsächlichRUNPATH . Dies sind zwei verschiedene optionale dynamische Abschnitte, die vom Lader sehr unterschiedlich behandelt werden. Sie können mehr über den Unterschied zwischen ihnen in dem Link lesen, den ich zuvor erwähnt habe.

Denken Sie vorerst daran:

  • Wenn RUNPATHgesetzt, RPATHwird ignoriert
  • RPATH ist veraltet und sollte vermieden werden
  • RUNPATH wird bevorzugt, da es von überschrieben werden kann LD_LIBRARY_PATH

Siehe den aktuellen R [UN] -PFAD

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

Löschen Sie den R [UN] -PFAD

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

Anmerkungen:

  • Entfernt beide RPATHundRUNPATH

Addiere Werte zu R [UN] PATH

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

Anmerkungen:

  • <desired-path> ist eine durch Kommas getrennte Verzeichnisliste, z. /my/libs:/my/other/libs
  • Wenn Sie angeben --force-rpath, setzt RPATH, sonst setztRUNPATH
Daniel Trugman
quelle
1
-Wl,-R,<desired-rpath> -Wl,--enable-new-dtagssetzt DT_RUNPATH, und das ist das, was die meisten Leute verwenden sollten. RUNPATHkann von überschrieben werden LD_LIBRARY_PATH, daher sollten Leute nicht verwenden --force-rpath.
JWW
@jww Ich sehe, dass ich keinen Kommentar zur Ablehnung von RPATH hinzugefügt habe, also habe ich gerade einen hinzugefügt. Vielen Dank!
Daniel Trugman
Beachten Sie, dass im Beispiel <desired-path>ein Doppelpunkt verwendet wird. Es sollte ein Komma sein (dh :) /my/libs,/my/other/libs.
Alan De Smet
@AlanDeSmet, ich weiß nichts über das Komma, aber der Doppelpunkt funktioniert für mich.
Daniel Trugman
0

Dies funktionierte für mich und ersetzte XORIGIN durch $ ORIGIN.

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

Vikram Kedlaya
quelle