why /lib32/libc.so.6 has two "fopen" symbol in it?

1.1k views Asked by At
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

here is my question:

  1. why /lib32/libc.so.6 has two fopen symbol in it ? identical symbol in same target file should be forbidden ,right?

  2. why readelf -s dump out fopen@@GLIBC_2.1 and fopen@GLIBC_2.0 instead of fopen?

Thanks

2

There are 2 answers

1
gby On BEST ANSWER

Actually multiple definitions of the same symbol are fine and can happen in a number of ways. One of them (which isn't the case here) are weak symbols.

What happens here is that glibc dynamic linker supports symbol versioning and glibc uses that. It exports a version of fopen from glibc 2.1 and a backward compatible version from glibc 2.0 with difference interfaces.

At dynamic link time the application can chose a specific version or a default one.

0
Employed Russian On

In order to understand what is happening here, you first need to understand how binary compatibility has been handled traditionally.

The mechanism used to be "external versioning". You started with libfoo.so.1, and when you needed to change the ABI of an existing function, you were forced to introduce libfoo.so.2.

The applications that were linked before libfoo.so.2 continued to use libfoo.so.1 with the old ABI, and the new aplications used libfoo.so.2 with the new ABI.

This is all described in some detail here.

But then glibc introduced an extension, where instead of introducing a whole new library (that shares 99% of the code with previous verson), you introduce a new symbol into an existing library.

That extension is what allowed libc.so.6 to stay at version 6 for years, while allowing old binaries to work, and for the ABI to evolve.

In the particular case of fopen, an incompatible change to struct FILE was made in version 2.1 of glibc. Binaries that were linked on glibc-2.0 systems continue to use the old struct FILE (the only one that was available back then), and continue to call _IO_old_fopen (for which fopen@GLIBC_2.0 is an alias). Binaries linked against glibc-2.1 and newer use the new struct FILE, and call _IO_new_fopen (for which fopen@GLIBC_2.1 is an alias).

The @@ is just a notation showing the current default symbol version.