1

我在下面测试过这样一个简单的程序

/* a shared library */
dispatch_write_hello(void)
{
        fprintf(stderr, "hello\n");
}

extern void
print_hello(void)
{
        dispatch_write_hello();
}

我的主程序是这样的:

extern void
dispatch_write_hello(void)
{
        fprintf(stderr, "overridden\n");
}

int
main(int argc, char **argv)
{
        print_hello();
        return 0;
}

该程序的结果是“覆盖”。
为了弄清楚为什么会发生这种情况,我使用了 gdb。调用链是这样的:
_dl_runtime_resolve -> _dl_fixup ->_dl_lookup_symbol_x
我发现_dl_lookup_symbol_xglibc中的定义是

在加载对象的符号表中搜索符号 UNDEF_NAME 的定义,可能带有符号的请求版本

所以我认为在尝试查找符号时dispatch_write_hello,它首先在主目标文件中查找,然后在共享库中查找。这就是这个问题的原因。我的理解对吗?非常感谢您的时间。

4

1 回答 1

2

鉴于您提到_dl_runtime_resolve,我假设您使用的是 Linux 系统(感谢@Olaf 澄清这一点)。

对您的问题的简短回答 - 是的,在符号插入期间,动态链接器将首先查看可执行文件内部,然后才扫描共享库。所以以定义dispatch_write_hello为准。

编辑

如果您想知道为什么运行时链接器需要解析对dispatch_write_helloin的调用,print_hello而不是dispatch_write_hello在同一个翻译单元中 - 这是由 GCC 中所谓的语义插入支持引起的。默认情况下,编译器将库代码中的任何调用(即用 编译的代码-fPIC)视为在运行时可能插入,除非您明确告诉它不要、通过-fvisibility-hidden、或。这已经在网上讨论过很多次了,例如在Linux 上臭名昭著的动态库的抱歉状态-Wl,-Bsymbolic-fno-semantic-interposition__attribute__((visibility("hidden")))

附带说明一下,与其他编译器(Clang、Visual Studio)相比,此功能会导致显着的性能损失。

于 2017-03-12T15:33:09.797 回答