`-rpath-link`和`-L`有什么区别?

时间:2018-03-06 19:03:33

标签: linker ld gold-linker bfd lld

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 个答案:

答案 0 :(得分:21)

这是针对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.solibbar.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.solibbar.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 - ed目录加上/lib和{{ 1}}。

答案 1 :(得分:3)

bfd ld使用--rpath-link选项添加到用于在执行链接时符号解析时查找DT_NEEDED共享库的搜索路径。在尝试模拟动态链接器在解析符号时所执行的操作(由--rpath选项或LD_LIBRARY_PATH环境变量设置)时,它基本上告诉链接器要使用什么作为运行时搜索路径

在解析共享库中的符号时,Gold不会遵循DT_NEEDED条目,因此忽略--rpath-link选项。这是一个刻意的设计决定;在链接过程中,不需要存在间接依赖关系或在其运行时位置。