是否可以静态链接libstdc ++和wrap memcpy?

时间:2016-04-06 20:21:09

标签: glibc memcpy libstdc++

我正在尝试在Linux上构建符合以下条件的可执行文件:

  1. 静态链接到libstdc ++和libgcc
  2. 使用最新版本的gcc(版本> = 4.8.2)和glibc(版本> 2.14)构建
  3. 向后兼容旧版本的glibc(版本<2.5)
  4. 我当前的开发环境是CentOS 7上的gcc4.8.5,glibc 2.17。构建的二进制文件不适用于glibc&lt; 2.14由于对memcpy的依赖。

    objdump -T main | fgrep GLIBC_2.14
    0000000000000000      DF *UND*  0000000000000000  GLIBC_2.14  memcpy
    

    glibc 2.14中引入的memcpy发生了重大变化,所以我想强制使用旧版本。我遇到了这个stackoverflow帖子Linking against older symbol version in a .so file,但由于与libstdc ++相关的链接器问题,它对我不起作用。以下是我尝试解决方案的问题。

    的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);
    }
    

    编译器选项和错误:

    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
    

    我在这里做错了什么?我还尝试了堆栈溢出帖中的其他解决方案,我得到了同样的错误。我也尝试在Ubuntu 15.0.4上的glibc 5.2.1上构建它并获得相同的结果。请注意,由于许可问题,将memcpy(在GPL许可下)静态链接到二进制文件不是一种选择。

1 个答案:

答案 0 :(得分:6)

你需要在外部&#34; C&#34;中包装__wrap_memcpy。 {},这个函数被导出为C函数;否则它的名称将被装饰为C ++函数。 另外我强烈建议一些额外的#ifdef,因为这个问题只发生在以后的编译器版本中,而且只发生在x64上(条件不完全完善,所以可能需要调整它们):

#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