【问题标题】:Different symbols from glibc/pthreads used when using gold vs ld linker使用gold vs ld链接器时使用的来自glibc/pthreads的不同符号
【发布时间】:2016-05-11 01:48:05
【问题描述】:

我有一个简单的测试程序调用pthread_cond_broadcast

当与ld 链接器链接时,会显示:

案例一:

$ nm ld-test  | grep cond_broadcast
U pthread_cond_broadcast@@GLIBC_2.3.2

当与gold 链接器链接时,它显示:

案例 2:

 $ nm gold-test  | grep cond_broadcast
 U pthread_cond_broadcast

pthread/libc 包含几个具有不同版本符号的 pthread_cond_broadcast 符号,大概是因为 ABI 已更改。

$ nm  /lib64/libc.so.6  |grep cond_broadca
00000036b84f7d30 t __pthread_cond_broadcast
00000036b85278f0 t __pthread_cond_broadcast_2_0
00000036b84f7d30 T pthread_cond_broadcast@@GLIBC_2.3.2
00000036b85278f0 T pthread_cond_broadcast@GLIBC_2.2.5
$ nm  /lib64/libpthread.so.0  |grep cond_broadcast
00000036b880bee0 t __pthread_cond_broadcast
00000036b880c250 t __pthread_cond_broadcast_2_0
00000036b880bee0 T pthread_cond_broadcast@@GLIBC_2.3.2
00000036b880c250 T pthread_cond_broadcast@GLIBC_2.2.5

所以问题是:

  1. 为什么gold 和旧的/正常的ld 之间的行为不同。
  2. 当二进制文件链接到未版本化的pthread_cond_broadcast 符号时,在情况 2 中运行时使用了哪个 pthread_cond_broadcast 符号。 pthread_cond_broadcast 的最新实现?最古老的?

这是使用 gcc 4.9.2 和 binutils 2.24 中的 gold/ld 链接器(作为 Red Hat 的 devtoolset-3 的一部分。)

【问题讨论】:

    标签: c linux gcc glibc binutils


    【解决方案1】:

    首先澄清一下:ELF 文件通常有两个符号表。有一个“胖”或“完整”包含所有内部符号(通常在一个名为 .symtab 类型为 SHT_SYMTAB 的部分中),还有一个“瘦”只包含运行时详细信息(通常在一个名为.dynsym 类型为 SHT_DYNSYM)。 nm 仅解析第一个,因此它通常不是运行时行为的良好指标。您想改用 readelf -s 并查看 .dynsym 表以了解运行时真正重要的内容。

    (1) 我不知道为什么在使用黄金时调试符号表不包括完整的符号版本。对我来说似乎是一个错误。

    (2) 查看运行时符号表后,您的答案会自行出现:pthread_cond_broadcast@GLIBC_2.3.2 将被使用。

    (2a) 至于该符号将从哪个 加载,这完全取决于 ELF 的链接方式及其运行时环境。让我们忽略所有可能性并关注常见的可能性:如果您与 -lpthread 链接,则将使用 libpthread.so 中的版本。如果没有,则使用 libc.so 中的版本。

    (2b) 为什么一个库有多个版本(例如libc.sopthread_cond_broadcast@@GLIBC_2.2.5pthread_cond_broadcast@@GLIBC_2.3.2)?你猜对了,它是为了向后兼容。在过去的某个时候,ABI 发生了变化,因此他们没有破坏所有现有的应用程序,而是更新了版本。所有与旧 glibc 版本链接的程序都将使用旧符号版本,而新程序将使用新符号。作为一项政策,glibc 将最新的符号版本公开为默认版本,因此当您使用pthread_cond_broadcast 时,您将链接到pthread_cond_broadcast@@GLIBC_2.3.2 版本。这纯粹是大多数人都使用的约定……尽管技术上可以将其中任何一个公开为默认版本。

    (2c) 为什么 libc.so 和 libpthread.so 中都存在符号?这允许库支持多线程环境,而不会在单线程环境中受到惩罚,或者不必编写两个不同的库,例如一个名为 libfoo.so,一个名为 libfoo_thread.so。 libc.so 中的符号是虚拟符号——它们总是返回“成功”。因此,如果您的主程序不是多线程的,则 libfoo.so 中的所有调用都将被删除。但是如果您的主程序是多线程的(即针对-lpthread 的链接),那么这些符号将被透明地自动路由到libpthread.so,并且libfoo.so 中的所有调用都将DTRT(即获取互斥锁/等...)。

    【讨论】:

      猜你喜欢
      • 2018-01-11
      • 2011-04-09
      • 1970-01-01
      • 2015-06-04
      • 2011-04-11
      • 1970-01-01
      • 1970-01-01
      • 2019-07-03
      • 1970-01-01
      相关资源
      最近更新 更多