如何使用相对路径链接到共享库?

ws_*_*421 3 gcc shared-library ld

ld.so(8)手册页中,它说

解析库依赖项时,动态链接器首先检查每个依赖项字符串以查看它是否包含斜杠(如果在链接时指定了包含斜杠的库路径名,则会发生这种情况)。如果找到斜杠,则依赖字符串被解释为(相对或绝对)路径名,并使用该路径名加载库。

如何gcc链接带有斜杠路径的库?我尝试过,-l但这似乎只适用于用于搜索各种路径的库名称,而不适用于路径参数本身。

一个后续问题:当以这种方式链接到相对路径时,相对于的路径是什么(例如,包含二进制文件的目录或运行时的工作目录)?

所有链接引导我找到搜索时的讨论使用RPATHLD_LIBRARY_PATHRUNPATHRPATH已弃用,大多数讨论不鼓励使用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.


Tho*_*key 6

您可以通过将选项传递给链接器来完成此操作。例如,要从 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 问题)。