• Библиотеки, определенные в файле /etc/ld.so.cache
. Этот файл генерируется программой ldcoding
, регистрирующей каждую библиотеку, которую она находит в каталоге, указанном в /etc/ld.so.conf
, во время ее выполнения.
• /usr/lib
• /lib
Если filename равен NULL
, то функция dlopen()
открывает экземпляр текущего исполняемого файла. Это полезно только в редких случаях. В случае сбоя функция dlopen()
возвращает NULL
.
Поиск файлов является простой частью работы функции dlopen()
; разрешение символов является более сложной задачей. Существует два фундаментально разных типа разрешения символов: немедленный (immediate) и отложенный (lazy). При немедленном разрешении функция dlopen()
разрешает все неразрешенные символы до возвращения результата; под отложенным разрешением подразумевается, что разрешение символов будет происходить по требованию.
Если большинство символов будет разрешено в самом конце, то гораздо эффективнее будет выполнить немедленное разрешение. Однако для библиотек со многими неразрешенными символами время, потраченное на разрешение символов, может оказаться продолжительным; если это существенно сказывается на вашем пользовательском интерфейсе, можно отдать предпочтение отложенному разрешению. Разница в общей эффективности будет незначительной.
Во время разработки и отладки вы практически во всех случаях будете использовать немедленное разрешение. Если ваши разделяемые объекты имеют неразрешенные символы, вам нужно будет знать об этом немедленно, а не тогда, когда в программе произойдет сбой во время выполнения кода, который на первый взгляд не будет иметь к этому отношения. Отложенное разрешение станет причиной сложно воспроизводимых ошибок, если вы не проверите свои разделяемые объекты сначала с немедленным разрешением.
Это особенно относится к тем случаям, когда вам необходимо, чтобы разделяемые объекты, зависящие от других разделяемых объектов, могли передавать некоторые свои символы. Если разделяемый объект А зависит от символа
в разделяемом объекте В, а В загружается после А, то отложенное разрешение
сможет быть выполнено только после загрузки объекта В, а до его загрузки — нет. Если написать код с немедленным разрешением, то вы сможете перехватить эту ошибку еще до того, как она сможет стать причиной возникновения проблем.
Здесь подразумевается, что загружать модули нужно всегда в обратном порядке по отношению к их зависимостям: если объект А зависит от объекта В в некоторых его символах, вы должны загрузить объект В до загрузки объекта А, и должны выгрузить объект А до выгрузки объекта B. К счастью, многие приложения с динамически загружаемыми разделяемыми объектами не имеют подобных взаимозависимостей.
По умолчанию символы в разделяемом объекте не экспортируются и потому не используются для разрешения символов в остальных разделяемых объектах. Они будут доступны только для их поиска и использования, о чем будет сказано в следующем разделе. Однако вы можете экспортировать все символы из одного разделяемого объекта во все остальные разделяемые объекты; эти символы будут доступны всем разделяемым объектам, которые будут загружены позже.
Управление всеми этими действиями осуществляется через аргумент flags
. Он должен иметь значение RTLD_LAZY
для отложенного разрешения и RTLD_NOW
для немедленного разрешения. Любое из этих значений может быть объединено битовым "ИЛИ" с RTLD_GLOBAL
, чтобы разрешить экспортирование символов в остальные модули.
Если разделяемый объект экспортирует программу _init
, то она будет выполняться до того, как функция dlopen()
вернет результат.
Функция dlopen()
возвращает dlsym()
и dlclose()
. Если разделяемый объект открывается несколько раз, функция dlopen()
каждый раз будет возвращать один и тот же дескриптор, и с каждым новым вызовом счетчик ссылок будет увеличиваться на единицу.
Функция dlsym()
производит поиск символа в библиотеке:
void * dlsym(void * handle, char * symbol);