在libc和libdl中使用dlopen

如果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中已经存在的私有 dl函数,以及一些包装器,使得库的使用更容易一些。 您可以通过查看libdl的符号表来查看其中的一些行为。

如果在libdl上使用readelf,则限制为私有符号:

 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 

您看到所有UND的条目,从GLIBC_PRIVATE列出? 这些都是引用libc中的实现。

libc本身定义的API本身没有声明为实现dl函数作为一个暴露的API,但是在glibc libdl被绑定到libc ,并且暴露了已知的API。 在这种情况下,glibc可以使用私有的例程来完成运行时打开和使用相关的.so文件。