【问题标题】:Isn't ld checking for unresolved symbols in shared libraries redundant?ld 检查共享库中未解析的符号不是多余的吗?
【发布时间】:2017-06-11 10:23:21
【问题描述】:

将程序链接到共享对象时,ld 将确保可以解析符号。这基本上保证了程序与其共享对象之间的接口是兼容的。在阅读了Linking with dynamic library with dependencies 之后,我了解到ld 将下降到链接的共享对象并尝试解析它们的符号。

当共享对象本身链接时,我的共享对象的引用不是已经检查了吗?

我可以理解在链接时找出程序是否具有启动所需的所有部分的吸引力,但是在共享对象可能单独分发的包构建的上下文中这似乎无关紧要(Debian 的 lib* 包,例如)。它在对执行构建程序不感兴趣的系统上引入了递归构建依赖项。

我可以相信构建共享对象时解决的依赖关系吗?如果是这样,在构建我的程序时使用 -unresolved-symbols=ignore-in-shared-libs 有多安全?

【问题讨论】:

    标签: linker dependencies ld


    【解决方案1】:

    您想知道为什么程序的链接要费心去解析源自 与其链接的共享库,因为:

    当共享对象本身链接时,我的共享对象的引用不是已经检查了吗?

    不,它们不是,除非您在链接共享库时明确坚持,

    这里我要建一个共享库libfoo.so

    foo.c

    extern void bar();
    
    void foo(void)
    {
        bar();
    }
    

    例行编译链接:

    $ gcc -fPIC -c foo.c
    $ gcc -shared -o libfoo.so foo.o
    

    没问题,bar 未定义:

    $ nm --undefined-only libfoo.so | grep bar
                    U bar
    

    我需要坚持让链接器反对:

    $ gcc --shared -o libfoo.so foo.o -Wl,--no-undefined
    foo.o: In function `foo':
    foo.c:(.text+0xa): undefined reference to `bar'
    

    当然:

    ma​​in.c

    extern void foo(void);
    
    int main(void)
    {
        foo();
        return 0;
    }
    

    它不会让我将libfoo 链接到一个程序

    $ gcc -c main.c
    $ gcc -o prog main.o -L. -lfoo
    ./libfoo.so: undefined reference to `bar'
    

    除非我也在同一个链接中解析bar

    bar.c

    #include <stdio.h>
    
    void bar(void)
    {
        puts("Hello world!");
    }
    

    也许通过从另一个共享库获取它:

    gcc -fPIC -c bar.c
    $ gcc -shared -o libbar.so bar.o
    $ gcc -o prog main.o -L. -lfoo -lbar
    

    然后一切都很好。

    $ export LD_LIBRARY_PATH=.; ./prog
    Hello world!
    

    它是共享库的本质,默认情况下它没有 在链接时解析其所有符号。这样一来,程序 - 通常确实需要它的所有符号解析一个链接时间 - 可以获得它的所有符号 通过与多个库链接来解决。

    【讨论】:

    • 通过我所做的测试,留下的印象是在创建共享对象时检查了引用。这让我想知道为什么不是这样,但是对于 @yugr 提出的案例,在构建库时检查引用会导致鸡和蛋的问题。
    • @Mike:有什么理由不将-Wl,--no-undefined 传递给链接器吗?
    • @Andreas 不,没有!我忘了我只是试图输出一个.so禁止未定义的符号而不是输入一个。固定的,很好的收获。
    【解决方案2】:

    我的共享对象的引用不是已经检查了吗 共享对象本身何时链接?

    嗯,共享库可能已与 -Wl,--allow-shlib-undefined 或虚拟依赖项链接,因此检查它们仍然有意义。

    我可以相信构建共享对象时解决的依赖关系吗?

    可能不是,当前的链接环境和链接原始shlibs的环境可能不同。

    如果是这样,使用 -unresolved-symbols=ignore-in-shared-libs 有多安全 在构建我的程序时?

    在这种情况下,您可能会遗漏潜在的错误(或者将它们延迟到运行时,这仍然很糟糕)。想象这样一种情况,共享对象所需的一些符号来自可执行文件本身或来自可执行文件链接的库之一(但 不是 由缺少符号的 shlib 链接)。

    编辑

    虽然上面是正确的,但 Mike Kinghan 的回答给出了更有力的论据,支持在可执行链接期间在库中解析符号。

    【讨论】:

    • 但是,如果您正在构建用于分发的软件,您的构建环境也可能与部署的环境不同。至于使用 allow-undefined 构建的库,在手头的情况下,我也会控制它们的构建。为可执行文件本身中定义的符号+1,没有想到这一点。这听起来像是一种利基用法(主要是插件界面)。这很常见吗?
    • @elik “但是,如果您正在构建用于分发的软件,您的构建环境也可能与部署的环境不同” - 是的,在这种情况下,您会在运行时收到错误消息。但最好尽早发现不兼容性。 “这听起来像是一种小众用法(主要是插件界面)。这很常见吗?” - 不是很常见,但我添加了一个 很常见的用例。
    • @elik 总而言之,我认为迈克的回答更正确——他支持在可执行链接期间进行符号解析的论点比我的强(尽管我仍然持有)。
    • 你能举一个具体的编辑例子吗?我了解它,我了解如何使用它,但我不认为它很常见。
    • 虽然我很欣赏@Mike 的回答(我不知道没有检查符号),但您提供了更有力的论据,说明为什么这样做是一个坏主意。
    猜你喜欢
    • 2010-12-09
    • 2010-10-17
    • 1970-01-01
    • 2014-03-06
    • 2021-08-20
    • 2017-08-02
    • 2011-04-25
    • 1970-01-01
    • 2016-10-16
    相关资源
    最近更新 更多