Чи можу я змінити 'rpath' у вже складеному двійковому файлі?


92

У мене є старий виконуваний файл, який заплановано для сміття, але його ще немає. Це покладається на деякі бібліотеки, які були видалені з мого середовища, але у мене є деякі заглушені бібліотеки десь, де це чудово працює. Я хотів би спрямувати цей виконуваний файл на ці заглушки. Так, я міг би встановити LD_LIBRARY_PATH, але цей виконуваний файл викликається з багатьох сценаріїв, і багато користувачів, і я хотів би це виправити в одному місці.

У мене немає джерела для цього, і важко було б його отримати. Я думав - чи можу я відредагувати цей файл, використовуючи редактор, який усвідомлює ELF, і додати простий PATH до rpath, щоб він потрапив у нові бібліотеки? Чи можливо це, або коли ви створюєте двійковий файл ELF, ви фіксуєте речі в місцях, і їх неможливо перемістити?


3
Оберніть його в оболонку, яка встановлює LD_LIBRARY_PATH і викликає двійковий файл. Помістіть скрипт оболонки в місце, яке знаходиться в PATH абонента.
wildplasser

LD_LIBRARY_PATH успадковується дочірніми процесами. Можливо, ви цього не хочете.
Буде

1
@ буде так, і я вже сказав, що не хочу цього робити. :)
Rich Homolka

Відповіді:


78

Є інструмент, chrpathякий може це зробити - він, ймовірно, доступний у пакунках вашого дистрибутива.


9
Лише примітка для користувачів Mac, це install_name_toolможна зробити за допомогою -rpathпрапора
Кевін Тонон,

10
Якщо ви отримали помилку:, <binary>: no rpath or runpath tag found.ви не chrpathможете замінити її, але patchelfв цьому випадку ви можете використовувати :patchelf --set-rpath /path/to/libaries <binary>
phyatt

Я віддаю перевагу chrpath, якщо це можливо, оскільки, хоча це більш універсально, patchelf має деяку давню помилку, яка різко збільшує розмір ваших бібліотек / виконуваних файлів.
таранакі

157

Існує більш універсальний інструмент, ніж chrpathназивається patchelf. Спочатку він був створений для створення пакетів для Nix та NixOS (система упаковки та дистрибутив GNU / Linux).

Якщо в двійковому файлі немає rpath (тут називається rdsamp), chrpathпомилка:

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

З іншої сторони,

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

вдається просто чудово.


9
Особливо, patchelfвін може додати rpath до двійкового файлу, який не містить rpath, але - де chrpathлише, здається, може змінити вже наявний запис.
maxschlepzig

4
Як загальне зауваження, варто розуміти тонку різницю між rpathі runpath. В основному, одне може замінити, LD_LIBRARY_PATHа інше - ні. Детальніше див. Blog.tremily.us/posts/rpath
Стюарт Берг,

6
Прикро те, що обидва chrpathі patchelfнедбалі своєю термінологією. Наприклад, patchelfкоманда, показана вище, зміниться, runpathале лише rpathякщо ви також не вказали цю --force-rpathопцію.
Стюарт Берг,

10
@superbatfish Так, але різниця зазвичай не має значення. Цей запис із CHANGELOG patchelfпояснює це: " --set-rpath, --shrink-rpathі --print-rpathтепер віддайте перевагу DT_RUNPATHнад DT_RPATH, що застаріло. Під час оновлення, якщо присутні обидва, оновляються обидва. Якщо присутній лише DT_RPATH, він перетворюється на, DT_RUNPATHякщо --force-rpathне вказано. Якщо жоден не присутній , a DT_RUNPATHдодається, якщо --force-rpathне вказано, у цьому випадку DT_RPATHдодається a . " Ім'я опції, мабуть, залишалося незмінним з міркувань сумісності.
user7610

2
Безумовно найкраща відповідь, замість цього має бути прийнятою відповіддю!
Кеннет Хосте

12

Як сказав @ user7610, правильним шляхом є patchelfінструмент.

Але, я відчуваю, що можу дати більш вичерпну відповідь, охоплюючи всі команди, які потрібні, щоб зробити саме це.

Щоб отримати вичерпну статтю на цю тему, натисніть тут

Перш за все, багато розробників говорять про це RPATH, але насправді мають на увазі RUNPATH. Це дві різні необов’язкові динамічні секції, і навантажувач обробляє їх дуже по-різному. Детальніше про різницю між ними ви можете прочитати за посиланням, про яке я згадав раніше.

Наразі просто пам’ятайте:

  • Якщо RUNPATHвстановлено, RPATHігнорується
  • RPATH застаріло і його слід уникати
  • RUNPATH є кращим, оскільки його можна замінити LD_LIBRARY_PATH

Див. Поточний R [UN] PATH

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

Зніміть R [UN] PATH

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

Примітки:

  • Видаляє обидва RPATHіRUNPATH

Додайте значення до R [UN] PATH

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

Примітки:

  • <desired-path> - це список каталогів, розділених комами, наприклад: /my/libs:/my/other/libs
  • Якщо вказати --force-rpath, набори RPATH, інакше набориRUNPATH

1
-Wl,-R,<desired-rpath> -Wl,--enable-new-dtagsнабори DT_RUNPATH, і саме це слід використовувати більшості людей. RUNPATHможе бути замінено LD_LIBRARY_PATH, тому люди не повинні використовувати --force-rpath.
jww

@jww Я бачу, що я не додав коментар щодо припинення дії RPATH, тому я додав його щойно. Дякую!
Даніель Тругман,

Зверніть увагу, що в прикладі <desired-path>використовується двокрапка; це повинна бути кома (тобто:) /my/libs,/my/other/libs.
Алан Де Смет

@AlanDeSmet, я не знаю про кому, але двокрапка працює для мене.
Даніель Тругман,

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.