GLIBC_2.14 兼容问题 version `GLIBC_2.14′ not found

来源:互联网 发布:知乎爆料明星人品 编辑:程序博客网 时间:2024/06/07 04:58

原帖:http://b.liuctic.com/2013/11/glibc_2-14-%E5%85%BC%E5%AE%B9%E9%97%AE%E9%A2%98-lib64libc-so-6-version-glibc_2-14-not-found/


这个问题出现在我在台式机上编译binary之后,直接到目标服务器上运行。

./mybin: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./mybin)./mybin: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by ./mybin)

本地的台式机gcc版本为4.6.3, libc版本为2.15, libstdc++版本为libstdc++.so.6.0.16。服务器的gcc版本为4.1.2,libc版本为2.5,libstdc++版本为libstdc++.so.6.0.8。

1 查找版本不兼容的函数

~: objdump -T mybin | fgrep GLIBC_2.140000000000000000 DF *UND* 0000000000000000 GLIBC_2.14 memcpy

可以看到mybin需要调用GLIBC_2.14中的memcpy实现,在目标机上运行:

#: objdump -T /lib64/libc.so.6 | fgrep memcpy00000032be87bdb0 g DF .text 0000000000000465 GLIBC_2.2.5 memcpy

也就是说目标机上的libc只提供了memcpy@GLIBC_2.2.5的实现,所以导致mybin无法运行。

再在本机上运行一次上面的命令(使用ldd查看实际调用的libc路径):

~: objdump -T /lib/x86_64-linux-gnu/libc.so.6 | fgrep memcpy00000000000917f0 g iD .text 000000000000003c GLIBC_2.14 memcpy000000000008bbd0 g iD .text 0000000000000047 (GLIBC_2.2.5) memcpy

这说明了在本机上是可以同时使用memcpy@GLIBC_2.2.5和memcpy@GLIBC_2.14的,那么为了保证最大兼容性,有没有什么方法可以强制链接memcpy@GLIBC_2.2.5呢?当然是有的,不然我还写这篇做什么。

2 .symver 绑定符号版本
这篇文章中给出了一个realpath的例子:Linking to Older Versioned Symbols (glibc)

#include <limits.h>#include <stdlib.h>#include <stdio.h>__asm__(".symver realpath,realpath@GLIBC_2.2.5");int main(){   char* unresolved = "/lib64";   char  resolved[PATH_MAX+1];   if(!realpath(unresolved, resolved))      { return 1; }   printf("%s\n", resolved);   return 0;}

这种方案可以简单的解决代码中的显式函数调用。
但在mybin源代码中并没有直接使用memcpy函数,而是mybin链接的其它库中调用了memcpy,显然这种方案是行不通了。

3 –wrap 选项
首先写一个文件 memcpy.c, 定义函数__wrap_memcpy,然后用.symver显示指定__memcpy_glibc_2_2_5链接到memcpy@GLIBC_2.2.5上。

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

然后在链接时使用选项 -Wl,–wrap=memcpy
如果使用cmake编译链接,需要在CMakelists.txt里增加如下选项:

SET_TARGET_PROPERTIES( mybin PROPERTIES LINK_FLAGS "${LINK_FLAGS} -Wl,--wrap=memcpy" )

重新生成mybin之后,再次使用objdump查看

0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 memcpy000000000047355c g DF .text 000000000000002d Base __wrap_memcpy

可以看到调用的是memcpy@GLIBC_2.2.5

4 GLIBCXX 版本兼容问题
有两个方案可以解决,一是链接libstdc++的静态库,二是把本机的libstdc++.so一起打包发布,通过设置LD_LIBRARY_PATH使得mybin可以调用打包的libstdc++.so。

另外补充一个问题,之前看到有人说libstdc++是GPL协议的,所以如果想要打包发布,必须也要提供mybin的源代码。但是又搜了搜,发现libstdc++并不是plain GPL的,在我们这种简单链接应用的场景下是没有问题的。见这个回答和相关链接

5 2013.11.29 怒补充
在4里面语焉不详了一件事就是链接libstdc++的静态库。如果直接打包发布libstdc++.so的话,有可能出现的一个问题是在libstdc++.so中调用了GLIBC_2.14的函数,还是会导致最开始的问题,而且没办法通过wrap的方式解决。如果选择同时打包libc.so的话,libc.so的不同平台上兼容性很差(今天就遇到了一个)。于是又搜了下静态链接libstdc++,但是动态链接libc,于是就误入了康神的博客,所以回来怒更新。见这个帖子:从gcc静态链接开始的讨论,学了好几手

在CMakelists里就简单多了,显式指定 libstdc++.a 就可以了。这样就达到了静态链接libstdc++,但是动态链接libc的目的。

6 References
http://blog.kangkang.org/index.php/archives/17
http://micro.nicholaswilson.me.uk/post/31855915892/…
http://www.trevorpounds.com/blog/?p=103
http://stackoverflow.com/questions/4032373/…
https://gist.github.com/nicky-zs/7541169
http://www.cmake.org/pipermail/cmake/2003-August/004244.html
http://stackoverflow.com/a/3214398
http://lwn.net/Articles/549573/


0 0
原创粉丝点击