4
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?

谢谢

4

2 回答 2

9

为了了解这里发生了什么,您首先需要了解传统上如何处理二进制兼容性。

该机制曾经是“外部版本控制”。您libfoo.so.1libfoo.so.2.

之前链接的应用程序libfoo.so.2继续libfoo.so.1与旧 ABI 一起使用,而新应用程序libfoo.so.2与新 ABI 一起使用。

这一切都在这里进行了详细描述。

但随后 glibc 引入了一个扩展,而不是引入一个全新的库(与以前的版本共享 99% 的代码),而是在现有库中引入了一个新符号。

该扩展允许libc.so.6在版本 6 中保持多年,同时允许旧的二进制文件工作,以及 ABI 的发展。

在特定情况下fopen,在 glibc 的 2.1 版中对 进行了不兼容的更改。struct FILE在 glibc-2.0 系统上链接的二进制文件继续使用旧的struct FILE(当时唯一可用的),并继续调用_IO_old_fopen(这fopen@GLIBC_2.0是一个别名)。与 glibc-2.1 和更新版本链接的二进制文件使用 newstruct FILE和 call _IO_new_fopen(这fopen@GLIBC_2.1是别名)。

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

于 2012-02-06T07:34:18.690 回答
3

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

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

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

于 2012-02-06T06:53:24.180 回答