Posso cambiare 'rpath' in un binario già compilato?


92

Ho un vecchio eseguibile programmato per l'heap di scarto, ma non è ancora lì. Si basa su alcune librerie che sono state rimosse dal mio ambiente, ma ho alcune librerie stub da qualche parte in cui funziona bene. Vorrei indicare questo eseguibile a queste librerie stub. Sì, potrei impostare LD_LIBRARY_PATH, ma questo eseguibile è chiamato da molti script e molti utenti e mi piacerebbe risolverlo in un punto.

Non ho una fonte per questo e sarebbe difficile ottenerlo. Stavo pensando: posso modificare questo file, usando un editor compatibile con ELF, e aggiungere un semplice PATH a rpath per farlo colpire le nuove librerie? È possibile, o una volta creato un binario ELF, aggiusti le cose alle posizioni e non possono essere spostate?


3
Avvolgilo in uno shellscript che imposta LD_LIBRARY_PATH e chiama il binario. Metti lo script di shell in una posizione che si trova nel PERCORSO del chiamante.
Wildplasser

LD_LIBRARY_PATH viene ereditato dai processi figlio. Potresti non volerlo.
Sarà il

1
@ sì e ho già detto che non voglio farlo. :)
Rich Homolka

Risposte:


78

C'è uno strumento chiamato chrpathche può farlo - è probabilmente disponibile nei pacchetti della tua distribuzione.


9
Solo una nota per gli utenti Mac, install_name_toolpuò farlo con la -rpathbandiera
Kevin Tonon

10
Se ottieni l'errore <binary>: no rpath or runpath tag found.chrpathpatchelfpatchelf --set-rpath /path/to/libaries <binary>
:,

Preferisco chrpath se possibile poiché, sebbene sia più universale, patchelf ha qualche bug di vecchia data che gonfia drasticamente la dimensione delle tue librerie / eseguibili.
taranaki

158

C'è uno strumento più universale di quello chrpathchiamato patchelf. È stato originariamente creato per essere utilizzato nella creazione di pacchetti per Nix e NixOS (sistema di pacchettizzazione e distribuzione GNU / Linux).

Nel caso in cui non ci sia rpath in un binario (qui chiamato rdsamp), chrpathfallisce:

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

D'altro canto,

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

riesce benissimo.


9
In particolare, patchelfè in grado di aggiungere un rpath a un binario che non contiene ancora un rpath, dove chrpathsembra solo essere in grado di modificare una voce già presente.
maxschlepzig

4
Come nota generale, vale la pena comprendere la sottile distinzione tra rpathe runpath. Fondamentalmente, uno può sovrascrivere LD_LIBRARY_PATHe l'altro no. Per i dettagli, vedere blog.tremily.us/posts/rpath
Stuart Berg,

6
La cosa fastidiosa è che entrambi chrpathe patchelfsono sciatti con la loro terminologia. Ad esempio, il patchelfcomando mostrato sopra cambierà runpathma non a rpathmeno che tu non fornisca anche l' --force-rpathopzione.
Stuart Berg

10
@superbatfish Sì, ma la differenza di solito non ha importanza. Questa voce dal CHANGELOG di patchelfspiega: " --set-rpath, --shrink-rpathe --print-rpathora preferisco DT_RUNPATHrispetto a DT_RPATH, che è obsoleto. Durante l'aggiornamento, se sono presenti entrambi, vengono aggiornati entrambi. Se è presente solo DT_RPATH, viene convertito in a DT_RUNPATHmeno che non --force-rpathsia specificato. Se nessuno dei due è presente , a DT_RUNPATHviene aggiunto a meno che non --force-rpathsia specificato, nel qual caso DT_RPATHviene aggiunto a. " Il nome dell'opzione è stato probabilmente mantenuto invariato per motivi di compatibilità.
user7610

2
Di gran lunga la risposta migliore, questa dovrebbe essere invece la risposta accettata!
Kenneth Hoste

12

Proprio come ha detto @ user7610, la strada giusta da percorrere è lo patchelfstrumento.

Ma sento di poter dare una risposta più esauriente, coprendo tutti i comandi necessari per fare esattamente questo.

Per un articolo completo sull'argomento, fare clic qui

Prima di tutto, molti sviluppatori ne parlano RPATH, ma in realtà intendono RUNPATH. Si tratta di due diverse sezioni dinamiche opzionali e il caricatore le gestisce in modo molto diverso. Puoi leggere di più sulla differenza tra loro nel link che ho menzionato prima.

Per ora, ricorda:

  • Se RUNPATHè impostato, RPATHviene ignorato
  • RPATH è deprecato e dovrebbe essere evitato
  • RUNPATH è preferito perché può essere sovrascritto da LD_LIBRARY_PATH

Vedere l'attuale R [UN] PATH

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

Cancella il R [UN] PATH

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

Appunti:

  • Rimuove sia RPATHeRUNPATH

Aggiungi valori a R [UN] PATH

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

Appunti:

  • <desired-path> è un elenco di directory separate da virgole, ad esempio: /my/libs:/my/other/libs
  • Se specifichi --force-rpath, imposta RPATH, altrimenti impostaRUNPATH

1
-Wl,-R,<desired-rpath> -Wl,--enable-new-dtagsset DT_RUNPATH, e questo è quello che la maggior parte delle persone dovrebbe usare. RUNPATHpuò essere sovrascritto da LD_LIBRARY_PATH, quindi le persone non dovrebbero usare --force-rpath.
jww

@jww Vedo che non ho aggiunto un commento sulla deprecazione di RPATH, quindi ne ho aggiunto uno proprio ora. Grazie!
Daniel Trugman

Notare che l'esempio <desired-path>utilizza i due punti; dovrebbe essere una virgola (ovvero:) /my/libs,/my/other/libs.
Alan De Smet

@AlanDeSmet, non so della virgola, ma i due punti funzionano per me.
Daniel Trugman

0

Questo ha funzionato per me, sostituendo XORIGIN con $ ORIGIN.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.