使用gold vs ld链接器时使用的glibc/pthreads中的不同符号

bin*_*y01 6 c linux gcc glibc binutils

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

ld链接器链接时,显示:

情况1:

$ nm ld-test  | grep cond_broadcast
U pthread_cond_broadcast@@GLIBC_2.3.2
Run Code Online (Sandbox Code Playgroud)

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

案例2:

 $ nm gold-test  | grep cond_broadcast
 U pthread_cond_broadcast
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

所以问题是:

  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的一部分.)

Mik*_*ger 1

首先澄清一下:ELF 文件通常有两个符号表。.symtab一种是包含所有内部符号的“fat”或“full”(通常在名为type 的部分中SHT_SYMTAB),另一种是“slim”仅包含运行时详细信息(通常在名为.dynsymtype 的部分中SHT_DYNSYM)。 nm仅解析第一个,因此它通常不能很好地指示运行时行为。您想使用readelf -s它并查看.dynsym表以了解运行时真正重要的内容。

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

(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(即获取互斥体/等...)。