链接到不进行函数调用的库有什么影响?

时间:2011-06-20 13:31:16

标签: c linker

我有一个程序的make文件,链接到libdl.so,并带有以下行-ldl。没有调用dlopen或任何相关函数。即使您不使用任何函数,以这种方式链接到此库会有什么影响?

4 个答案:

答案 0 :(得分:4)

您必须阅读链接器的文档。来自我的Linux / ELF / GNU Binutils系统上的info ld(强调添加):

`--as-needed'
`--no-as-needed'
     This option affects ELF DT_NEEDED tags for dynamic libraries
     mentioned on the command line after the `--as-needed' option.
     Normally the linker will add a DT_NEEDED tag for each dynamic
     library mentioned on the command line, regardless of whether the
     library is actually needed or not.  `--as-needed' causes a
     DT_NEEDED tag to only be emitted for a library that satisfies an
     undefined symbol reference from a regular object file or, if the
     library is not found in the DT_NEEDED lists of other libraries
     linked up to that point, an undefined symbol reference from
     another dynamic library.  `--no-as-needed' restores the default
     behaviour.

您可以通过在测试程序上运行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,则libdl将不会被链接。根据我的测试,只有在命令行之前列出-Wl,--as-needed时才能使用此功能 -ldl

有什么影响?这意味着即使您不使用共享库,您的二进制文件也不会在没有共享库的系统上运行。这也意味着如果升级共享库并卸载旧库,则二进制文件将中断。这不是什么大问题,因为无论如何二进制兼容性都是一个熊,但我认为没有理由不为项目开启-Wl,--as-needed

答案 1 :(得分:1)

我编写了一个只使用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的功能。但是,无论如何都会添加boost_thread作为我的应用程序的依赖项(正如您在 ldd 的输出中看到的那样)。

答案 2 :(得分:1)

链接到共享库与链接静态库不同。主要的差异已由@Dietrich Epp解释,但还有另一个重要细节。共享库定义了在加载/卸载共享库时调用的函数void _init()void _fini(void);如果你自己没有定义它们,链接器将添加默认存根。

如果您将程序与共享库链接,但也不会引用库中的任何符号(并且不添加--as-needed链接器标志),那么也会调用它们。

答案 3 :(得分:0)

大多数链接器将简单地省略最终二进制文件中未使用的对象,就像您首先没有与库链接一样。