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:
why /lib32/libc.so.6 has two fopen symbol in it ? identical symbol in same target file should be forbidden ,right?
why readelf -s dump out fopen@@GLIBC_2.1 and fopen@GLIBC_2.0 instead of fopen?
Thanks
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.
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 introducelibfoo.so.2
.The applications that were linked before
libfoo.so.2
continued to uselibfoo.so.1
with the old ABI, and the new aplications usedlibfoo.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 tostruct FILE
was made in version 2.1 of glibc. Binaries that were linked on glibc-2.0 systems continue to use the oldstruct FILE
(the only one that was available back then), and continue to call_IO_old_fopen
(for whichfopen@GLIBC_2.0
is an alias). Binaries linked against glibc-2.1 and newer use the newstruct FILE
, and call_IO_new_fopen
(for whichfopen@GLIBC_2.1
is an alias).The
@@
is just a notation showing the current default symbol version.