libc 和 libdl 中的 dlopen

dlopen in libc and libdl

如果 gcc 编译的程序正在调用 dlopen,则必须在启用 -ldl 选项的情况下进行编译。这意味着这样的程序在 运行 时间依赖库 libdl.so。事实上,通过对它执行 ldd,我们看到了这一行:

libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2

libc.so 依次使用 dlopen(例如,处理 libnss.so),但在 libldl.so 上执行 ldd 不会出现:

/lib64/ld-linux-x86-64.so.2 (0x00007f5a488e4000)
linux-vdso.so.1 =>  (0x00007fff7bdfe000)

为什么会有这种差异?

libdl 仅公开 libc 中已经存在的 private dl 函数以及一些包装器,以使库的使用更容易一些。您可以通过查看 libdl.

的符号 table 来了解其中的一些行为

如果您在 libdl 上使用 readelf,限制为 PRIVATE 符号:

readelf -s /usr/lib/x86_64-linux-gnu/libdl.so | grep PRIVATE
    13: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  UND _rtld_global_ro@GLIBC_PRIVATE (7)
    14: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _dl_vsym@GLIBC_PRIVATE (8)
    16: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _dl_addr@GLIBC_PRIVATE (8)
    18: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _dl_sym@GLIBC_PRIVATE (8)
    20: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _dl_rtld_di_serinfo@GLIBC_PRIVATE (7)
    25: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  UND _rtld_global@GLIBC_PRIVATE (7)
    34: 00000000002030c0     8 OBJECT  GLOBAL DEFAULT   27 _dlfcn_hook@@GLIBC_PRIVATE
    39: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  ABS GLIBC_PRIVATE

您看到 GLIBC_PRIVATE 中 UND 的所有条目了吗?这些都引用了 libc 中的实现。

libc 本身定义的 API 未声明为实现 dl 函数作为公开的 API,但是在 glibc 中,libdl 与 libc,它公开了已知的 API。在这种情况下,glibc 可以使用自身内部的私有例程来完成 运行 次打开和使用相关 .so 文件用于 nss 例程。