男人的gold
状态:
-L DIR, --library-path DIR
Add directory to search path
--rpath-link DIR
Add DIR to link time shared library search path
bfd 的 manld
听起来有点像-rpath-link
用于递归包含的 sos。
ld.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 的 manld
听起来有点像-rpath-link
用于递归包含的 sos。
ld.lld
甚至没有将其列为论点。
有人可以为我澄清这种情况吗?
这是一个演示,对于 GNU ,和ld
之间的区别- 并且为了更好的衡量,和之间的区别。-L
-rpath-link
-rpath-link
-rpath
foo.c
#include <stdio.h>
void foo(void)
{
puts(__func__);
}
酒吧.c
#include <stdio.h>
void bar(void)
{
puts(__func__);
}
foobar.c
extern void foo(void);
extern void bar(void);
void foobar(void)
{
foo();
bar();
}
主程序
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
and做什么-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)
这种联系也成功了。($(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]
...
...
我们只需要知道可以找到它们的目录,无论它们是什么。
但这会给我们一个 runnableprog
吗?
$ ./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
ed 目录,加上/lib
和/usr/lib
。
在进行链接时符号解析时,bfd ld 使用该--rpath-link
选项添加到用于查找 DT_NEEDED 共享库的搜索路径。它基本上是在告诉链接器在尝试模仿动态链接器在解析符号时(由--rpath
选项或LD_LIBRARY_PATH
环境变量设置)时将做什么作为运行时搜索路径。
解析共享库中的符号时,Gold 不遵循 DT_NEEDED 条目,因此该--rpath-link
选项被忽略。这是一个深思熟虑的设计决定。在链接过程中,间接依赖项不需要存在或其运行时位置。