glibc - 是否可以静态链接 libstdc++ 并包装 memcpy?

标签 glibc memcpy libstdc++

我正在尝试在 Linux 上构建一个满足以下条件的可执行文件:

  • 静态链接到 libstdc++ 和 libgcc
  • 使用最新版本的 gcc(版本 >= 4.8.2)和 glibc(版本 > 2.14)构建
  • 向后兼容旧版本的 glibc(版本 < 2.5)

  • 我当前的开发环境是 CentOS 7 上的 gcc4.8.5、glibc 2.17。由于依赖于 memcpy,构建的二进制文件在 glibc < 2.14 的系统上不起作用。
    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++ 相关的链接器问题,它对我不起作用。这是我对以下解决方案的尝试。

    主程序
    #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 许可下)静态链接到二进制文件中。

    最佳答案

    需要将 __wrap_memcpy 包裹在 extern "C"{} 中,以便将该函数导出为 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
    

    关于glibc - 是否可以静态链接 libstdc++ 并包装 memcpy?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36461555/

    相关文章:

    c - 移植glibc 2.25并测试内存功能

    linux - 加载共享库 libstdc++.so.5 时出错

    c++ - 如何使用 dtrace 打印 libstdc++ 字符串内容

    linux - 我已经强制安装了 glibc 2.3 版本,之后我无法运行任何 linux cmd,因为它要求 glibc 2.4

    c - %ms 和 %s scanf 之间的区别

    c - 为什么 pthread_self 被标记为 attribute(const)?

    c++ - 我没有直接在我的程序中使用的 memcpy 偶尔崩溃

    c - linux 上的 memcpy 段错误,但 os x 上没有

    c - 从指向数组的指针使用 memcpy

    c++ - Clang 拒绝编译 libstdc++ 的 <filesystem> header