共享库中的符号查找

symbol lookup in shared libraries

我已经测试了下面这么简单的程序

/* 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;
}

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

Search loaded objects' symbol tables for a definition of the symbol UNDEF_NAME, perhaps with a requested version for the symbol

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

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

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

编辑

如果您想知道为什么运行时链接器需要将 print_hello 中对 dispatch_write_hello 的调用解析为同一翻译单元中除 dispatch_write_hello 之外的任何内容 - 这是由所谓的语义引起的GCC 中的插入支持。默认情况下,编译器将库代码(即使用 -fPIC 编译的代码)内的任何调用视为在运行时可能可插入,除非您通过 -fvisibility-hidden-Wl,-Bsymbolic、[=18= 明确告诉它不要这样做] 或 __attribute__((visibility("hidden")))。这已在网上多次讨论,例如在臭名昭著的 Sorry state of dynamic libraries on Linux.

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