LINUX.ORG.RU

Проблема с динамическим линковщиком.


0

1

На пальцах проблема выглядит примерно так:
Имеются закрытые библиотеки без RPATH: libfoo.so, libbar.so и libaaa.so лежат в /opt/megacorp/lib.
libbar зависит от libaaa которая зависит от libfoo.
/opt/megacorp/lib не в системном LD_LIBRARY_PATH.
Наше приложение использует libaaa.so. Перед этим делает следующее:

  • setenv(LD_LIBRARY_PATH += «/opt/megacorp/lib»);
  • dlopen(«foo», RTLD_NOW | RTLD_GLOBAL); // Грузит без ошибок
  • dlopen(«bar», RTLD_NOW | RTLD_GLOBAL); --> тянет зависимостью libaaa.so --> тянет зависимостью libfoo.so --> здесь ld.so ругается что libfoo.so не найдена.

Если задать LD_LIBRARY_PATH += «/opt/megacorp/lib» в шеле, то в приложении dlopen вообще не нужен, всё отлично работает.

Вопросы:

  1. Почему линкер ищет libfoo.so в ФС, когда она же уже загружена?
  2. почему линкер может не находить либу при LD_LIBRARY_PATH заданном через setenv?

Требуется не решить проблему загрузки, а хотябы понять почему так происходит. Пожалуйста пишите любые идеи.

«+=» исключает всякий анализ ситуации.

Если интересно, посмотри исходники ld.so

tailgunner ★★★★★
()

Так в любом случае делать не надо, не предназначена для этого LD_LIBRARY_PATH. Сделайте sh-скрипт для запуска программы, и пусть он выставит нужный LD_LIBRARY_PATH.

Странно тут то, что ld находит libfoo. Посмотрите strace'ом, может, она на самом деле есть не только в /opt/megacorp/lib?

proud_anon ★★★★★
()

setenv(LD_LIBRARY_PATH += «/opt/megacorp/lib»); Это, простите, на каком языке? Вообще настраивать перменные окружения в самих программах - дурной тон из дурнейших.

Vamp
()

> /opt/megacorp/lib не в системном LD_LIBRARY_PATH.

что такое «системный» LD_LIBRARY_PATH? Ты про какую «систему» вообще говоришь?

setenv(LD_LIBRARY_PATH += «/opt/megacorp/lib»);

/0

Led ★★★☆☆
()

> почему линкер может не находить либу при LD_LIBRARY_PATH заданном через setenv?

Так он устроен — читает LD_LIBRARY_PATH один раз при запуске программы. Дальнейшие модификации не имеют эффекта.

Теперь по поводу зависимостей. Есть два варианта:

1. Библиотеки зависят формально друг от друга. То есть, команда

$ ldd libaaa.so
выдаёт
libfoo.so => not found

Это значит, что libaaa была задана в командной строке при линковке libfoo (что в принципе не обязательно, она бы слинковалась и так).
В этом случае ничего не сделать, надо проставлять LD_LIBRARY_PATH перед запуском программы.

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

dlopen(«/opt/megacorp/lib/libfoo.so», RTLD_NOW | RTLD_GLOBAL);
dlopen(«/opt/megacorp/lib/libaaa.so», RTLD_NOW | RTLD_GLOBAL);
dlopen(«/opt/megacorp/lib/libbar.so», RTLD_NOW | RTLD_GLOBAL);

libaaa подхватит символы уже загруженной libfoo, а libbar соответственно подхватит символы уже загруженной libaaa.

Так что решайте сами — или задавать LD_LIBRARY_PATH, или перелинковывать libaaa и libbar без прямых зависимостей.

ringill
()

Да, и насчёт

Почему линкер ищет libfoo.so в ФС, когда она же уже загружена?


Это из соображений безопасности делается, чтобы не позволить злоумышленнику подпихнуть свою libfoo. Из тех же соображений LD_LIBRARY_PATH игнорируется для процессов с setuid и setgid.

ringill
()

Спасибо всем отписавшимся. К сожалению почему мы видим именно такое поведение не понятно.

Про +=, я не код цитирую, я схему описал того что мы делаем.

Под системным LD_LIBRARY_PATH подразумеваю то что выставлено общесистемно в ld.so.conf.

Про дурной тон, оно, конечно понятно, будем либо ставить закрытые либы в linux-style в /usr/lib, либо делать обёртку, запускающую саму программу в правильном окружении с локальным LD_LIBRARY_PATH, заказчики пока над этим думают.

может, она на самом деле есть не только в /opt/megacorp/lib

К сожалению только там...

dmitry_kuzmenko
() автор топика
Ответ на: комментарий от ringill

>Так он устроен — читает LD_LIBRARY_PATH один раз при запуске программы. Дальнейшие модификации не имеют эффекта.

Видимо этот эффект мы и видим. Возможно libbar загружает libaaa через dlopen, а libaaa тянет libfoo неявно через формальные зависимости. В этом случае как раз работает ld.so который забивает на наш setenv.

Спасибо. Проверим более подробно.

dmitry_kuzmenko
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.