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

时间:2016-02-02 10:06:44

标签: c linux gcc glibc binutils

我有一个简单的测试程序,调用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符号时,在案例2中正在运行时使用哪个pthread_cond_broadcast符号。 pthread_cond_broadcast的最新实现?最古老的?
  3. 这是使用gcc 4.9.2和binutils 2.24中的gold / ld链接器(作为Red Hat的devtoolset-3的一部分。)

1 个答案:

答案 0 :(得分:1)

首先澄清:ELF文件通常有两个符号表。包含所有内部符号的“胖”或“完整”符号(通常位于.symtab类型为SHT_SYMTAB的部分中),并且存在仅包含运行时详细信息的“苗条”符号(通常在名为.dynsym的{​​{1}}类型的部分中。 SHT_DYNSYM仅解析第一个,因此它通常不是运行时行为的良好指标。您想要使用nm而是查看readelf -s表以查看在运行时实际上重要的内容。

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

(2)一旦你看到运行时符号表,你的答案就会自动出现:.dynsym将被使用。

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

(2b)为什么单个库有多个版本(例如pthread_cond_broadcast@GLIBC_2.3.2libc.sopthread_cond_broadcast@@GLIBC_2.2.5)?你正确地猜到它是为了向后兼容。在过去的某个时刻,ABI已被更改,因此他们不是破坏所有现有应用程序,而是更新了版本。所有与旧glibc版本链接的程序都将使用旧符号版本,而新程序将使用新符号。作为一项政策问题,glibc将最新的符号版本公开为默认版本,因此当您使用pthread_cond_broadcast@@GLIBC_2.3.2时,您将与pthread_cond_broadcast版本链接。这纯粹是大多数人都使用的惯例......虽然技术上可以将它们中的任何一个暴露为默认版本。

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