В чем разница между `-rpath-link` и`-L`?

Человек для gold состояния:

  -L DIR, --library-path DIR
          Add directory to search path

  --rpath-link DIR
          Add DIR to link time shared library search path

Человек для BFD ld делает это вроде как -rpath-link используется для рекурсивно включенного SOS.

ld.lld даже не перечисляет это как аргумент.

Может ли кто-нибудь прояснить эту ситуацию для меня?

2 ответа

Решение

Вот демо, для GNU ld разницы между -L а также -rpath-link - и для хорошей меры, разница между -rpath-link а также -rpath,

foo.c

#include <stdio.h>

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

bar.c

#include <stdio.h>

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

foobar.c

extern void foo(void);
extern void bar(void);

void foobar(void)
{
    foo();
    bar();
}

main.c

extern void foobar(void);

int main(void)
{
    foobar();
    return 0;
}

Сделайте две общие библиотеки, libfoo.so а также libbar.so:

$ gcc -c -Wall -fPIC foo.c bar.c
$ gcc -shared -o libfoo.so foo.o
$ gcc -shared -o libbar.so bar.o

Сделайте третью общую библиотеку, libfoobar.so это зависит от первых двух;

$ gcc -c -Wall -fPIC foobar.c
$ gcc -shared -o libfoobar.so foobar.o -lfoo -lbar
/usr/bin/ld: cannot find -lfoo
/usr/bin/ld: cannot find -lbar
collect2: error: ld returned 1 exit status

К сожалению. Компоновщик не знает, где искать, чтобы решить -lfoo или же -lbar,

-L опция исправляет это.

$ gcc -shared -o libfoobar.so foobar.o -L. -lfoo -lbar

-Ldir опция говорит компоновщику, что dir является одним из каталогов для поиска библиотек, которые разрешают -lname варианты дано. Он ищет -L каталоги сначала в порядке их командной строки; затем он ищет свои настроенные каталоги по умолчанию, в их настроенном порядке.

Теперь создайте программу, которая зависит от libfoobar.so:

$ gcc -c -Wall main.c
$ gcc -o prog main.o -L. -lfoobar
/usr/bin/ld: warning: libfoo.so, needed by ./libfoobar.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libbar.so, needed by ./libfoobar.so, not found (try using -rpath or -rpath-link)
./libfoobar.so: undefined reference to `bar'
./libfoobar.so: undefined reference to `foo'
collect2: error: ld returned 1 exit status

Ой снова Компоновщик обнаруживает динамические зависимости, запрошенные libfoobar.so но не могу их удовлетворить. Давайте сопротивляться его советам - try using -rpath or -rpath-link - немного и посмотрим, что мы можем сделать с -L а также -l:

$ gcc -o prog main.o -L. -lfoobar -lfoo -lbar

Все идет нормально. Но:

$ ./prog
./prog: error while loading shared libraries: libfoobar.so: cannot open shared object file: No such file or directory

во время выполнения загрузчик не может найти libfoobar.so,

А как насчет совета линкера? С -rpath-link, мы можем:

$ gcc -o prog main.o -L. -lfoobar -Wl,-rpath-link=$(pwd)

и эта связь также успешно.

-rpath-link=dir опция сообщает компоновщику, что когда он встречает входной файл, который запрашивает динамические зависимости - например, libfoobar.so - он должен искать каталог dir разрешить их. Таким образом, нам не нужно указывать эти зависимости с -lfoo -lbar и даже не нужно знать, что они есть. То, что они есть, это информация, уже написанная в динамическом разделе libfoobar.so:-

$ readelf -d libfoobar.so

Dynamic section at offset 0xdf8 contains 26 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]
 0x0000000000000001 (NEEDED)             Shared library: [libbar.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 ...
 ...

Нам просто нужно знать каталог, где их можно найти, кем бы они ни были.

Но дает ли это нам работоспособный prog?

$ ./prog
./prog: error while loading shared libraries: libfoobar.so: cannot open shared object file: No such file or directory

Так же, как история, как и раньше. Это потому что -rpath-link=dir дает компоновщику информацию, которая понадобится загрузчику для разрешения некоторых динамических зависимостей prog во время выполнения - при условии, что он остался верным во время выполнения - но он не записывает эту информацию в динамический раздел prog, Это просто позволяет связать успешно, без нашей необходимости прописывать все рекурсивные динамические зависимости связи с -l опции.

Во время выполнения, libfoo.so, libbar.so - и действительно libfoobar.so - вполне может быть не там, где они сейчас - $(pwd) - но загрузчик мог бы найти их другими способами: через ldconfig кеш или настройка LD_LIBRARY_PATH переменная окружения, например:

$ export LD_LIBRARY_PATH=.; ./prog
foo
bar

rpath=dir предоставляет компоновщику ту же информацию, что и rpath-link=dir и инструктирует компоновщику запекать эту информацию в динамический раздел выходного файла. Давайте попробуем это:

$ export LD_LIBRARY_PATH=
$ gcc -o prog main.o -L. -lfoobar -Wl,-rpath=$(pwd)
$ ./prog
foo
bar

Все хорошо. Потому что сейчас prog содержит информацию, которая $(pwd) это путь поиска во время выполнения для разделяемых библиотек, от которого он зависит, как мы можем видеть:

$ readelf -d prog

Dynamic section at offset 0xe08 contains 26 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libfoobar.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000f (RPATH)              Library rpath: [/home/imk/develop/so/scrap]
 ...                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ...

Этот путь поиска будет пробоваться после каталогов, перечисленных в LD_LIBRARY_PATH, если таковые установлены, и перед настройками системы по умолчанию - ldconfig каталоги, плюс /lib а также /usr/lib,

--rpath-link опция используется bfd ld для добавления к пути поиска, используемому для поиска разделяемых библиотек DT_NEEDED при выполнении разрешения символов во время соединения. Это в основном говорит компоновщику, что использовать в качестве пути поиска во время выполнения при попытке имитировать то, что динамический компоновщик будет делать при разрешении символов (как установлено --rpath варианты или LD_LIBRARY_PATH переменная окружения).

Gold не следует за записями DT_NEEDED при разрешении символов в общих библиотеках, поэтому --rpath-link опция игнорируется Это было обдуманное дизайнерское решение; косвенные зависимости не обязательно должны присутствовать или находиться в местах их выполнения во время процесса соединения.

Другие вопросы по тегам