I am trying to build an executable on Linux that meets the following criteria:
- statically linked to libstdc++ and libgcc
- built with a recent version of gcc (version >= 4.8.2) and glibc (version > 2.14)
- backwards compatible with old versions of glibc (version < 2.5)
My current dev environment is gcc4.8.5, glibc 2.17 on CentOS 7. The binary built does not work on systems with glibc < 2.14 due to a dependency on memcpy.
objdump -T main | fgrep GLIBC_2.14
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.14 memcpy
There was a breaking change to memcpy introduced in glibc 2.14 so I want to force the use of an older version. I came across this stackoverflow post Linking against older symbol version in a .so file but it did not work for me due to linker issues related to libstdc++. Here's my attempt at a solution below.
main.cpp
#include <iostream>
#include <string.h>
int main(int argc, char** argv)
{
char source[] = "once upon a midnight dreary...", dest[4];
memcpy(dest, source, sizeof dest);
std::cout << dest << std::endl;
}
wrap_memcpy.cpp
#include <string.h>
__asm__(".symver memcpy, memcpy@GLIBC_2.2.5");
void *__wrap_memcpy(void *dest, const void *src, size_t n)
{
return memcpy(dest, src, n);
}
compiler options and errors:
g++ -static-libgcc -static-libstdc++ wrap_memcpy.cpp main.cpp -o main -Wl,--wrap=memcpy
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o): In function `std::ctype<char>::widen(char const*, char const*, char*) const':
(.text._ZNKSt5ctypeIcE5widenEPKcS2_Pc[_ZNKSt5ctypeIcE5widenEPKcS2_Pc]+0x5f): undefined reference to `__wrap_memcpy'
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o): In function `std::__timepunct<char>::__timepunct(__locale_struct*, char const*, unsigned long)':
(.text._ZNSt11__timepunctIcEC2EP15__locale_structPKcm[_ZNSt11__timepunctIcEC5EP15__locale_structPKcm]+0x96): undefined reference to `__wrap_memcpy'
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o): In function `std::messages<char>::messages(__locale_struct*, char const*, unsigned long)':
(.text._ZNSt8messagesIcEC2EP15__locale_structPKcm[_ZNSt8messagesIcEC5EP15__locale_structPKcm]+0x8e): undefined reference to `__wrap_memcpy'
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o): In function `std::messages_byname<char>::messages_byname(char const*, unsigned long)':
(.text._ZNSt15messages_bynameIcEC2EPKcm[_ZNSt15messages_bynameIcEC5EPKcm]+0xd6): undefined reference to `__wrap_memcpy'
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o): In function `std::__numpunct_cache<char>::_M_cache(std::locale const&)':
(.text._ZNSt16__numpunct_cacheIcE8_M_cacheERKSt6locale[_ZNSt16__numpunct_cacheIcE8_M_cacheERKSt6locale]+0x2ad): undefined reference to `__wrap_memcpy'
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/libstdc++.a(locale-inst.o):(.text._ZNSt16__numpunct_cacheIcE8_M_cacheERKSt6locale[_ZNSt16__numpunct_cacheIcE8_M_cacheERKSt6locale]+0x2cd): more undefined references to `__wrap_memcpy' follow
collect2: error: ld returned 1 exit status
What am I doing wrong here? I've also attempted other solutions in the stack overflow post and I get the same error. I've also tried building this on glibc 5.2.1 on Ubuntu 15.0.4 and got the same result. Note that statically linking memcpy (which is under the GPL license) into the binary is not an option because of licensing issues.
memcpy
in your code withmemmove
, and then you won't need the oldmemcpy
. Alternatively, fix the code that depends on non-guaranteedmemcpy
behavior, but if that were easy you'd've already done it. – Doughtymemcpy
, then why are you trying to use it? (Put another way, why is it a problem for your binary to refer to the newmemcpy
?) – Doughty