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.