К сожалению, официальной документацией является исходный код. Большинство дистрибутивов Linux используют glibc или его ответвление, eglibc. В исходном коде обоих файлов файл, который должен документировать dlopen(), выглядит следующим образом:
руководство/libdl.texi
@c FIXME these are undocumented:
@c dladdr
@c dladdr1
@c dlclose
@c dlerror
@c dlinfo
@c dlmopen
@c dlopen
@c dlsym
@c dlvsym
Какие технические спецификации существуют, можно взять из спецификации ELF и стандарта POSIX. Спецификация ELF — это то, что делает слабый символ значимым. POSIX — это фактическая спецификация самой функции dlopen().
Это то, что я считаю наиболее важной частью спецификации ELF.
Когда редактор ссылок выполняет поиск в архивных библиотеках, он извлекает элементы архива, содержащие определения неопределенных глобальных символов. Определение члена может быть либо глобальным, либо слабым символом.
В спецификации ELF не упоминается динамическая загрузка, поэтому остальная часть этого абзаца является моей собственной интерпретацией. Причина, по которой я считаю вышеизложенное актуальным, заключается в том, что разрешение символов происходит в одно «когда». В приведенном вами примере, когда программа a
динамически загружает b.so
, динамический загрузчик пытается разрешить неопределенные символы. В конечном итоге это может произойти с глобальными или слабыми символами. Когда программа затем динамически загружает c.so
, динамический загрузчик снова пытается разрешить неопределенные символы. В описанном вами сценарии символы в b.so
были разрешены слабыми символами. После разрешения эти символы больше не являются неопределенными. Неважно, использовались ли для их определения глобальные или слабые символы. К моменту загрузки c.so
они уже не являются неопределенными.
Спецификация ELF не дает точного определения того, что такое редактор ссылок или когда редактор ссылок должен объединять объектные файлы. Предположительно, это не проблема, потому что документ имеет в виду динамическую компоновку.
POSIX описывает некоторые функции dlopen(), но многое оставляет за реализацией, включая суть вашего вопроса. POSIX вообще не ссылается на формат ELF или слабые символы. Для систем, реализующих dlopen(), не требуется даже понятия слабых символов.
http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html
Соответствие POSIX является частью другого стандарта, Linux Standard Base. Дистрибутивы Linux могут следовать этим стандартам, а могут и не следовать, а также могут или не должны быть сертифицированы. Например, я понимаю, что официальная сертификация Unix от Open Group стоит довольно дорого — отсюда и обилие «Unix-подобных» систем.
Интересный момент о соответствии стандартам dlopen() упоминается в статье Википедии о динамической загрузке. dlopen() в соответствии с требованиями POSIX возвращает void*, но C, согласно требованиям ISO, говорит, что void* является указателем на объект, и такой указатель не обязательно совместим с указателем на функцию.
Факт остается фактом: любое преобразование между указателями на функции и объекты должно рассматриваться как (по своей сути непереносимое) расширение реализации, и что не существует «правильного» способа прямого преобразования, поскольку в этом отношении стандарты POSIX и ISO противоречат друг другу. разное.
Существующие стандарты противоречат друг другу, а существующие документы стандартов в любом случае могут не иметь особого смысла. Вот Ульрих Дреппер, который пишет о своем презрении к Open Group и их «спецификациям».
http://udrepper.livejournal.com/8511.html
Похожее мнение выражено в посте, на который ссылается Родриго.
Причина, по которой я внес это изменение, заключается не в том, чтобы быть более согласованным (это приятно, но это не причина, поскольку никто не жаловался на старое поведение).
Изучив его, я считаю, что правильный ответ на вопрос, который вы задали, заключается в том, что для dlopen()
нет правильного или неправильного поведения в этом отношении. Возможно, после того, как поиск разрешил символ, он больше не является неопределенным, и при последующих поисках динамический загрузчик не будет пытаться разрешить уже определенный символ.
Наконец, как вы заявляете в комментариях, то, что вы описываете в исходном сообщении, неверно. Динамически загружаемые общие библиотеки можно использовать для разрешения неопределенных символов в ранее динамически загруженных общих библиотеках. На самом деле это не ограничивается неопределенными символами в динамически загружаемом коде. Вот пример, в котором сам исполняемый файл имеет неопределенный символ, который разрешается с помощью динамической загрузки.
main.c
#include <dlfcn.h>
void say_hi(void);
int main(void) {
void* symbols_b = dlopen("./dyload.so", RTLD_NOW | RTLD_GLOBAL);
/* uh-oh, forgot to define this function */
/* better remember to define it in dyload.so */
say_hi();
return 0;
}
dyload.c
#include <stdio.h>
void say_hi(void) {
puts("dyload.so: hi");
}
Скомпилируйте и запустите.
gcc-4.8 main -fpic -ldl -Wl,--unresolved-symbols=ignore-all -o main
gcc-4.8 dyload.c -shared -fpic -o dyload.so
$ ./main
dyload.so: hi
Обратите внимание, что сам основной исполняемый файл был скомпилирован как PIC.
person
Praxeolitic
schedule
25.09.2014
dlopen()
не будет иметь значения между слабыми и сильными символами. - person rodrigo   schedule 16.01.2014