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

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

在里面ld.so(8) 的手册页,它说

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

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

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

我在搜索时找到的所有链接指南都讨论了使用RPATHLD_LIBRARY_PATHRUNPATHRPATH已被弃用,并且大多数讨论都不鼓励使用LD_LIBRARY_PATH.RUNPATH以 开头的路径$ORIGIN允许链接到相对路径,但它有点脆弱,因为它可以被 覆盖LD_LIBRARY_PATH。我想知道相对路径是否会更健壮(因为我找不到任何讨论此问题的内容,我猜不是,可能是因为该路径是相对于运行时目录的)。

答案1

如果我们(暂时)忽略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)

我们现在有一个带有相对路径库的二进制文件,如果存在包含libhello.so.1文件的合适目录

$ cd english/
$ ../hello
hello, world
$ cd ../lojban/
$ ../hello
coi rodo

我们发现该路径是相对于进程的工作目录的,这会带来各种各样的问题,特别是安全 问题。这可能有一些富有成效的用途,也许可以测试库的不同版本。编译两个不同的二进制文件可能会更简单,或者patchelf在必要的库中编译,而无需相对工作目录的复杂化。

编译步骤

libhello只有一个helloworld电话

$ cat libhello.c
#include <stdio.h>
void helloworld(void)
{
    printf("coi rodo\n");
}

并通过编译

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

hello进行调用的方法是helloworld通过编译的

$ cat hello.c
int main(void)
{
    helloworld();
    return 0;
}
$ CFLAGS="-lhello -L`pwd`/english" make hello

没有补丁

事后看来,修改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

以正常方式编译库,然后根据需要使用patchelf.

答案2

您可以通过将选项传递给链接器来完成此操作。例如,要从 ncurses 的构建目录(依赖于未安装的库)运行测试程序,我使用如下选项(在 gcc 命令行中):

-Wl,-rpath,../lib

它嵌入了一个相对路径名。相同的选项可以嵌入绝对路径名:

-Wl,-rpath,../lib:/usr/local/ncurses6/lib

这样做对于本地测试很有用,但由于多种原因不适用于在系统上安装。 Debian 有一项反对它的政策,可以追溯到 20 世纪 90 年代,尽管连贯的讨论很少(参见例如RPATH问题它收集了一些信息)。

答案3

如果使用gcc简单编译的话,只需要这样做:

gcc -o prog main.c ./liblib.so

编译后,程序的行为与 thrig 的答案相同。我认为这个命令应该只在测试环境中使用。

相关内容