Динамическая загрузка и слабое разрешение символов

анализ этот вопрос я узнал кое-что о поведении слабого разрешения символов в контексте динамической загрузки (dlopen) на Linux. Теперь я ищу спецификации, регулирующие это.

давайте пример. Предположим, есть программа a который динамически загружает библиотеки b.so и c.so - в таком порядке. Если c.so зависит от двух других библиотеки foo.so (на самом деле libgcc.so в этом примере) и bar.so (на самом деле libpthread.so), то, как правило, символы, экспортируемые bar.so может использоваться для удовлетворения слабых связей символов в foo.so. Но если ... --2--> зависит foo.so а не на bar.so, то эти слабые символы, по-видимому, не будут связаны против bar.so. Кажется, что foo.so inkages только искать символы из a и b.so и все их зависимости.

это имеет смысл, в некоторой степени, так как в противном случае загрузка c.so может изменить поведение foo.so в какой-то точка, где b.so уже использует библиотеку. С другой стороны, в вопросе, который заставил меня начать, это вызвало довольно много проблем, поэтому я задаюсь вопросом, есть ли способ обойти эту проблему. И чтобы найти способы обойти, мне сначала нужно хорошее понимание очень точных деталей, как указывается разрешение символа в этих случаях.

что спецификация или другой технический документ для того чтобы определить правильное поведение в этих сценарии?

1 ответов


к сожалению, авторитетной документацией является исходный код. Большинство дистрибутивов Linux используют glibc или его fork, eglibc. В исходном коде для обоих файлов файл, который должен документировать dlopen (), читается следующим образом:

руководство/libdl.текси!--11-->

@c FIXME these are undocumented:
@c dladdr
@c dladdr1
@c dlclose
@c dlerror
@c dlinfo
@c dlmopen
@c dlopen
@c dlsym
@c dlvsym

какую техническую спецификацию там можно нарисовать от спецификация эльф и стандарт POSIX. Спецификация ELF-это то, что делает слабый символ значимым. POSIX является фактическим спецификация для dlopen ().

это то, что я считаю наиболее актуальной частью спецификации ELF.

когда редактор ссылок ищет архивные библиотеки, он извлекает архив члены, содержащие определения неопределенных глобальных символов. Этот определение члена может быть либо глобальным, либо слабым символом.

спецификация ELF не ссылается на динамическую нагрузку, поэтому остальная часть этого абзац-это мое собственное толкование. Причина, по которой я нахожу вышеизложенное актуальным, заключается в том, что разрешение символов происходит в одном "когда". В приведенном примере, когда program 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. Дистрибутивы Linux могут выбрать или не выбрать следуйте этим стандартам и может или не может пойти на проблемы сертификации. Например, я понимаю, что формальная сертификация Unix в Open Group довольно дорога - отсюда и обилие "Unix-подобных" систем.

интересный момент о соответствии стандартов dlopen () сделан на статья Википедии для динамической загрузки. dlopen(), как предписано POSIX, возвращает void*, но C, как предписано ISO, говорит, что void* является указателем на объект и такой указатель не обязательно совместим с указателем функции.

факт остается фактом, что любое преобразование между функцией и объектом указатели должны рассматриваться как (по своей сути непереносимые) расширение внедрения, и что нет "правильного" пути для прямого преобразование существует, так как в этом отношении стандарты POSIX и ISO противоречить друг другу.

стандарты, которые существуют, противоречат и какие стандарты документы есть не может быть особенно значимым. Вот Ульрих Дрэппер пишет о своем презрении к открытой группе и их "спецификациям".

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

обратите внимание, что основной исполняемый файл был скомпилирован как рис.