我有一个简单的测试程序,调用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
所以问题是:
gold
与旧/普通ld
之间的行为不同。pthread_cond_broadcast
符号时,在案例2中正在运行时使用哪个pthread_cond_broadcast符号。 pthread_cond_broadcast的最新实现?最古老的?这是使用gcc 4.9.2和binutils 2.24中的gold / ld链接器(作为Red Hat的devtoolset-3的一部分。)
答案 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.2
有libc.so
和pthread_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(即抓取互斥锁等等)。