Ответ 1
К сожалению, официальная документация является исходным кодом. В большинстве дистрибутивов 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.
Когда редактор ссылок ищет архивные библиотеки, он извлекает архив члены, содержащие определения глобальных символов undefined. определение членов может быть глобальным или слабым символом.
В спецификации ELF нет ссылки на динамическую нагрузку, поэтому остальная часть этого абзаца является моей собственной интерпретацией. Причина, по которой я нахожу вышеприведенное, состоит в том, что разрешающие символы возникают при одном "когда". В приведенном примере, когда программа a
динамически загружает b.so
, динамический загрузчик пытается разрешить символы undefined. Это может привести к глобальным или слабым символам. Когда программа затем динамически загружает c.so
, динамический загрузчик снова пытается разрешить символы undefined. В описываемом вами сценарии символы в b.so
были разрешены со слабыми символами. После разрешения эти символы больше не являются undefined. Не имеет значения, использовались ли глобальные или слабые символы для их определения. Они уже не будут undefined к моменту загрузки c.so
.
В спецификации ELF нет точного определения того, что такое редактор ссылок или когда редактор ссылок должен объединять объектные файлы. Предположительно, это не проблема, потому что документ имеет динамическую связь.
POSIX описывает некоторые функциональные возможности dlopen(), но значительно уступает реализации, включая суть вашего вопроса. POSIX не ссылается на формат ELF или слабые символы в целом. Для систем, реализующих dlopen(), не должно быть даже понятия слабых символов.
http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html
Соответствие POSIX является частью другого стандарта - стандартной базы Linux. Распределения Linux могут или не могут следовать этим стандартам и могут или не могут попасть в проблему сертификации. Например, я понимаю, что официальная сертификация Unix от Open Group довольно дорога - поэтому обилие "Unix-подобных" систем.
Интересный вопрос о соответствии стандартов dlopen() содержится в статье в Википедии для динамической загрузки. dlopen(), как утверждается POSIX, возвращает void *, но C, как указано в ISO, говорит, что void * является указателем на объект, и такой указатель необязательно совместим с указателем функции.
Факт остается фактом: любое преобразование функции и объекта указатели должны рассматриваться как (по своей сути, не переносные) и что "правильный" способ для прямого конверсия существует, поскольку в этом отношении стандарты POSIX и ISO противоречат друг другу.
Стандарты, которые действительно существуют, противоречат друг другу и какие документы по стандартизации там, возможно, не имеют особого значения. Здесь Ульрих Дреппер пишет о своем презрении к Open Group и их "спецификациях".
http://udrepper.livejournal.com/8511.html
Подобное мнение выражается в сообщении, связанном с rodrigo.
Причина, по которой я сделал это изменение, на самом деле не должна быть более совместимой (это хорошо, но нет причин, так как никто не жаловался на старый поведение).
Посмотрев на него, я считаю, что правильный ответ на вопрос, как вы просили, заключается в том, что в этом отношении нет правильного или неправильного поведения для dlopen()
. Возможно, как только поиск разрешил символ, он больше не undefined, и в последующих поисках динамический загрузчик не попытается решить уже определенный символ.
Наконец, как вы заявляете в комментариях, то, что вы описали в исходном посте, неверно. Динамически загруженные разделяемые библиотеки могут использоваться для разрешения символов undefined в ранее динамически загружаемых разделяемых библиотеках. На самом деле это не ограничивается символами undefined в динамически загружаемом коде. Вот пример, в котором сам исполняемый файл имеет символ undefined, который разрешен посредством динамической загрузки.
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.