在共享库中进行未解析符号的ld检查是否是多余的?

5
当将程序与共享对象链接时,ld会确保符号可以被解析。这基本上确保了程序和其共享对象之间的接口是兼容的。阅读完Linking with dynamic library with dependencies后,我了解到ld会进入链接的共享对象并尝试解决它们的符号。
当共享对象本身被链接时,我的共享对象引用不是已经被检查过了吗?
我可以理解在链接时找出程序是否具有启动所需的所有部件的吸引力,但是在构建软件包的上下文中似乎无关紧要,因为共享对象可能会单独分发(例如Debian的lib*软件包)。它在对不想执行构建程序的系统上引入了递归构建依赖项。
我可以相信共享对象构建时解决的依赖关系吗?如果可以,使用-unresolved-symbols=ignore-in-shared-libs构建程序时安全性如何?
2个回答

9
您可能会想,程序链接时为什么要解析源自共享库的符号,因为:

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

不,除非您在链接共享库时明确要求这样做。

下面我将构建一个名为 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'

当然:
主要.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提出的情况,当构建库时检查引用会导致一个先有鸡还是先有蛋的问题。 - elik
1
@Mike:你为什么不将“-Wl,--no-undefined”传递给链接器呢? - Andreas
@Andreas 没有这个问题!我忘记了,我只是试图输出一个.so文件,禁止未定义的符号,而不是输入一个。已修复,好发现。 - Mike Kinghan

2
我的共享对象在链接时已经检查了它们的引用,是吗?
共享库可能已经使用-Wl,--allow-shlib-undefined或虚拟依赖关系进行链接,因此仍然有必要进行检查。
我可以信任共享对象构建时解决的依赖项吗?
可能不能,当前链接环境和用于链接原始shlibs的环境可能不同。
那么,在构建我的程序时使用-unresolved-symbols = ignore-in-shared-libs安全吗?
在这种情况下,您可能会错过一些潜在的错误(或者将它们推迟到运行时,这仍然很糟糕)。想象一种情况,其中一些由共享对象所需的符号来自可执行文件本身或由被可执行文件链接的库之一提供的(但是没有被缺少符号的shlib链接)。
编辑
尽管上述内容是正确的,但Mike Kinghan的答案为支持在可执行文件链接期间对库中的符号进行符号分辨率提供了更强的论据。

但是,如果您正在构建软件进行分发,则构建环境可能与部署环境不同。至于使用allow-undefined构建的库,在这种情况下,我也将控制其构建。对于在可执行文件本身中定义的符号+1,我之前没有考虑过这一点。听起来像是一种小众用途(主要是插件接口)。这种情况常见吗? - elik
@elik “但是,如果您正在构建用于分发的软件,则构建环境可能与部署环境不同” - 是的,在这种情况下,您将在运行时获得错误。但最好尽早检测到不兼容性。 “听起来像是一个小众用途(主要是插件接口)。这很常见吗?” - 不是很常见,但我添加了另一个用例,它确实非常常见。 - yugr
你能给一个编辑方面的具体例子吗?我理解它,我知道我如何使用它,但我觉得它并不常见。 - elik
经过仔细审查我的问题,我认为你是正确的:@Mike回答了我的问题,这是一个简单的否定,共享库的符号在构建时不会被检查。他还告诉我如何使它们受到检查。这将导致后续问题:为什么。我认为你对此给出了很好的答案。你想让我把它作为一个单独的问题发布吗? - elik
@elik 嗯,我认为现在这样很好。 - yugr
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接