Разрешают ли библиотеки, о которых сообщает ldd, все неопределенные ссылки входной библиотеки? - PullRequest
0 голосов
/ 07 января 2019

Я хотел бы знать, что именно делает ldd. Печатает ли он только библиотеки из DT_NEEDED структур раздела .dynamic? Это не полный список библиотек, которые необходимы для разрешения всех неопределенных символов входной библиотеки ldd, насколько я знаю. В таком случае какая польза от ldd?

Или это действительно список всех библиотек, от которых на самом деле зависит входная библиотека ldd?

Вопрос не в том, показывает ли ldd зависимости зависимостей, а в том, разрешают ли библиотеки, о которых сообщает ldd, все неопределенные символы входной библиотеки ldd.

Ответы [ 3 ]

0 голосов
/ 08 января 2019

Разрешают ли библиотеки, о которых сообщает ldd, все неопределенные ссылки входной библиотеки?

Нет. Общая библиотека может быть связана с неопределенными ссылками (и это обычное дело). Так что это может быть ссылка, содержащая неопределенные ссылки, которые не будет разрешен ни одной из его (рекурсивных) зависимостей DSO, или любым существующим DSO или объектным файлом.

foo.c

#include <stdio.h>

extern void bar(void);

void foo(void)
{
    puts(__func__);
    bar();
}

Создать общую библиотеку:

$ gcc -shared -o libfoo.so foo.c

ldd libfoo.so рекурсивно перечисляет зависимости DSO libfoo.so:

$ ldd libfoo.so
    linux-vdso.so.1 (0x00007ffc30bf5000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd19209b000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fd19268e000)

Ни один из них не разрешает неопределенную ссылку на bar.

0 голосов
/ 08 января 2019

Невозможно получить список библиотек, необходимых для разрешения неопределенных символов в общем объекте, из самого общего объекта. Такой список может существовать или не существовать. Легко создать библиотеку с неопределенным символом, который не может быть разрешен ни одной из существующих в мире библиотек.

# cat test.c 
extern void foo99988776543quzzu();
void test() {
    foo99988776543quzzu();
}
# gcc -fPIC -shared -o libtest.so test.c

Здесь мы создали библиотеку с неопределенным символом, который не может удовлетворить ни одна другая библиотека в мире - пока мы не создадим ее.

# cat foo.c 
void foo99988776543quzzu() {}
# gcc -fPIC -shared -o libfoo.so foo.c

Никакая магия в мире не может помочь ldd libtest.so найти libfoo.so. Но легко создать загружаемую, запускаемую программу из libtest.so и libfoo.so.

# cat main.c
extern void test();
int main() { test(); }
# gcc main.c -lfoo -ltest -L. -Wl,-rpath=.
# ./a.out

ldd не пытается создать невозможный список библиотекарей, необходимых для разрешения неопределенных символов. Он делает именно то, что говорит на банке:

ldd печатает общие объекты (общие библиотеки), необходимые для каждой программы или общего объекта, указанного в командной строке.

Слово «требуется» здесь не означает «требуется для разрешения неопределенных символов». Как уже было сказано, список объектов, необходимых для разрешения неопределенных символов, не может быть создан. Вместо этого «требуется» означает набор динамических зависимостей, a.k.a. «разделяемые объекты, необходимые для рекурсивного DT_NEEDED», как подробно описано в ldd (1) и ld.so (8).

какая польза от ldd вообще?

DT_NEEDED разделы содержат sonames . ldd рекурсивно собирает эти сонамы и сопоставляет их с путями к файлам , используя информацию в DT_RUNPATH, DT_RPATH, LD_LIBRARY_PATH, /etc/ld.so.conf и в любых местах, которые мы ищем на этой неделе. Таким образом, вывод ldd содержит список путей к файлам для общих объектов, которые будут загружены при загрузке общего объекта в командной строке ldd. Вот пример:

#ldd ./test
    linux-vdso.so.1 (0x00007fff0593f000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fe7e6776000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe7e6385000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe7e5fe7000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fe7e6d01000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe7e5dcf000)

Это довольно полезная информация даже для самых случайных наблюдателей. Мы видим, что test представляется 64-битной программой C ++ для x86 Linux, созданной, например, с относительно недавней версией gcc или совместимым компилятором. Мы также видим, что у него нет сторонних зависимостей.

С другой стороны,

# ldd  /usr/bin/kdiff3
    linux-vdso.so.1 (0x00007ffeeed79000)
    libkparts.so.4 => /usr/lib/libkparts.so.4 (0x00007f801a14d000)
    libkio.so.5 => /usr/lib/libkio.so.5 (0x00007f8019c9b000)
    libkdeui.so.5 => /usr/lib/libkdeui.so.5 (0x00007f8019637000)
    libkdecore.so.5 => /usr/lib/libkdecore.so.5 (0x00007f801916b000)
    libQtCore.so.4 => /usr/lib/x86_64-linux-gnu/libQtCore.so.4 (0x00007f8018c79000)
    libQtGui.so.4 => /usr/lib/x86_64-linux-gnu/libQtGui.so.4 (0x00007f8017f84000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8017bfb000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f801785d000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f801746c000)
    libQtXml.so.4 => /usr/lib/x86_64-linux-gnu/libQtXml.so.4 (0x00007f8017226000)
    libQtNetwork.so.4 => /usr/lib/x86_64-linux-gnu/libQtNetwork.so.4 (0x00007f8016ed1000)
    libQtSvg.so.4 => /usr/lib/x86_64-linux-gnu/libQtSvg.so.4 (0x00007f8016c78000)
    libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f8016940000)
    ... many more lines ...

перечисляет много зависимостей. Если он не загружается, мы можем использовать список, чтобы выяснить причину. Например, любая строка с надписью => not found будет очень полезна.

0 голосов
/ 08 января 2019

Печатает ли ldd только библиотеки из DT_NEEDED структур раздела .dynamic?

Нет, это то, что делает readelf --dynamic.

какая польза от ldd вообще?

ldd показывает, какие библиотеки загружает компоновщик времени выполнения ld.so при запуске исполняемого файла или загрузке совместно используемой библиотеки. Это рекурсивный процесс, например, исполняемый файл нуждается в общей библиотеке (DT_NEEDED), поэтому библиотека загружается. Затем происходит загрузка зависимостей загруженной библиотеки (DT_NEEDED) и т. Д.

Вам не обязательно нужен ldd, вы можете просто установить LD_DEBUG=all переменную окружения, чтобы ld.so печатать эту информацию и многое другое. См. man ld.so для получения дополнительной информации.

Каждая загруженная исполняемая или совместно используемая библиотека предоставляет свои определенные экспортированные динамические символы в виде области поиска (хеш-таблица). Область поиска формирует список. При разрешении неопределенного символа ld.so обходит области поиска и находит первый, который определяет символ и разрешает ссылку на символ. Если ld.so достигает конца областей поиска, он сообщает, что символ не разрешен.

Нет никакого соответствия между неразрешенным именем символа и исполняемой / разделяемой библиотекой, из которой он должен исходить. ld.so рекурсивно загружает все разделяемые библиотеки из DT_NEEDED разделов, создает этот список областей поиска и затем ищет там неразрешенные символы.

Как писать общие библиотеки У. Дреппера объясняет это в деталях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...