Linking against older symbol version in a .so file

前端 未结 11 1801
长发绾君心
长发绾君心 2020-11-27 11:25

Using gcc and ld on x86_64 linux I need to link against a newer version of a library (glibc 2.14) but the executable needs to run on a system with an older version (2.5). Si

相关标签:
11条回答
  • 2020-11-27 11:37

    I found the following working solution. First create file memcpy.c:

    #include <string.h>
    
    /* some systems do not have newest memcpy@@GLIBC_2.14 - stay with old good one */
    asm (".symver memcpy, memcpy@GLIBC_2.2.5");
    
    void *__wrap_memcpy(void *dest, const void *src, size_t n)
    {
        return memcpy(dest, src, n);
    }
    

    No additional CFLAGS needed to compile this file. Then link your program with -Wl,--wrap=memcpy.

    0 讨论(0)
  • 2020-11-27 11:38

    For nim-lang, I elaborated on a solution I found using the C compiler --include= flag as follows:

    Create a file symver.h with:

    __asm__(".symver fcntl,fcntl@GLIBC_2.4");
    

    Build your program with nim c ---passC:--include=symver.h

    As for me I'm cross compiling too. I compile with nim c --cpu:arm --os:linux --passC:--include=symver.h ... and I can get symbol versions using arm-linux-gnueabihf-objdump -T ../arm-libc.so.6 | grep fcntl

    I had to remove ~/.cache/nim at some point. And it seems to work.

    0 讨论(0)
  • 2020-11-27 11:48

    I had a similar problem. Trying to install some oracle components on RHEL 7.1, I got this:

    $ gcc -o /some/oracle/bin/foo .... -L/some/oracle/lib ... 
    /some/oracle/lib/libfoo.so: undefined reference to `memcpy@GLIBC_2.14'
    

    It seems that (my) RHEL's glibc only defines memcpy@GLIBC_2.2.5:

    $ readelf -Ws /usr/lib/x86_64-redhat-linux6E/lib64/libc_real.so | fgrep memcpy@
       367: 000000000001bfe0    16 FUNC    GLOBAL DEFAULT    8 memcpy@@GLIBC_2.2.5
      1166: 0000000000019250    16 FUNC    WEAK   DEFAULT    8 wmemcpy@@GLIBC_2.2.5
    

    So, I managed to get around this, by first creating a memcpy.c file without wrapping, as follows:

    #include <string.h>
    asm (".symver old_memcpy, memcpy@GLIBC_2.2.5");       // hook old_memcpy as memcpy@2.2.5
    void *old_memcpy(void *, const void *, size_t );
    void *memcpy(void *dest, const void *src, size_t n)   // then export memcpy
    {
        return old_memcpy(dest, src, n);
    }
    

    and a memcpy.map file that exports our memcpy as memcpy@GLIBC_2.14:

    GLIBC_2.14 {
       memcpy;
    };
    

    I then compiled my own memcpy.c into a shared lib like this:

    $ gcc -shared -fPIC -c memcpy.c
    $ gcc -shared -fPIC -Wl,--version-script memcpy.map -o libmemcpy-2.14.so memcpy.o -lc
    

    , moved libmemcpy-2.14.so into /some/oracle/lib (pointed to by -L arguments in my linking), and linked again by

    $ gcc -o /some/oracle/bin/foo .... -L/some/oracle/lib ... /some/oracle/lib/libmemcpy-2.14.so -lfoo ...
    

    (which compiled without errors) and verified it by:

    $ ldd /some/oracle/bin/foo
        linux-vdso.so.1 =>  (0x00007fff9f3fe000)
        /some/oracle/lib/libmemcpy-2.14.so (0x00007f963a63e000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f963a428000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f963a20c000)
        librt.so.1 => /lib64/librt.so.1 (0x00007f963a003000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f9639c42000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f963aa5b000)
    

    This worked for me. I hope it does it for you, too.

    0 讨论(0)
  • 2020-11-27 11:48

    It may caused by old ld (gnu link) version. For following simple problem:

    #include <string.h>
    #include <stdio.h>
    int main(int argc,char **argv)
    {
        char buf[5];
        memset(buf,0,sizeof(buf));
        printf("ok\n");
        return 0;
    }
    

    When I use ld 2.19.1, memset is relocated to: memset@@GLIBC_2.0, and cause crash. After upgraded to 2.25, it is: memset@plt, and crash solved.

    0 讨论(0)
  • 2020-11-27 11:52

    I think you can get away with making a simple C file containing the symver statement and perhaps a dummy function calling memcpy. Then you just have to ensure that the resulting object file is the first file given to linker.

    0 讨论(0)
  • 2020-11-27 11:58

    I had a similar issue. A third party library we use needs the old memcpy@GLIBC_2.2.5. My solution is an extended approach @anight posted.

    I also warp the memcpy command, but i had to use a slightly different approach, since the solution @anight posted did not work for me.

    memcpy_wrap.c:

    #include <stddef.h>
    #include <string.h>
    
    asm (".symver wrap_memcpy, memcpy@GLIBC_2.2.5");
    void *wrap_memcpy(void *dest, const void *src, size_t n) {
      return memcpy(dest, src, n);
    }
    

    memcpy_wrap.map:

    GLIBC_2.2.5 {
       memcpy;
    };
    

    Build the wrapper:

    gcc -c memcpy_wrap.c -o memcpy_wrap.o
    

    Now finally when linking the program add

    • -Wl,--version-script memcpy_wrap.map
    • memcpy_wrap.o

    so that you will end up with something like:

    g++ <some flags> -Wl,--version-script memcpy_wrap.map <some .o files> memcpy_wrap.o <some libs>
    
    0 讨论(0)
提交回复
热议问题