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

lan*_*nza 11 linker ld bfd gold-linker lld

国家的人gold:

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

  --rpath-link DIR
          Add DIR to link time shared library search path
Run Code Online (Sandbox Code Playgroud)

bfd的男人ld让它有点像-rpath-link用于递归包含sos 的声音.

ld.lld 甚至没有将其列为参数.

有人可以为我澄清这种情况吗?

Mik*_*han 26

这里是一个演示,为GNU ld之间的差异-L-rpath-link-和好措施,之间的差异-rpath-link-rpath.

foo.c的

#include <stdio.h>

void foo(void)
{
    puts(__func__);
}
Run Code Online (Sandbox Code Playgroud)

bar.c

#include <stdio.h>

void bar(void)
{
    puts(__func__);
}
Run Code Online (Sandbox Code Playgroud)

foob​​ar.c但是

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

void foobar(void)
{
    foo();
    bar();
}
Run Code Online (Sandbox Code Playgroud)

main.c中

extern void foobar(void);

int main(void)
{
    foobar();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

制作两个共享库,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
Run Code Online (Sandbox Code Playgroud)

建立第三个共享库,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
Run Code Online (Sandbox Code Playgroud)

哎呀.链接器不知道在哪里寻求解析-lfoo-lbar.

-L选项修复了这一点.

$ gcc -shared -o libfoobar.so foobar.o -L. -lfoo -lbar
Run Code Online (Sandbox Code Playgroud)

-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
Run Code Online (Sandbox Code Playgroud)

哎呀.链接器检测请求的动态依赖性libfoobar.so 但不能满足它们.让我们反对它的建议 - try using -rpath or -rpath-link有点看看我们能做些什么,-L并且-l:

$ gcc -o prog main.o -L. -lfoobar -lfoo -lbar
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.但:

$ ./prog
./prog: error while loading shared libraries: libfoobar.so: cannot open shared object file: No such file or directory
Run Code Online (Sandbox Code Playgroud)

在运行时,加载器无法找到libfoobar.so.

然后链接器的建议怎么样?有了-rpath-link,我们可以做到:

$ gcc -o prog main.o -L. -lfoobar -Wl,-rpath-link=$(pwd)
Run Code Online (Sandbox Code Playgroud)

这种联系也成功了.

-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]
 ...
 ...
Run Code Online (Sandbox Code Playgroud)

我们只需知道一个可以找到它们的目录,无论它们是什么.

但是这会给我们一个可运行的prog吗?

$ ./prog
./prog: error while loading shared libraries: libfoobar.so: cannot open shared object file: No such file or directory
Run Code Online (Sandbox Code Playgroud)

没有.和以前一样的故事.这是因为-rpath-link=dir链接器提供了加载器 在运行时需要解决一些动态依赖关系所需的信息prog- 假设它在运行时保持为真 - 但它并没有将该信息写入动态部分 prog.它只是让链接成功,而不需要拼出链接与-l选项的所有递归动态依赖关系.

在运行时,libfoo.so,libbar.so-事实上libfoobar.so-很可能不是他们现在在哪里- $(pwd)-但装载机也许能够通过其他方式找到他们:通过ldconfig高速缓存或的设置LD_LIBRARY_PATH环境变量,例如:

$ export LD_LIBRARY_PATH=.; ./prog
foo
bar
Run Code Online (Sandbox Code Playgroud)

rpath=dir为链接器提供与其相同的信息,rpath-link=dir 指示链接器将该信息烘焙到输出文件的动态部分.我们试试看:

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

都好.因为现在,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]
 ...                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
Run Code Online (Sandbox Code Playgroud)

该搜索路径将在列出的目录LD_LIBRARY_PATH(如果有)之后,在系统默认之前 - ldconfig-ed目录,加号/lib/usr/lib.

  • 我仍然不清楚:为什么不让动态依赖项也在 -L 提供的路径中查找?或者,为什么不在 -rpath-link 指定的路径中搜索库?-L 和 -rpath-link 都存在的理由是什么? (2认同)

Car*_*ant 7

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

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