Why /Lib32/Libc.So.6 Has Two "Fopen" Symbol in It

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

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.

why I can't set breakpoint at fopen in linux

It's a bug in GDB, which appears to be fixed in current CVS sources (as of 20120124).

The problem is that there are two versions of fopen in 32-bit libc.so.6 on Linux, and GDB used to select the wrong one:

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

If you also break on main, and repeat info break, you'll see that GDB set the breakpoint on fopen@GLIBC_2.0, but the function that is called is the fopen@@GLIBC_2.1.

Mismatch between output of ldd --version and ldd -r -v a.out

You should read this answer, and look at the output from readelf -V a.out.

When a program is linked, it records the symbol version(s) used (current) at the time of the link.

Many of the symbols your program is using have not changed since e.g. GLIBC_2.2.5, so ldd says: you need at least version GLIBC_2.2.5 (for these symbols). Some of the symbols you use have changed in GLIBC-2.16, GLIBC-2.17 and GLIBC-2.18, so ldd says that you need these as well.

What would happen if I have compiled a binary on a system that has old version of libc.so (suppose has highest version of GLIBC as 2.17) and then run the binary on a system with new version of libc.so (suppose has highest version of GLIBC as 2.31) ?

The recorded symbols (encoded into a.out) will all be GLIBC_2.17 or older, and the program will run fine on a newer system, because GLIBC guarantees backward compatibility (programs built on an older system continue to run fine on newer ones).

But if you did the inverse -- built on a GLIBC-2.31 system and tried to run the program on a GLIBC-2.17 one, it may (or may not, depending on which symbols it actually uses) fail.

In the example you provided, the highest required version of GLIBC is GLIBC_2.18. Therefore, this particular a.out will work fine on a GLIBC-2.18 or newer system, but will fail on GLIBC-2.17 or older one.

Update:

What happens if an executable that is compiled on an old system which has highest version of GLIBC_2_17, is run on a system that has GLIBC_2_31 available? Will the executable pick the latest symbols (if they are ABI complaint) eg say memcpy - exec compiled on old system (with GLIBC without vector support) when run on new system (with GLIBC that has memcpy with vector support) will pick memcpy from new GLIBC that has vector support.

Yes, the executable will pick up the version it was linked with, and so long as the ABI for a given function hasn't changed, it will be the most recent version.

The case of memcpy in particular is a bit more complicated. On Fedora 35 x86_64 system (GLIBC-2.34):

nm /lib64/libc.so.6 | grep ' memcpy'
00000000000a1560 i memcpy
00000000000a1560 i memcpy@@GLIBC_2.14
00000000000b9c30 T memcpy@GLIBC_2.2.5

What you can see here is that the memcpy ABI changed in GLIBC-2.14, and it became a GNU indirect function. You can read the details at the link, but TL;DR is that the actual function called by your program will depend on processor capabilities. It could be any one of these:

00000000001870b0 t __memcpy_avx512_no_vzeroupper
0000000000189f00 t __memcpy_avx512_unaligned
0000000000189f70 t __memcpy_avx512_unaligned_erms
00000000001828f0 t __memcpy_avx_unaligned
0000000000182960 t __memcpy_avx_unaligned_erms
000000000018b0e0 t __memcpy_avx_unaligned_erms_rtm
000000000018b070 t __memcpy_avx_unaligned_rtm
00000000000b9ca0 t __memcpy_erms
00000000001920b0 t __memcpy_evex_unaligned
0000000000192120 t __memcpy_evex_unaligned_erms
00000000000b9c30 t __memcpy_sse2_unaligned
00000000000b9d10 t __memcpy_sse2_unaligned_erms
000000000015d400 t __memcpy_ssse3
0000000000162990 t __memcpy_ssse3_back

gcc undefined reference even though ld finds the library and it contains the desired function

Could you be facing an

extern "C" 

problem?



Related Topics



Leave a reply



Submit