共享库中的符号查找
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)相比,此功能会导致显着的性能损失。
我已经测试了下面这么简单的程序
/* 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)相比,此功能会导致显着的性能损失。