.\" -*- coding: UTF-8 -*- .\" Copyright 1995 Yggdrasil Computing, Incorporated. .\" written by Adam J. Richter (adam@yggdrasil.com), .\" with typesetting help from Daniel Quinlan (quinlan@yggdrasil.com). .\" and Copyright 2003, 2015 Michael Kerrisk .\" .\" %%%LICENSE_START(GPLv2+_DOC_FULL) .\" This is free documentation; you can redistribute it and/or .\" modify it under the terms of the GNU General Public License as .\" published by the Free Software Foundation; either version 2 of .\" the License, or (at your option) any later version. .\" .\" The GNU General Public License's references to "object code" .\" and "executables" are to be interpreted as the output of any .\" document formatting or typesetting system, including .\" intermediate and printed output. .\" .\" This manual is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public .\" License along with this manual; if not, see .\" . .\" %%%LICENSE_END .\" .\" Modified by David A. Wheeler 2000-11-28. .\" Applied patch by Terran Melconian, aeb, 2001-12-14. .\" Modified by Hacksaw 2003-03-13. .\" Modified by Matt Domsch, 2003-04-09: _init and _fini obsolete .\" Modified by Michael Kerrisk 2003-05-16. .\" Modified by Walter Harms: dladdr, dlvsym .\" Modified by Petr Baudis , 2008-12-04: dladdr caveat .\" .\"******************************************************************* .\" .\" This file was generated with po4a. Translate the source file. .\" .\"******************************************************************* .TH DLOPEN 3 "1 ноября 2020 г." Linux "Руководство программиста Linux" .SH ИМЯ dlclose, dlopen, dlmopen \- открывает и закрывает общий объект .SH СИНТАКСИС \fB#include \fP .PP \fBvoid *dlopen(const char *\fP\fIfilename\fP\fB, int \fP\fIflags\fP\fB);\fP .PP \fBint dlclose(void *\fP\fIhandle\fP\fB);\fP .PP \fB#define _GNU_SOURCE\fP .br \fB#include \fP .PP \fBvoid *dlmopen(Lmid_t \fP\fIlmid\fP\fB, const char *\fP\fIfilename\fP\fB, int \fP\fIflags\fP\fB);\fP .PP Компонуется при указании параметра \fI\-ldl\fP. .SH ОПИСАНИЕ .SS dlopen() Функция \fBdlopen\fP() загружает динамический общий объект (общую библиотеку) из файла, имя которого указано в строке \fIfilename\fP (завершается null) и возвращает скрытный описатель на загруженный объект. Данный описатель используется другими функциями программного интерфейса dlopen, такими как \fBdlsym\fP(3), \fBdladdr\fP(3), \fBdlinfo\fP(3) и \fBdlclose\fP(). .PP .\" FIXME On Solaris, when handle is NULL, we seem to get back .\" a handle for (something like) the root of the namespace. .\" The point here is that if we do a dlmopen(LM_ID_NEWLM), then .\" the filename==NULL case returns a different handle than .\" in the initial namespace. But, on glibc, the same handle is .\" returned. This is probably a bug in glibc. .\" Если \fIfilename\fP равно NULL, то возвращается описатель основной программы. Если \fIfilename\fP содержит косую черту («/»), то это воспринимается как имя с путём (относительным или абсолютным). Иначе динамический компоновщик ищет объект в следующих местах (подробности смотрите в \fBld.so\fP(8)): .IP o 4 (ELF only) If the calling object (i.e., the shared library or executable from which \fBdlopen\fP() is called) contains a DT_RPATH tag, and does not contain a DT_RUNPATH tag, then the directories listed in the DT_RPATH tag are searched. .IP o Если при запуске программы была определена переменная окружения \fBLD_LIBRARY_PATH\fP, содержащая список каталогов через двоеточие, то производится поиск в этих каталогах (по соображениям безопасности эта переменная игнорируется для программ с установленными битами set\-user\-ID и set\-group\-ID). .IP o (ELF only) If the calling object contains a DT_RUNPATH tag, then the directories listed in that tag are searched. .IP o Производится проверка в кэширующем файле \fI/etc/ld.so.cache\fP (обслуживается \fBldconfig\fP(8)) на предмет наличия записи для \fIfilename\fP. .IP o Просматриваются каталоги \fI/lib\fP и \fI/usr/lib\fP (именно в таком порядке). .PP Если объект, указанный \fIfilename\fP, зависит от других общих объектов, то они также автоматически загружаются динамическим компоновщиком согласно этим же правилам (процесс может выполняться рекурсивно, если эти объекты, в свою очередь, зависят от других, и так далее). .PP В \fIflags\fP должно быть одно из двух следующих значений: .TP \fBRTLD_LAZY\fP .\" commit 12b5b6b7f78ea111e89bbf638294a5413c791072 Выполнять позднее связывание (lazy binding). Выполняется поиск только тех символов, на которые есть ссылки из кода. Если на символ никогда не ссылаются, то он никогда не будет разрешён (позднее связывание выполняется только при ссылке на функции; ссылки на переменные всегда привязываются сразу при загрузке общего объекта). Начиная с libc 2.1.1, этот флаг заменяется на значение переменной окружения \fBLD_BIND_NOW\fP. .TP \fBRTLD_NOW\fP Если указано данное значение или переменная окружения \fBLD_BIND_NOW\fP не пуста, то все неопределённые символы в общем объекте ищутся до возврата из \fBdlopen\fP(). Если этого сделать не удаётся, то возвращается ошибка. .PP Также в В \fIflags\fP может быть ноль или более значение, объединяемых по ИЛИ: .TP \fBRTLD_GLOBAL\fP Символы, определённые в этом общем объекте, будут доступны при поиске символов, для общих объектов, загружаемых далее. .TP \fBRTLD_LOCAL\fP Противоположность \fBRTLD_GLOBAL\fP, используется по умолчанию, если не задано ни одного флага. Символы, определённые в этом общем объекте, не будут доступны при разрешении ссылок для общих объектов, загружаемых далее. .TP \fBRTLD_NODELETE\fP (начиная с glibc 2.2) Не выгружать общий объект при \fBdlclose\fP(). В результате статические и глобальные переменные объекта не инициализируются повторно, если объект загружается снова по \fBdlopen\fP(). .TP \fBRTLD_NOLOAD\fP (начиная с glibc 2.2) .\" Не загружать общий объект. Это можно использовать для тестирования того, что объект уже загружен (\fBdlopen\fP() возвращает NULL, если нет, или описатель объекта в противном случае). Данный флаг также можно использовать для изменения флагов уже загруженного объекта. Например, общий объект, который был загружен ранее с \fBRTLD_LOCAL\fP, можно открыть повторно с \fBRTLD_NOLOAD\ |\ RTLD_GLOBAL\fP. .TP \fBRTLD_DEEPBIND\fP (начиная с glibc 2.3.4) .\" Inimitably described by UD in .\" http://sources.redhat.com/ml/libc-hacker/2004-09/msg00083.html. Задать объекта, в котором поиск символов будет осуществляться перед поиском в области глобальных символов. Это означает, что самодостаточный объект будет использовать свои собственные символы вместо глобальных символов с тем же именем, содержащихся в объектах, которые уже были загружены. .PP If \fIfilename\fP is NULL, then the returned handle is for the main program. When given to \fBdlsym\fP(3), this handle causes a search for a symbol in the main program, followed by all shared objects loaded at program startup, and then all shared objects loaded by \fBdlopen\fP() with the flag \fBRTLD_GLOBAL\fP. .PP Поиск символьных ссылок общего объекта производится следующим образом (в таком порядке): символы в карте ссылок объектов, загруженных для главной программы и её зависимостей; символы в общих объектах (и их зависимостях), которые были открыты ранее с помощью \fBdlopen\fP() и флага \fBRTLD_GLOBAL\fP; определения в самом общем объекте (и любых зависимостях, которые были загружены для этого объекта). .PP Все глобальные символы в исполняемом файле, которые были помещены в его таблицу динамических символов посредством \fBld\fP(1), также могут быть использованы при поиске ссылок динамически загружаемого общего объекта. Символы могут попасть в таблицу динамических символов из\-за того, что исполняемый файл был скомпонован с флагом «\-rdynamic» (или его синонимом «\-\-export\-dynamic»), который помещает что все глобальные символы исполняемого файла в таблицу динамических символов, или из\-за того, что \fBld\fP(1) определил зависимость от символа из другого объекта при статической компоновке. .PP Если общий объект загружается с помощью \fBdlopen\fP() повторно, то возвращается тот же описатель на объект. Динамический компоновщик ведёт счётчик ссылок для описателей объектов, поэтому динамически загруженный общий объект не высвобождается \fBdlclose\fP() до тех пор, пока он не будет вызвана столько же раз сколько и \fBdlopen\fP(). Процедуры инициализации (смотрите ниже) вызываются только когда объект действительно загружается в память (т. е., когда счётчик ссылок увеличивается на 1). .PP Последующий вызов \fBdlopen\fP(), загружающий тот же общий объект с флагом \fBRTLD_NOW\fP, может привести к поиску символов для общего объекта ранее загруженного с флагом \fBRTLD_LAZY\fP. Схожим образом объект, открытый ранее с флагом \fBRTLD_LOCAL\fP, в последующем вызове \fBdlopen\fP() может быть преобразован в \fBRTLD_GLOBAL\fP. .PP .\" Если по какой\-то причине \fBdlopen\fP() завершается неудачно, то возвращается NULL. .SS dlmopen() Данная функция делает то же самое что и \fBdlopen\fP(), аргументы \fIfilename\fP и \fIflags\fP, а также возвращаемое значение — такие же, отличия описаны далее. .PP Функция \fBdlmopen\fP() отличается от \fBdlopen\fP(), главным образом в том, что имеет дополнительный аргумент \fIlmid\fP, в котором задаётся список карт связей (link\-map list, ещё называемый \fIпространством имён\fP), в который должен быть загружен общий объект (\fBdlopen\fP() добавляет динамически загружаемый общий объект в тоже пространство имён, в котором находится общий объект, из которого был вызван \fBdlopen\fP()). Тип \fILmid_t\fP является скрытым описателем, который ссылается на пространство имён. .PP .\" FIXME: Is using dlinfo() RTLD_DI_LMID the right technique? В аргументе \fIlmid\fP может быть указан ID существующего пространства имён (который может быть получен с помощью \fBdlinfo\fP(3) с запросом \fBRTLD_DI_LMID\fP) или одно из следующих специальных значений: .TP \fBLM_ID_BASE\fP Загрузить общий объект в начальное пространство имён (т. е., в пространство имён приложения). .TP \fBLM_ID_NEWLM\fP Создать новое пространство имён и загрузить в него общий объект. Объект должен быть корректно скомпонован с ссылками на все остальные общие объекты, которые ему требуются, так как новое пространство имён изначально пустое. .PP Если \fIfilename\fP равно NULL, то для \fIlmid\fP разрешено только значение \fBLM_ID_BASE\fP. .SS dlclose() Функция \fBdlclose\fP() уменьшает счётчик ссылок на динамически загружаемый общий объект, на который ссылается \fIhandle\fP. .PP Если счётчик ссылок достигает нуля и символы этого объекта не нужны другим объектам, то объект выгружается после первого вызова любого деструктора, определённого в объекте (символы в этом объекте могут требоваться в другом объекте из\-за того, что этот объект был открыт с флагом \fBRTLD_GLOBAL\fP и один из его символов совпадает с расположением из другого объекта). .PP Все общие объекты, которые были автоматически загружены при вызове \fBdlopen\fP() для объекта, на который ссылается \fIhandle\fP, рекурсивно закрываются таким же способом. .PP Успешный возврат из \fBdlclose\fP() не гарантирует, что символы, связанные с \fIhandle\fP удалятся из адресного пространства вызывающего. В дополнении к ссылкам, полученным из\-за явного вызова \fBdlopen\fP(), общий объект может быть загружен неявно (и увеличится счётчик ссылок), так как от него зависят другие общие объекты. Общий объект будет удалён из адресного пространства только когда будут удалены все ссылки на него. .SH "ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ" При успешном выполнении \fBdlopen\fP() и \fBdlmopen\fP() для загруженного объекта возвращают описатель не равный NULL. При ошибке (файл не найден, недоступен для чтения, имеет неправильный формат или возникли ошибке при загрузке) эти функции возвращают NULL. .PP При успешном выполнении \fBdlclose\fP() возвращает 0; при ошибке возвращается ненулевое значение. .PP Ошибки, возникшие в этих функциях, можно определить с помощью \fBdlerror\fP(3). .SH ВЕРСИИ Функции \fBdlopen\fP() и \fBdlclose\fP() имеются в glibc 2.0 и новее. Функция \fBdlmopen\fP() впервые появилась в glibc 2.3.4. .SH АТРИБУТЫ Описание терминов данного раздела смотрите в \fBattributes\fP(7). .TS allbox; lbw30 lb lb l l l. Интерфейс Атрибут Значение T{ \fBdlopen\fP(), \fBdlmopen\fP(), \fBdlclose\fP() T} Безвредность в нитях MT\-Safe .TE .SH "СООТВЕТСТВИЕ СТАНДАРТАМ" В POSIX.1\-2001 описаны \fBdlclose\fP() и \fBdlopen\fP(). Функция \fBdlmopen\fP() является расширением GNU. .PP Флаги \fBRTLD_NOLOAD\fP, \fBRTLD_NODELETE\fP и \fBRTLD_DEEPBIND\fP являются расширением GNU; первые два этих флага есть также в Solaris. .SH ЗАМЕЧАНИЯ .SS "Функция dlmopen() и пространства имён" Списком карты связей задаётся изолированное пространство имён для определения символов динамическим компоновщиком. Внутри пространства имён зависимые общие объекты неявно загружаются по обычным правилам, символьные ссылки разрешаются подобным образом, но при этом учитываются только те объекты, которые были загружены (явно и неявно) в пространство имён. .PP Функция \fBdlmopen\fP() позволяет достичь изоляции загружаемых объектов — загружает общий объект в новое пространство имён без показа символов всему приложению, а только новому объекту. Заметим, что использование флага \fBRTLD_LOCAL\fP недостаточно для этой цели, так как он делает недоступным символы общего объекта \fIлюбому\fP другому общему объекту. В некоторых случаях может понадобиться, чтобы символы динамически загружаемого общего объекта были доступны другим общим объектам (но не всем объектам) без показа этих символов всему приложению. Этого можно достичь используя отдельное пространство имён и флаг \fBRTLD_GLOBAL\fP. .PP Функцию \fBdlmopen\fP() также можно использовать для получения изолированности, большей чем с флагом \fBRTLD_LOCAL\fP. В частности, общие объекты, загруженные с \fBRTLD_LOCAL\fP, могут быть видимы при флаге \fBRTLD_GLOBAL\fP, если они зависят от другого общего объекта, загруженного с флагом \fBRTLD_GLOBAL\fP. То есть, \fBRTLD_LOCAL\fP недостаточно изолирует загружаемый общий объект, за исключением случая (редкого), где он явно контролирует зависимости всех загружаемых общих объектов. .PP Возможный случай применения \fBdlmopen\fP() — модули, где автор инфраструктуры модулей не может доверять авторам модулей и не хочет, чтобы все неопределённые символы инфраструктуры модулей определялись из модулей. Другой случай использования — загрузка одного объекта несколько раз. Без \fBdlmopen\fP() это потребовало бы создание отдельных копий файлов общего объекта. С помощью \fBdlmopen\fP() можно загрузить один файл общего объекта в разные пространства имён. .PP .\" DL_NNS .\" В реализации glibc поддерживается до 16 пространств имён. .SS "Функции инициализации и завершения" .\" info gcc "C Extensions" "Function attributes" Общие объекты могут экспортировать с помощью атрибутов функций \fB__attribute__((constructor))\fP и \fB__attribute__((destructor))\fP. Функции\-конструкторы выполняются перед возвратом из \fBdlopen\fP(), а функции\-деструкторы выполняются перед возвратом из \fBdlclose\fP(). Общий объект может экспортировать несколько конструкторов и деструкторов, с каждой функцией может быть связан приоритет, которым определяется порядок выполнения функций. Подробней смотрите info\-страницу \fBgcc\fP (раздел «Атрибуты функции»). .PP Старым способом достижения того же (частично) результата является использование двух специальных символов, распознаваемых компоновщиком: \fB_init\fP и \fB_fini\fP. Если динамически загружаемый общий объект экспортирует процедуру с именем \fB_init\fP(), то её код выполняется после загрузки общего объекта, но возвращения из \fBdlopen\fP(). Если общий объект экспортирует процедуру с именем \fB_fini\fP(), то её код выполняется перед выгрузкой объекта. В этом случае не должна выполняться компоновка с системными файлами начального запуска, в которых содержатся версии по умолчанию этих файлов; для этого нужно вызывать \fBgcc\fP(1) с параметром командной строки \fI\-nostartfiles\fP. .PP .\" .\" Using these routines, or the gcc .\" .B \-nostartfiles .\" or .\" .B \-nostdlib .\" options, is not recommended. .\" Their use may result in undesired behavior, .\" since the constructor/destructor routines will not be executed .\" (unless special measures are taken). .\" .\" void _init(void) __attribute__((constructor)); .\" .\" void _fini(void) __attribute__((destructor)); .\" Использование \fB_init\fP и \fB_fini\fP теперь не рекомендуется, используйте упомянутые конструкторы и деструкторы, которые, среди прочих преимуществ, позволяют определять многократно вызываемые функции инициализации и завершения. .PP Начиная с glibc 2.2.3, \fBatexit\fP(3) может использоваться для регистрации обработчика завершения работы, который автоматически вызывается при выгрузке общего объекта. .SS История Эти функции являются часть программного интерфейса dlopen, возникшего в SunOS. .SH ДЕФЕКТЫ .\" dlerror(): "invalid mode" .\" https://sourceware.org/bugzilla/show_bug.cgi?id=18684 В glibc 2.24 указание флага \fBRTLD_GLOBAL\fP при вызове \fBdlmopen\fP() приводит к ошибке. Кроме этого, указание \fBRTLD_GLOBAL\fP при вызове \fBdlopen\fP() приводит к падению программы (\fBSIGSEGV\fP), если вызов делается из любого объекта, загруженного в пространство имён, отличное от начального пространства имён. .SH ПРИМЕРЫ Программа, представленная ниже, загружает библиотеку math (glibc), ищет адрес функции \fBcos\fP(3) и печатает косинус 2.0. Пример сборки и выполнения программы: .PP .in +4n .EX $ \fBcc dlopen_demo.c \-ldl\fP $ \fB./a.out\fP \-0.416147 .EE .in .SS "Исходный код программы" \& .EX #include #include #include #include /* определение LIBM_SO (который является строкой вида libm.so.6») */ int main(void) { void *handle; double (*cosine)(double); char *error; handle = dlopen(LIBM_SO, RTLD_LAZY); if (!handle) { fprintf(stderr, "%s\en", dlerror()); exit(EXIT_FAILURE); } dlerror(); /* Очистка всех результатов ошибок */ cosine = (double (*)(double)) dlsym(handle, "cos"); /* According to the ISO C standard, casting between function pointers and \(aqvoid *\(aq, as done above, produces undefined results. POSIX.1\-2001 and POSIX.1\-2008 accepted this state of affairs and proposed the following workaround: *(void **) (&cosine) = dlsym(handle, "cos"); Такое (топорное) преобразование удовлетворяет стандарту ISO C и предупреждений компилятора не будет. .\" http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html#tag_03_112_08 .\" http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html#tag_16_96_07 .\" http://austingroupbugs.net/view.php?id=74 The 2013 Technical Corrigendum 1 to POSIX.1\-2008 improved matters by requiring that conforming implementations support casting \(aqvoid *\(aq to a function pointer. Nevertheless, some compilers (e.g., gcc with the \(aq\-pedantic\(aq option) may complain about the cast used in this program. */ error = dlerror(); if (error != NULL) { fprintf(stderr, "%s\en", error); exit(EXIT_FAILURE); } printf("%f\en", (*cosine)(2.0)); dlclose(handle); exit(EXIT_SUCCESS); } .EE .SH "СМ. ТАКЖЕ" \fBld\fP(1), \fBldd\fP(1), \fBpldd\fP(1), \fBdl_iterate_phdr\fP(3), \fBdladdr\fP(3), \fBdlerror\fP(3), \fBdlinfo\fP(3), \fBdlsym\fP(3), \fBrtld\-audit\fP(7), \fBld.so\fP(8), \fBldconfig\fP(8) .PP Страницы в формате Info для gcc и ld .SH ЗАМЕЧАНИЯ Эта страница является частью проекта Linux \fIman\-pages\fP версии 5.10. Описание проекта, информацию об ошибках и последнюю версию этой страницы можно найти по адресу \%https://www.kernel.org/doc/man\-pages/. .PP .SH ПЕРЕВОД Русский перевод этой страницы руководства был сделан Yuri Kozlov и Иван Павлов . .PP Этот перевод является бесплатной документацией; прочитайте .UR https://www.gnu.org/licenses/gpl-3.0.html Стандартную общественную лицензию GNU версии 3 .UE или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ. .PP Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на .MT man-pages-ru-talks@lists.sourceforge.net .ME .