Reputation: 11
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
@@
vs @
in the versioned symbolsWhy 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
?
i
mean in the output. man nm
saysFor 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.
libc.so
I have provide memcpy@@GLIBC_2.14
for others to link against?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?
__asm__
has no effectI 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?
Upvotes: 1
Views: 2812
Reputation: 11
As for Q3, I think it's because gcc is inlining its builtin version of memcpy. You have to pass -fno-builtin to gcc to force the use of libc's memcpy. Not sure if Q4 is also related to this.
I'm also looking for answers to the other questions. It's not relevant, but the reason libc has multiple memcpy versions is to guarantee backwards compatibility with programs that use memcpy with overlapping regions.
Upvotes: 1