Czy mogę zmienić „rpath” w już skompilowanym pliku binarnym?


93

Mam stary plik wykonywalny zaplanowany na stertę złomu, ale jeszcze go tam nie ma. Opiera się na niektórych bibliotekach, które zostały usunięte z mojego środowiska, ale mam kilka bibliotek zastępczych gdzieś, gdzie działa dobrze. Chciałbym wskazać ten plik wykonywalny na te biblioteki zastępcze. Tak, mógłbym ustawić LD_LIBRARY_PATH, ale ten plik wykonywalny jest wywoływany z wielu skryptów i wielu użytkowników i chciałbym to naprawić w jednym miejscu.

Nie mam źródła tego i trudno byłoby to zdobyć. Zastanawiałem się - czy mogę edytować ten plik, używając edytora obsługującego ELF i dodać prostą PATH do rpath, aby trafił do nowych bibliotek? Czy to możliwe, czy po utworzeniu pliku binarnego ELF naprawiasz rzeczy w lokalizacjach i nie można ich przenieść?


3
Umieść go w skrypcie powłoki, który ustawia LD_LIBRARY_PATH i wywołuje plik binarny. Umieść skrypt powłoki w miejscu, które jest w PATH wywołującego.
wildplasser

LD_LIBRARY_PATH jest dziedziczona przez procesy potomne. Możesz tego nie chcieć.
Będzie

1
@Will yeah that i już powiedziałem, że nie chcę tego robić. :)
Rich Homolka

Odpowiedzi:


79

Jest narzędzie o nazwie, chrpathktóre może to zrobić - prawdopodobnie jest dostępne w pakietach twojej dystrybucji.


9
Tylko uwaga dla użytkowników komputerów Mac, install_name_toolmogą to zrobić za pomocą -rpathflagi
Kevin Tonon,

10
Jeśli pojawi się błąd <binary>: no rpath or runpath tag found.chrpathpatchelfpatchelf --set-rpath /path/to/libaries <binary>
:,

Preferuję chrpath, jeśli to możliwe, ponieważ chociaż jest bardziej uniwersalny, patchelf ma jakiś długo istniejący błąd, który dramatycznie zwiększa rozmiar twoich bibliotek / plików wykonywalnych.
taranaki

@taranaki: O której wersji patchelf mówisz?
hagello

1
chrpath ma poważne ograniczenie: może zastąpić RPATH tylko taką o równej lub krótszej długości (strona
podręcznika rpath w

161

Istnieje bardziej uniwersalne narzędzie niż chrpathzwane patchelf. Pierwotnie został stworzony do tworzenia pakietów dla Nix i NixOS (system pakowania i dystrybucja GNU / Linux).

W przypadku braku rpath w pliku binarnym (zwanym tutaj rdsamp), chrpathkończy się niepowodzeniem:

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

Z drugiej strony,

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

udaje się dobrze.


10
W szczególności patchelfjest w stanie dodać rpath do pliku binarnego, który jeszcze nie zawiera rpath - gdzie chrpathtylko wydaje się, że jest w stanie zmodyfikować już istniejący wpis.
maxschlepzig

4
Ogólnie warto zrozumieć subtelne rozróżnienie między rpathi runpath. Zasadniczo jeden może zastąpić, LD_LIBRARY_PATHa drugi nie. Aby uzyskać szczegółowe informacje, patrz blog.tremily.us/posts/rpath
Stuart Berg

6
Irytujące jest to, że obaj chrpathi patchelfsą niedbali w swojej terminologii. Na przykład patchelfpolecenie pokazane powyżej zmieni się, runpathale nie, rpathchyba że podasz również --force-rpathopcję.
Stuart Berg

10
@superbatfish Tak, ale różnica zwykle nie ma znaczenia. Ten wpis z changelogu z patchelfwyjaśnia: " --set-rpath, --shrink-rpatha --print-rpathteraz wolą DT_RUNPATHciągu DT_RPATH, który jest przestarzały podczas aktualizacji, jeśli oba są obecne, oba są aktualizowane Jeśli tylko DT_RPATH jest obecny, to przekształca się.. DT_RUNPATHChyba że --force-rpathokreślono Jeśli nie jest obecny. , DT_RUNPATHdodaje się a, chyba że --force-rpathokreślono, w którym to przypadku DT_RPATHdodaje się a. " Nazwa opcji prawdopodobnie pozostała niezmieniona ze względu na kompatybilność.
user7610,

2
Zdecydowanie najlepsza odpowiedź, zamiast tego powinna być zaakceptowana!
Kenneth Hoste

13

Tak jak powiedział @ user7610, właściwą drogą jest patchelf narzędzie.

Ale czuję, że mogę udzielić bardziej kompleksowej odpowiedzi, obejmującej wszystkie polecenia, których potrzeba, aby to zrobić.

Aby uzyskać obszerny artykuł na ten temat, kliknij tutaj

Przede wszystkim wielu programistów mówi o tym RPATH, ale tak naprawdę mają na myśliRUNPATH . Są to dwie różne opcjonalne sekcje dynamiczne, które są obsługiwane przez program ładujący w różny sposób. Więcej o różnicy między nimi przeczytasz w linku, o którym wspomniałem wcześniej.

Na razie pamiętaj tylko:

  • Jeśli RUNPATHjest ustawione,RPATH jest ignorowana
  • RPATH jest przestarzały i należy go unikać
  • RUNPATH jest preferowany, ponieważ można go zastąpić LD_LIBRARY_PATH

Zobacz aktualną ŚCIEŻKĘ R [UN]

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

Wyczyść R [UN] PATH

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

Uwagi:

  • Usuwa zarówno RPATHiRUNPATH

Dodaj wartości do R [UN] PATH

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

Uwagi:

  • <desired-path> to lista katalogów oddzielonych przecinkami, np .: /my/libs:/my/other/libs
  • Jeśli określisz --force-rpath, ustawia RPATH, w przeciwnym razie ustawiaRUNPATH

1
-Wl,-R,<desired-rpath> -Wl,--enable-new-dtagszestawy DT_RUNPATHi to jest ten, którego większość ludzi powinna używać. RUNPATHmoże zostać zastąpiony przez LD_LIBRARY_PATH, więc ludzie nie powinni używać --force-rpath.
jww

@jww Widzę, że nie dodałem komentarza o wycofaniu RPATH, więc dodałem jeden przed chwilą. Dzięki!
Daniel Trugman

Zauważ, że w przykładzie <desired-path>użyto dwukropka; powinien to być przecinek (czyli:) /my/libs,/my/other/libs.
Alan De Smet

@AlanDeSmet, nie wiem o przecinku, ale dwukropek działa dla mnie.
Daniel Trugman

RPATH może być przestarzałe, ale użycie RUNPATH może prowadzić do „nieoczekiwanych” przypadków narożnych. Zobacz na przykład qt.io/blog/2011/10/28/rpath-and-runpath .
Rob

0

To zadziałało dla mnie, zastępując XORIGIN $ ORIGIN.

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.