链接到不进行函数调用的库有什么影响?
我有一个程序的make文件,链接到libdl.so与以下行-ldl。 没有调用dlopen或任何相关函数。 即使您不使用任何function,以这种方式链接到此库有什么影响?
您必须阅读链接器的文档。 来自我的Linux / ELF / GNU Binutils系统上的info ld
(强调添加):
`--as急需” `--no-按需” 此选项会影响动态库的ELF DT_NEEDED标记 在`--as-needed'选项后的命令行中提到。 通常,链接器将为每个动态添加DT_NEEDED标记 在命令行中提到的库,无论是否 实际上是否需要库。 `--as-needed'导致a DT_NEEDED标记仅为满足a的库发出 来自常规对象文件的未定义符号引用,或者,如果是 在其他库的DT_NEEDED列表中找不到库 链接到那一点,来自的未定义的符号引用 另一个动态库。 `--no-as-needed'恢复默认值 行为。
您可以通过在测试程序上运行ldd
来检查自己。 在一个简单的测试程序中,我得到:
linux-vdso.so.1 => (0x00007fffd8305000) libc.so.6 => /lib/libc.so.6 (0x00007f646c669000) /lib/ld-linux-x86-64.so.2 (0x00007f646c9ca000)
但是,如果我链接-ldl
,我得到这个:
linux-vdso.so.1 => (0x00007fff644f1000) libdl.so.2 => /lib/libdl.so.2 (0x00007fb9b1375000) libc.so.6 => /lib/libc.so.6 (0x00007fb9b1014000) /lib/ld-linux-x86-64.so.2 (0x00007fb9b1579000)
即使我的程序没有使用libdl
。 但是,如果我使用-Wl,--as-needed
运行GCC -Wl,--as-needed
, libdl
将不会被链接。根据我的测试,这只适用于-Wl,--as-needed
在 -ldl
之前的命令行中列出。
有什么影响? 这意味着即使您不使用共享库,您的二进制文件也不会在没有共享库的系统上运行。 这也意味着如果升级共享库并卸载旧库,则二进制文件将中断。 这不是什么大问题,因为二进制兼容性无论如何都是一个熊,但我认为没有理由不开启-Wl,--as-needed
一般来说是项目-Wl,--as-needed
。
我编写了一个只使用STL的小应用程序。 它有8275字节的大小,没有链接到任何特定的库:
linux-gate.so.1 => (0x00e1e000) libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x0015a000) libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0x0044b000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00741000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00250000) /lib/ld-linux.so.2 (0x00a75000)
现在,当我编译它并将其与boost_thread链接时,它增长到8290字节 :
linux-gate.so.1 => (0x009d9000) libboost_thread.so.1.40.0 => /usr/lib/libboost_thread.so.1.40.0 (0x00e59000) libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x003a3000) libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0x00bc5000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00f8a000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00110000) libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0x00bf0000) librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0x00dd8000) /lib/ld-linux.so.2 (0x00ba3000)
请注意,我的代码上没有函数调用boost_thread的function。 但是,无论如何都会添加boost_thread作为我的应用程序的依赖项(正如您在ldd的输出中看到的那样)。
链接到共享库与链接静态库不同。 主要的差异已由@Dietrich Epp解释,但还有另一个重要细节。 共享库定义函数void _init()
和void _fini(void)
,这些函数在加载/卸载共享库时调用; 如果您不自己定义它们,链接器将添加默认存根。
如果您将程序链接到共享库,但是不引用库中的任何符号(并且不添加–as-needed链接器标志),也会调用这些。
大多数链接器将简单地省略最终二进制文件中未使用的对象,就像您首先没有链接到库一样。