错误:/lib64/libc.so.6: version `GLIBC_2.14’ not found解决办法

不管你是用annoy还是用tensorflow,用pip安装后,然后import的时候会产生类似以下的异常:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/users/kinva/tools/lib/python2.7/site-packages/annoy/__init__.py", line 15, in <module>
    from .annoylib import *
ImportError: /lib64/tls/libc.so.6: version `GLIBC_2.14' not found (required by /home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so)
# 如果是TF就是lib/python2.7/site-packages/tensorflow/python/_pywrap_tensorflow.so

优先尝试这种方法:
python错误:/lib64/libc.so.6: version `GLIBC_2.14’ not found解决办法

我在这个问题上卡了很久,也查找了很多资料,都不能圆满解决glibc依赖的问题,连重新编译libc-2.14都试过了。
后来偶然发现了这篇文文章:Running new applications on old glibc 参考这篇文章的思路,这个问题才得以圆满解决(感谢文章的作者,同时感谢公司内部资料),下面根据这篇文章的思路来阐述如何逐步解决annoy或者tf依赖glibc的问题。

解决方案

解决方法主要包括两部分内容:

  • 减弱版本依赖以便在程序在启动的时候不被动态连接器终止
  • 提供缺失的依赖函数(由最新的glibc版本提供)

下面以annoy为例,TF类似的,自己替换文件路径即可

查看依赖

错误是由/home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so这个动态连接库引起的,那看一看这个so里到底哪部分依赖了glibc2.14。

# readelf -s 文件路径|grep GLIBC_2.14
readelf -s /home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so | grep GLIBC_2.14

输出如下:

108: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND memcpy@GLIBC_2.14 (7)
180: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND memcpy@@GLIBC_2.14

我们看到依赖了2.14的memcpy函数。

再来看一看annoylib.so中依赖的glibc版本信息,执行:

# readelf -V 文件路径
readelf -V /home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so

输出:


readelf1.png

可以看出在地址偏移量0x0050处,是glibc_2.14的标记地址,问题的关键是如何减弱这个版本依赖。
其思路就是想办法让这个glibc_2.14这个版本依赖变成可选而非强制性的。

更改glic_2.14依赖

  • 图中.gpu.version_r 的地址起始位置在文件偏移量0x002288处
  • glibc_2.14版本标记地址偏移量是0x0050,在文件地址偏移量的(0x002288+0x0050)
  • 指向0x0090偏移量的位置存放的是结构体Elfxx_Vernaux


    glibc1.png
  • vna_flags 是依赖信息,在结构体的第二个位置,ELFxx_Word是32bit,也就是4B,因此vna_flag的起始地址偏移量是0x04

通常Flags:none在二进制位置的值是0x0000,根据上述分析,为了能减弱glibc_2.14的版本依赖,需要在(0x002288+0x0050+0x04)处填充0x02(对应VER_FLG_WEAK)

因此执行:

# 要养成习惯,更改文件的时候,一定要备份
cp /home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so annoylib.so
# 更改为弱依赖
# 其中0x22dc需要自己计算0x002288+0x0050+0x04
# 这里替换2个地方,一个是地址,一个是文件路径,其他保持不变。
for addr in 0x22dc; do printf '\x02' | dd conv=notrunc of=/home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so  bs=1 seek=$((addr)) ; done

执行完了,我们验证效果:

# readelf -V 文件路径
readelf -V /home/users/kinva/tools/lib/python2.7/site-packages/annoy/annoylib.so
readelf2.png

看到2.14版本依赖已经变成weak了。成功了一半。

实现缺失的函数

接下来需要解决缺失的memcpy函数,最简单的方式是生成一个本地的动态库来实现缺失的函数,并在执行程序之前使用LD_PRELOAD去load这个动态库。
针对上文中指出的缺失的memcpy函数,如果查看实际的glibc_2.14实现的memcpy函数就会发现,其实际上和memmove相同,这样我们可以自己实现这个函数(mylibc.so):

#include <string.h>
void* memcpy(void *dest, const void *src, size_t n) {
    return memmove(dest, src, n);
}

执行以下命令编译成so

gcc -s -shared -o mylibc.so -fPIC -fno-builtin mylibc.c

得到mylibc.so共享库
接下来就是链接动态库就好了。

  • 可以拷贝so到已经在引入的路径,如我的/home/users/kinva/tools/lib
  • 或者 export LD_LIBRARY_PATH=/home/users/kinva/tools/mylib:$LD_LIBRARY_PATH

再次执行:

[kinva@MacBook-Pro ~]$ python
Python 2.7.3 (default, Jan 24 2017, 17:03:37) 
[GCC 3.4.5 20051201 (Red Hat 3.4.5-2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import annoy
>>> 

其他问题

如果还是继续报错,请注意报的so已经不一样了,把每一个so的问题都解决。
如果你依赖的gcc是4.8+,请用4.6版本,否则你要拥有root权限。

TF需要更改的文件:
_pywrap_tensorflow.so
libstdc++.so.6(root权限)
librt.so.1
_sparse_feature_cross_op.so
_bucketization_op.so
_set_ops.so
_lstm_ops.so
_sdca_ops.so
需要实现的so有:mylibc.so和mygettime.so
memcpy和gettime相关,可以查查别的资料这个实现很简单的,我就不写了。

建议

这个东西根本原因就是系统版本库太老,如果更新glibc将会引起系统不稳定,所以建议还是升级系统吧。如果是centos,建议用6u3及以上版本。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容