Компоновка с динамическими библиотеками [1]
Перед применением библиотеки необходимо выполнить 2 дополнительных шага, которые не требуются для работы со статическими аналогами:
1. Поскольку исполняемый файл не содержит копии необходимых объектных модулей, он должен иметь возможность определять, какая разделяемая библиотека требуется для работы. Для этого, на этапе статической компоновки, в ELF файл программы внедряется метка
DT_NEEDED с именем библиотеки.
Если говорить чуть более точно, то в поле
DT_NEEDED записывается полный путь до библиотеки. Если зависимость находится в неизвестном компоновщику каталоге, то лучше указать дорогу через флаг -L, иначе потом может возникнуть вопрос "Почему зависимость находится корректно при ее локальном размещении?" - потому что ее полый путь записан в поле
NEEDED.
$ gcc -Wall -o prog main.o -L=./libs/ -ldemo
// Выводим содержимое динамической секции ELF файла
$ readelf -d ./prog
Dynamic section at offset 0xd88 contains 28 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libdemo.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
2. Должен существовать механизм, который, во время выполнения программы, находит библиотеку по имени и выгружает ее в память, если она не была загружена ранее. Данная процедура выполняется динамическим компоновщиком и необходима для разрешения имени библиотеки на этапе выполнения.
Компоновщик, сам по себе, является разделяемой библиотекой “
/lib/ld-linux.so.2” и используется всеми исполняемыми файлами формата ELF, которые содержат динамические зависимости.
На самом деле, Id-linux.so.2 представляет собой обычную символическую ссылку на библиотеку динамического компоновщика “
Id-<version>.so” (например, ld-2.11. so), где version - это версия
glibc, которая установлена в системе.
Если на данном этапе попробовать запустить программу, выведется следующее сообщение об ошибке:
$ ./prog
./prog: error in loading shared libraries: libdemo.so:
cannot open shared object file: No such file or directory
Это возвращает нас ко второму пункту. Дело в том, что динамический компоновщик анализирует список рантайм зависимостей программы и находит соответствующие библиотечные файлы, используя набор заранее заданных правил.
Часть этих правил основывается на списке стандартных каталогов, в которых обычно хранятся разделяемые библиотеки (lib и /usr/lib). Причина ошибки выше заключается в том, что библиотека находится в текущем каталоге, который не учитывается при поиске.
Для оповещения динамического компоновщика о том, что разделяемая библиотека находится в нестандартном месте, можно воспользоваться переменной среды
LD_LIBRARY_PATH, указав соответствующий каталог в качестве значения.
Если переменная определена, компоновщик начинает поиск разделяемой библиотеки с тех каталогов, которые в ней перечислены, и только потом переходит к стандартным библиотечным путям.
Следовательно, можно запустить программу с помощью следующей команды:
$ LD_LIBRARY_PATH=./libs ./prog