Рис. 7.1. Формат объектного файла: представление компоновки и представление исполнения
Рис. 7.2. Схема распределения памяти для процесса (на архитектурах x86)
1. Если запрашиваемая разделяемая библиотека еще не загружена в память, ее загружает динамический компоновщик:
Если имя разделяемой библиотеки задано полностью (т. е. начинается с косой черты), она загружается прямо из указанного места. Если разделяемая библиотека в указанном месте отсутствует, дальнейший поиск не выполняется.
Если же путевое имя задано не полностью, динамический компоновщик выполняет поиск разделяемой библиотеки следующим образом:
а) Если динамическая секция исполняемого модуля содержит тег DT_RPATH, тогда поиск выполняется по пути, указанному в этом теге.
б) Если разделяемая библиотека не найдена, то динамический компоновщик ищет ее в каталогах, заданных переменной LD_LIBRARY_PATH, при условии, что программа не имеет атрибут setuid.
в) Если разделяемая библиотека все равно не найдена, тогда динамический компоновщик определяет путь поиска библиотеки по умолчанию, который задан модулю procnto посредством переменной окружения LD_LIBRARY_PATH (т.е. в строке конфигурации CS_LIBPATH). Если данная переменная окружения не определена, тогда путь поиска библиотеки по умолчанию задается как путь к образной файловой системе.
2. После обнаружения запрошенной разделяемой библиотеки, она загружается в память. Для разделяемых библиотек формата ELF эта операция очень эффективна, так как динамическому компоновщику нужно всего лишь два раза использовать вызов mmap() для того, чтобы отобразить два загружаемых сегмента в памяти.
3. Затем разделяемая библиотека добавляется во внутренний список всех библиотек, которые были загружены данным процессом. Список составляется динамическим компоновщиком.
4. Далее динамический компоновщик декодирует динамическую секцию разделяемого объекта.
Замечание
1. Разделяемая библиотека.
2. Список библиотек, заданный переменной окружения LD_PRELOAD. Эта переменная окружения может использоваться для добавления или изменения функциональности при запуске программы. Для двоичных модулей ELF с установленным битом setuid или setgid будут загружаться только библиотеки, расположенные в стандартных каталогах поиска и так же имеющие установленный бит setuid или setgid.
3. Глобальный список.
4. Все зависимые объекты, на которые ссылается разделяемая библиотека (т. е. любые другие библиотеки, с которыми данная библиотека связана).
Когда программа загружает новую библиотеку, она может дать динамическому компоновщику инструкцию поместить идентификаторы, содержащиеся в этой библиотеке, в глобальный список посредством передачи вызову dlopen() флага RTLD_GLOBAL. В результате все идентификаторы данной библиотеки станут доступными для всех библиотек, которые впоследствии будут загружены.
Список объектов для поиска при разрешении идентификаторов, содержащихся в разделяемой библиотеке, может быть изменен. Если флаг RTLD_GROUP передается вызову dlopen(), тогда поиск идентификаторов будет осуществляться только в тех объектах, на которые библиотека непосредственно ссылается. Если передается флаг RTLD_WORLD, тогда поиск осуществляется только в объектах, перечисленных в глобальном списке.