链接:为什么链接器不支持库的符号链接?
Linking: Why does linker not honour symlink to library?
我有以下 C 程序:
#include <stdio.h>
#include <zlib.h>
int main()
{
z_stream strm;
int integer = 0;
scanf("heloworld %d", &integer);
printf("ok\n");
if (integer == 10)
{
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
deflateInit(&strm, 0);
}
return 0;
}
这是一个使用 zlib 的基本 helloworld 程序。
如果我搜索 libz 库,我可以在 /usr/lib/x86_64-linux-gnu/libz 下找到它。所以:
$ ls -lah libz.so
lrwxrwxrwx 1 root root 40 May 20 14:55 libz.so -> /usr/lib/x86_64-linux-gnu/libz.so.1.2.11
它指向的是真实版本的 libz 而不是 soname。
我用以下命令编译它并检查依赖关系:
$ gcc a.c -lz
$ ldd a.out
linux-vdso.so.1 (0x00007ffec44b6000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f6674055000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6673e63000)
/lib64/ld-linux-x86-64.so.2 (0x00007f667408c000)
它如何指向 libz.so.1 而不是 libz.so.1.2.11(实名),因为 libz.so.1 的符号链接指向那里?我假设链接器正在使用符号链接,但事实并非如此。
此外,如果我执行以下命令:
$ objdump -p libz.so.1.2.11 | grep SONAME
SONAME libz.so.1
我的问题是,它是使用符号链接名称还是符号链接提供的文件中的 SONAME?
如果 linker 将 libz.so.1.2.11 放入您的可执行文件中,那么它会在您更新库时中断。相反,它将 ldconfig 已知的主要版本放在可执行文件中,这又是当前安装版本的 link。
查看 ldconfig http://man7.org/linux/man-pages/man8/ldconfig.8.html
我发现 /lib/x86_64-linux-gnu 下有两个 libz.so 的符号链接,它们是:
libz.so
libz.so.1
当我编译时,链接器使用 libz.so 作为指向另一个 .so 文件的符号链接。
libz.so 指向的 .so 文件包含一个 SONAME 条目,可以这样查看:
$ objdump -p ./libz.so | grep SONAME
SONAME libz.so.1
此外,我可以看到符号链接指向 libz.so.1.2.11
$ ls -alh libz.so
lrwxrwxrwx 1 root root 36 May 21 00:51 libz.so -> /lib/x86_64-linux-gnu/libz.so.1.2.11
如果我像这样编辑该库的 .dynstr 部分:
$ sudo objcopy --dump-section .dynstr=/tmp/dyn.dump ./libz.so.1.2.11
# Find the bytes for libz.so.1 and change them to libz.so.2
$ hexedit /tmp/dyn.dump
$ sudo objcopy --update-section .dynstr=/tmp/dyn.dump ./libz.so.1.2.11
然后重新编译我的二进制文件我注意到:
$ ldd a.out
linux-vdso.so.1 (0x00007ffe54bbe000)
libz.so.2 => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f58bb5c7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f58bb7f0000)
在 /lib/x86_64-linux-gnu/libz.so.2 下创建 libz.so.2 的符号链接以指向 libz.so.1.2.11 后,我得到以下输出:
$ ldd a.out
linux-vdso.so.1 (0x00007ffe54bbe000)
libz.so.2 => /lib/x86_64-linux-gnu/libz.so.2 (0x00007f58bb7b9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f58bb5c7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f58bb7f0000)
因此,要回答我的问题,在可执行文件的运行时依赖项中添加条目的不是符号链接,而是共享对象中的 SONAME 条目。
我有以下 C 程序:
#include <stdio.h>
#include <zlib.h>
int main()
{
z_stream strm;
int integer = 0;
scanf("heloworld %d", &integer);
printf("ok\n");
if (integer == 10)
{
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
deflateInit(&strm, 0);
}
return 0;
}
这是一个使用 zlib 的基本 helloworld 程序。
如果我搜索 libz 库,我可以在 /usr/lib/x86_64-linux-gnu/libz 下找到它。所以:
$ ls -lah libz.so
lrwxrwxrwx 1 root root 40 May 20 14:55 libz.so -> /usr/lib/x86_64-linux-gnu/libz.so.1.2.11
它指向的是真实版本的 libz 而不是 soname。
我用以下命令编译它并检查依赖关系:
$ gcc a.c -lz
$ ldd a.out
linux-vdso.so.1 (0x00007ffec44b6000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f6674055000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6673e63000)
/lib64/ld-linux-x86-64.so.2 (0x00007f667408c000)
它如何指向 libz.so.1 而不是 libz.so.1.2.11(实名),因为 libz.so.1 的符号链接指向那里?我假设链接器正在使用符号链接,但事实并非如此。
此外,如果我执行以下命令:
$ objdump -p libz.so.1.2.11 | grep SONAME
SONAME libz.so.1
我的问题是,它是使用符号链接名称还是符号链接提供的文件中的 SONAME?
如果 linker 将 libz.so.1.2.11 放入您的可执行文件中,那么它会在您更新库时中断。相反,它将 ldconfig 已知的主要版本放在可执行文件中,这又是当前安装版本的 link。
查看 ldconfig http://man7.org/linux/man-pages/man8/ldconfig.8.html
我发现 /lib/x86_64-linux-gnu 下有两个 libz.so 的符号链接,它们是:
libz.so
libz.so.1
当我编译时,链接器使用 libz.so 作为指向另一个 .so 文件的符号链接。
libz.so 指向的 .so 文件包含一个 SONAME 条目,可以这样查看:
$ objdump -p ./libz.so | grep SONAME
SONAME libz.so.1
此外,我可以看到符号链接指向 libz.so.1.2.11
$ ls -alh libz.so
lrwxrwxrwx 1 root root 36 May 21 00:51 libz.so -> /lib/x86_64-linux-gnu/libz.so.1.2.11
如果我像这样编辑该库的 .dynstr 部分:
$ sudo objcopy --dump-section .dynstr=/tmp/dyn.dump ./libz.so.1.2.11
# Find the bytes for libz.so.1 and change them to libz.so.2
$ hexedit /tmp/dyn.dump
$ sudo objcopy --update-section .dynstr=/tmp/dyn.dump ./libz.so.1.2.11
然后重新编译我的二进制文件我注意到:
$ ldd a.out
linux-vdso.so.1 (0x00007ffe54bbe000)
libz.so.2 => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f58bb5c7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f58bb7f0000)
在 /lib/x86_64-linux-gnu/libz.so.2 下创建 libz.so.2 的符号链接以指向 libz.so.1.2.11 后,我得到以下输出:
$ ldd a.out
linux-vdso.so.1 (0x00007ffe54bbe000)
libz.so.2 => /lib/x86_64-linux-gnu/libz.so.2 (0x00007f58bb7b9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f58bb5c7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f58bb7f0000)
因此,要回答我的问题,在可执行文件的运行时依赖项中添加条目的不是符号链接,而是共享对象中的 SONAME 条目。