Могу ли я изменить 'rpath' в уже скомпилированном двоичном файле?


93

У меня есть старый исполняемый файл, который планируется отправить в кучу лома, но его еще нет. Он полагается на некоторые библиотеки, которые были удалены из моей среды, но у меня есть некоторые библиотеки-заглушки, где они работают нормально. Я хочу указать этот исполняемый файл на эти библиотеки-заглушки. Да, я мог бы установить LD_LIBRARY_PATH, но этот исполняемый файл вызывается из многих скриптов и многих пользователей, и я хотел бы исправить его в одном месте.

У меня нет источника для этого, и было бы трудно его получить. Я подумал - могу ли я отредактировать этот файл, используя редактор, поддерживающий ELF, и добавить простой PATH в rpath, чтобы он попал в новые библиотеки? Возможно ли это, или как только вы создаете двоичный файл ELF, вы фиксируете что-то в местах, и их нельзя перемещать?


3
Оберните его в сценарий оболочки, который устанавливает LD_LIBRARY_PATH и вызывает двоичный файл. Поместите сценарий оболочки в место в PATH вызывающего.
— wildplasser 07

LD_LIBRARY_PATH наследуется дочерними процессами. Возможно, вы этого не захотите.
— Уилл

1
@ да, и я уже сказал, что не хочу этого делать. :)
— Rich Homolka

Ответы:


79

Есть инструмент, 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 есть давняя ошибка, которая резко увеличивает размер ваших библиотек / исполняемых файлов.
— taranaki

@taranaki: О какой версии patchelf вы говорите?
— Хагелло

1
У chrpath есть серьезное ограничение: он может заменить RPATH только на один равной или меньшей длины (справочная страница rpath версии 0.16)
— hagello

162

Есть средство более универсальное, чем 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

удается просто отлично.


10
В частности, 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не указано Если ни присутствует. , DT_RUNPATHдобавляется a, если --force-rpathне указано иное, в этом случае DT_RPATHдобавляется a ". Название опции, вероятно, осталось без изменений из соображений совместимости.
— user7610 09

2
Безусловно, лучший ответ, это должен быть принятый ответ!
— Кеннет Хост

13

Как сказал @ user7610, правильный путь - это patchelfинструмент.

Но я чувствую, что могу дать более исчерпывающий ответ, охватывающий все команды, необходимые для этого.

Чтобы прочитать подробную статью по этому вопросу, нажмите здесь

Во-первых, многие разработчики говорят RPATH, но на самом деле имеют в виду RUNPATH. Это два разных необязательных динамических раздела, и загрузчик обрабатывает их по-разному. Вы можете узнать больше о разнице между ними в упомянутой ранее ссылке.

А пока просто помните:

  • Если RUNPATHустановлено, RPATHигнорируется
  • RPATH устарел, и его следует избегать
  • RUNPATH предпочтительнее, потому что он может быть отменен LD_LIBRARY_PATH

См. Текущий R [UN] PATH

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

Очистить ПУТЬ R [UN]

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, про запятую не знаю, но двоеточие у меня работает.
— Дэниел Тругман,

RPATH может быть устаревшим, но использование RUNPATH может привести к "неожиданным" угловым случаям. См., Например, qt.io/blog/2011/10/28/rpath-and-runpath .
— Роб

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.