Как сделать так, чтобы $ORIGIN в RPATH не следовал символьным ссылкам?

Вопрос или проблема

У меня есть исполняемый app, который зависит от библиотеки libbar.so и загружает ее через RPATH с помощью $ORIGIN следующим образом:

$ readelf -d app

Секция динамической информации по смещению 0xe08 содержит 26 записей:
  Тег        Тип                            Имя/Значение
 0x0000000000000001 (NEEDED)                Общая библиотека: [libbar.so]
 0x0000000000000001 (NEEDED)                Общая библиотека: [libc.so.6]
 0x000000000000000f (RPATH)                 Путь к библиотеке rpath: [$ORIGIN/lib/]

Было бы неплохо запустить его в соответствующей структуре каталогов, созданной с помощью символических ссылок на исполняемый файл и libbar.so:

$ ls -R
.:
app@  lib/

./lib:
libbar.so@

— но линковщик следует за символическими ссылками на оригинальный файл исполняемого файла, устанавливает $ORIGIN на директорию исполняемого файла и решает пути зависимостей оттуда. Можно ли заставить его не делать этого? Так, чтобы в плане каталогов, при поиске файлов библиотек, символические ссылки рассматривались как реальные файлы файловой системы (“конечные точки” поиска).

Также некоторые размышления по этой проблеме:

  1. Удобно иметь бинарники, настроенные на поиск зависимостей в нескольких связанных директориях, например, в $ORIGIN/ самого бинарника, а также в $ORIGIN/appname_dependencies/ (так что можно просто скопировать бинарник и его зависимости в одну директорию и запустить его, но также иметь резервный вариант для более сложной настройки с несколькими версиями одного и того же бинарника в системе).

  2. Из-за требования нескольких путей поиска зависимостей, RPATH является методом поиска, который нужно использовать: “разделенное” имя зависимости (NEEDED Shared library: [./libbar.so]) устанавливает только 1 путь поиска. Также, для простоты пути разрешения зависимостей должны находиться в самом бинарнике.

  3. Приятно иметь возможность объединить все бинарники (приложение и все его зависимости) в полный граф зависимостей с ссылками, вместо копирования файлов. А символические ссылки более устойчивы, чем жесткие ссылки: они связывают между файловыми системами. На самом деле, у меня есть эта проблема в одной академической среде Linux-кластера, где нельзя создать жесткую ссылку на родительский каталог:

        $ ln ../afile 
        ln: создание жесткой ссылки `./afile' => `../afile': Недопустимая перекрестная ссылка между устройствами
    

Если вы действительно хотите смешивать символические ссылки таким образом, вы можете построить конфигурацию следующего типа:

  • переместите ваш исполняемый файл в его собственный каталог
  • создайте символическую ссылку из “нормального” местоположения на перемещенный исполняемый файл
  • создайте символические ссылки в каталоге исполняемого файла на общие библиотеки, которые вы хотите разрешить

Ответ или решение

Для решения проблемы, связанной с тем, что $ORIGIN в RPATH следует символьным ссылкам на исполняемый файл, необходимо учитывать, что система динамической линковки в Linux обрабатывает символические ссылки, что влияет на путь поиска библиотек. К сожалению, стандартными средствами вы не можете изменить это поведение напрямую, так как оно является частью спецификации ELF и динамического линковщика, но есть несколько обходных путей для достижения желаемого результата.

Возможные решения:

  1. Создание специальной структуры каталогов:
    Чтобы обойти проблему, вы можете создать специализированную структуру каталогов. Например:
    • Переместите исполняемый файл app в отдельный каталог.
    • Создайте символическую ссылку на этот исполняемый файл в нужном месте.
    • В каталоге, где будет находиться исполняемый файл, создайте символические ссылки на необходимые библиотеки, такие как libbar.so.

Пример структуры каталогов:

/path/to/your/app_directory/
    ├── app (исполнимый файл)
    ├── lib/
    │   └── libbar.so (символическая ссылка)
  1. Использование RPATH с фиксированным путем:
    Вместо использования $ORIGIN, вы можете жестко прописать полный путь к библиотекам в RPATH. Хотя это решение снижает гибкость переносимости вашего приложения, оно полностью исключает возможность следования символьным ссылкам.

  2. Использование RUNPATH вместо RPATH:
    Если ваша система поддерживает RUNPATH, вы могли бы попробовать использовать его, так как он имеет более высокий приоритет и предоставляет больше контроля над порядком поиска. Однако, это не гарантирует полное исключение следования символьным ссылкам, и может работать не во всех случаях.

  3. Использование chrpath или patchelf для изменения RPATH:
    Вы можете изменить RPATH после компиляции с помощью утилит chrpath или patchelf, чтобы указать более специфичные пути для библиотек. Вы можете добавить относительные пути без использования $ORIGIN, однако это решение требует дальнейшего анализа и тестирования.

Заключение:

К сожалению, полностью контролировать поведение динамической линковки и запретить следование символьным ссылкам для $ORIGIN невозможно в рамках стандартного функционала. Наилучший способ – использовать структуру каталогов с физическими копиями библиотек или жестко прописанные пути для RPATH. Выбор подхода зависит от ваших требований к переносимости и удобству установки приложения.

Оцените материал
Добавить комментарий

Капча загружается...