ws_*_*421 3 gcc shared-library ld
解析库依赖项时,动态链接器首先检查每个依赖项字符串以查看它是否包含斜杠(如果在链接时指定了包含斜杠的库路径名,则会发生这种情况)。如果找到斜杠,则依赖字符串被解释为(相对或绝对)路径名,并使用该路径名加载库。
如何gcc
链接带有斜杠路径的库?我尝试过,-l
但这似乎只适用于用于搜索各种路径的库名称,而不适用于路径参数本身。
一个后续问题:当以这种方式链接到相对路径时,相对于的路径是什么(例如,包含二进制文件的目录或运行时的工作目录)?
所有链接引导我找到搜索时的讨论使用RPATH
,LD_LIBRARY_PATH
和RUNPATH
。RPATH
已弃用,大多数讨论不鼓励使用LD_LIBRARY_PATH
. RUNPATH
以 开头的路径$ORIGIN
允许链接到相对路径,但它有点脆弱,因为它可以被LD_LIBRARY_PATH
. 我想知道相对路径是否会更健壮(因为我找不到任何讨论这个的东西,我猜不是,可能是因为路径是相对于运行时目录的)。
thr*_*rig 10
如果我们(目前)忽略问题的gcc
或链接部分,而是patchelf
在 Linux 系统上修改二进制文件
$ ldd hello
linux-vdso.so.1 => (0x00007ffd35584000)
libhello.so.1 => not found
libc.so.6 => /lib64/libc.so.6 (0x00007f02e4f6f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f02e533c000)
$ patchelf --remove-needed libhello.so.1 hello
$ patchelf --add-needed ./libhello.so.1 hello
$ ldd hello
linux-vdso.so.1 => (0x00007ffdb74fc000)
./libhello.so.1 => not found
libc.so.6 => /lib64/libc.so.6 (0x00007f2ad5c28000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2ad5ff5000)
Run Code Online (Sandbox Code Playgroud)
我们现在有一个带有相对路径库的二进制文件,如果存在合适的目录,其中存在libhello.so.1
文件
$ cd english/
$ ../hello
hello, world
$ cd ../lojban/
$ ../hello
coi rodo
Run Code Online (Sandbox Code Playgroud)
我们发现该路径是相对于进程的工作目录,这就引出了各种各样的问题,尤其是安全 问题。这可能有一些富有成效的用途,也许可以测试不同版本的库。编译两个不同的二进制文件或patchelf
在必要的库中编译两个不同的二进制文件可能会更简单,而没有相对工作目录的复杂性。
libhello
只有一个helloworld
电话
$ cat libhello.c
#include <stdio.h>
void helloworld(void)
{
printf("coi rodo\n");
}
Run Code Online (Sandbox Code Playgroud)
并通过编译
CFLAGS="-fPIC" make libhello.o
gcc -shared -fPIC -Wl,-soname,libhello.so.1 -o libhello.so.1.0.0 libhello.o -lc
ln -s libhello.so.1.0.0 libhello.so.1
ln -s libhello.so.1.0.0 libhello.so
Run Code Online (Sandbox Code Playgroud)
hello
进行helloworld
调用的那个是通过编译的
$ cat hello.c
int main(void)
{
helloworld();
return 0;
}
$ CFLAGS="-lhello -L`pwd`/english" make hello
Run Code Online (Sandbox Code Playgroud)
事后看来,修改gcc
命令以使用相对目录路径:
$ gcc -shared -fPIC -Wl,-soname,./libhello.so.1 -o libhello.so.1.0.0 libhello.o -lc
$ cd ..
$ rm hello
$ CFLAGS="-lhello -L`pwd`/lojban" make hello
$ ldd hello | grep hello
./libhello.so.1 => not found
$ english
$ ../hello
hello, world
Run Code Online (Sandbox Code Playgroud)
以正常方式编译库然后根据需要使用patchelf
.
您可以通过将选项传递给链接器来完成此操作。例如,要从 ncurses 的构建目录(依赖于未安装的库)运行测试程序,我使用如下选项(在 gcc 命令行中):
-Wl,-rpath,../lib
Run Code Online (Sandbox Code Playgroud)
它嵌入了一个相对路径名。相同的选项可以嵌入绝对路径名:
-Wl,-rpath,../lib:/usr/local/ncurses6/lib
Run Code Online (Sandbox Code Playgroud)
这样做对于本地测试很有用,但由于多种原因不适用于在系统上安装。Debian 有一项反对它的政策,可以追溯到 20 世纪 90 年代,尽管连贯的讨论很少(参见例如收集了一些信息的RPATH 问题)。