为什么/lib32/libc.so.6中有两个“fopen”符号?

时间:2012-02-06 06:33:45

标签: linux nm readelf

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

这是我的问题:

  1. 为什么/lib32/libc.so.6中有两个fopen符号?应禁止同一目标文件中的相同符号,对吗?

  2. 为什么readelf -s转出fopen @@ GLIBC_2.1和fopen@GLIBC_2.0而不是fopen?

  3. 由于

2 个答案:

答案 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_fopenfopen@GLIBC_2.1为别名)。

@@只是一个显示当前默认符号版本的符号。

答案 1 :(得分:3)

实际上,同一符号的多个定义很好,并且可以以多种方式发生。其中一个(这里不是这种情况)是弱符号。

这里发生的是glibc动态链接器支持符号版本控制,glibc使用它。它从glibc 2.1导出fopen的版本,从glibc 2.0导出具有不同接口的向后兼容版本。

在动态链接时,应用程序可以选择特定版本或默认版本。