当使用黄金与ld链接器时,使用glibc / pthreads中的不同符号

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

链接到ld链接器时,显示如下:

情况1:

 $ 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符号时,哪个pthread_cond_broadcast符号在运行时被使用。 pthread_cond_broadcast的最新实现? 最老的 ?

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

首先澄清:ELF文件通常有两个符号表。 有一个包含所有内部符号的“fat”或“full”,通常在一个名为.symtab类型的SHT_SYMTAB ,还有一个只包含运行时细节的“slim”键入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(即抢互斥/ etc …)。