Today, when I use conda zlib to compile a binary, I encountered the error Undefined reference to memcpy@GLIBC_2.14
.
.../x86_64-conda-linux-gne/bin/ld: ...envs/myenv/lib/libz.so: undefined reference to memcpy@GLIBC_2.14
Although somebody asked similar questions, like this, they cannot solve my problem since I am using third party library.
I then try to understand what is happening. I did the following experiments:
~ $ ldd $CONDA_PREFIX/lib/libz.so
linux-vdso.so.1 (0x00007ffcc4a90000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe449c1a000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe449e70000)
~ $ nm $CONDA_PREFIX/lib/libz.so | grep memcpy
U memcpy@@GLIBC_2.14
~ $ nm -gD /lib/x86_64-linux-gnu/libc.so.6 | grep ' memcpy'
00000000000c7a30 T memcpy@GLIBC_2.2.5
00000000000ad1e0 i memcpy@@GLIBC_2.14
Q1: @@
vs @
in the versioned symbols
Why does nm libz.so
above show memcpy@@GLIBC_2.14
instead of memcpy@GLIBC_2.14
.
From all-about-symbol-versioning, I learnt that @@
is the default to be used if a symbol without version is requested. But If the libz.so
explicitly asks for memcpy@@GLIBC_2.14
, shouldn't the error be undefined reference to memcpy@@GLIBC_2.14
?
Q2: what does i
mean in the output. man nm
says
For ELF format files this indicates that the symbol is an indirect function. This is a GNU extension to the standard set of ELF symbol types. It indicates a symbol which if referenced by a relocation does not evaluate to its address, but instead must be invoked at runtime. The runtime execution will then return the value to be used in the relocation.
But I cannot understand what it means.
- Does the
libc.so
I have providememcpy@@GLIBC_2.14
for others to link against?
Q3: why my following code does not depend on symbol memcpy
I then coded a simple foo.c
file
#include <stdio.h>
#include <string.h>
int main()
{
char from[10] = "hello";
char to[10] = "";
printf("from <%s> to <%s>\n", from, to);
memcpy(to, from, 10);
printf("from <%s> to <%s>\n", from, to);
}
Compiling it gcc -c foo.c
and then nm foo.o
, I see the following:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T main
U printf
It has U printf
, but not U memcpy
. Why? Is this related to the i
type in Q?
Q4: why adding __asm__
has no effect
I added a line __asm__(".symver memcpy,memcpy@GLIBC_2.14");
to foo.c
, the result is the same. I then changed it to one of the following. Strangely, all of them will be compiled successfully, even some of them contains various typos.
__asm__(".symver memcpy,memcpy@GLIBC_2.14");
__asm__(".symver memcpy,memcpy@GLIBC_2.18");
2.18 does not exist__asm__(".symver memcpy,xxxxxx@GLIBC_2.18");
It seems it has no effect for memcpy
. I tested it for other functions like foo,foo@v1
and it works only if foo@v1
exists as an exported symbol. So I think the syntax and mechanism for versioned symbols is correct when foo
is used; but memcpy
is special.
How to explain this?