nm -D /lib32/libc.so.6 | grep '\<fopen\>'
0005d0c0 T fopen
00109750 T fopen
readelf -s /lib32/libc.so.6 | egrep '0005d0c0|00109750'
181: 0005d0c0 50 FUNC GLOBAL DEFAULT 12 fopen@@GLIBC_2.1
182: 00109750 136 FUNC GLOBAL DEFAULT 12 fopen@GLIBC_2.0
679: 0005d0c0 50 FUNC GLOBAL DEFAULT 12 _IO_fopen@@GLIBC_2.1
680: 00109750 136 FUNC GLOBAL DEFAULT 12 _IO_fopen@GLIBC_2.0
这是我的问题:
为什么/lib32/libc.so.6中有两个fopen符号?应禁止同一目标文件中的相同符号,对吗?
为什么readelf -s转出fopen @@ GLIBC_2.1和fopen@GLIBC_2.0而不是fopen?
由于
答案 0 :(得分:9)
为了理解这里发生的事情,首先需要了解传统上如何处理二进制兼容性。
该机制曾经是“外部版本控制”。您从libfoo.so.1
开始,当您需要更改现有函数的ABI时,您被迫引入libfoo.so.2
。
在libfoo.so.2
之前链接的应用程序继续使用libfoo.so.1
旧ABI,新应用程序将libfoo.so.2
与新ABI一起使用。
这一切都有详细描述here。
然后glibc引入了extension,而不是引入一个全新的库(与前一个版本共享99%的代码),你将一个新的符号引入现有的库中。
该扩展程序允许libc.so.6
在年中保留第6版,同时允许旧的二进制文件工作,并使ABI继续发展。
在fopen
的特定情况下,对struct FILE
的不兼容的更改是在glibc的2.1版本中进行的。在glibc-2.0系统上链接的二进制文件继续使用旧版struct FILE
(当时唯一可用的版本),并继续调用_IO_old_fopen
(其中fopen@GLIBC_2.0
是别名)。与glibc-2.1及更新版链接的二进制文件使用新的struct FILE
,并调用_IO_new_fopen
(fopen@GLIBC_2.1
为别名)。
@@
只是一个显示当前默认符号版本的符号。
答案 1 :(得分:3)
实际上,同一符号的多个定义很好,并且可以以多种方式发生。其中一个(这里不是这种情况)是弱符号。
这里发生的是glibc动态链接器支持符号版本控制,glibc使用它。它从glibc 2.1导出fopen
的版本,从glibc 2.0导出具有不同接口的向后兼容版本。
在动态链接时,应用程序可以选择特定版本或默认版本。