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

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

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

Ответ 1

Существует инструмент chrpath, который может это сделать - он, вероятно, доступен в ваших дистрибутивных пакетах.

Ответ 2

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

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

Ответ 3

Как сказал @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

Ответ 4

Это сработало для меня, заменив XORIGIN на $ORIGIN.

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