我有一个简单的测试程序调用pthread_cond_broadcast.
情况1:
$nm ld-test | grep cond_broadcast
U pthread_cond_broadcast@@GLIBC_2.3.2
案例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
所以问题是:
>为什么黄金和旧/普通ld之间的行为不同.
>当二进制文件链接到无版本的pthread_cond_broadcast符号时,在案例2中运行时使用了哪个pthread_cond_broadcast符号. pthread_cond_broadcast的最新实现?最老的 ?
这是使用gcc 4.9.2和binutils 2.24中的gold / ld链接器(作为Red Hat的devtoolset-3的一部分.)
(1)我不知道为什么调试符号表在使用黄金时不包含完整的符号版本控制.对我来说似乎是个错误.
(2)一旦查看运行时符号表,您的答案就会自动出现:将使用pthread_cond_broadcast@GLIBC_2.3.2.
(2a)关于将从哪个库加载的库,这完全取决于ELF的链接方式和运行时环境.让我们忽略所有的可能性并专注于常见的:如果你与-lpthread链接,那么将使用libpthread.so中的版本.如果你没有,那么将使用libc.so中的版本.
(2b)为什么单个库有多个版本(例如libc.so有pthread_cond_broadcast @@ GLIBC_2.2.5和pthread_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(即抓取互斥锁/等…).