Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to statically link libstdc++ and wrap memcpy?

I am trying to build an executable on Linux that meets the following criteria:

  1. statically linked to libstdc++ and libgcc
  2. built with a recent version of gcc (version >= 4.8.2) and glibc (version > 2.14)
  3. 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.

like image 402
yoshimonster Avatar asked Apr 06 '16 20:04

yoshimonster


1 Answers

You need to wrap __wrap_memcpy in extern "C" {}, so that this function is is exported as a C function; otherwise its name will be decorated as a C++ function. In addition I strongly suggest some additional #ifdef, because this problem only occurs with later compiler versions and only for x64 (the conditions are not totally perfect, so may need to adjust them):

#if defined( __GNUC__ )  &&  defined( __LP64__ )  &&  __LP64__ >= 1  && \
(_GNUC__ >= 5  ||  (__GNUC__ == 4  &&  __GNUC_MINOR__ >= 7))  &&  \
(defined( __x86_64__ )  ||  defined( __i386__ )  ||\
defined( __i486__ )  ||  defined( __i586__ )  ||  defined( __i686__ ))

#include <string.h>

__asm__(".symver memcpy, memcpy@GLIBC_2.2.5");

extern "C"
{
void *__wrap_memcpy(void *dest, const void *src, size_t n)
{
    return memcpy(dest, src, n);
}
}

#endif
like image 91
Klingon Avatar answered Jun 27 '23 21:06

Klingon