旧版glibc兼容旅程

一.背景

在新环境编译程序部署到老环境运行。

为什么不直接在老环境里面编译?因为用到了一点c++11的特性,需要较高版本的gcc进行编译;老环境默认的gcc版本太低,新版gcc的rpm包安装部署不上(glibc版本太低),源码安装高版本gcc又太麻烦。

二. 错误表现

注: server名字做过修改, 暂且叫my_server.

 

运行时报错,找不到GLIBC_2.14的符号:


而本机glibc的版本才2.12:

 


glibc官方最新版本虽然为glibc_2.23. 但是编译机gblic版本为glibc_2.17.

所以只需要查看my_server用到了哪些>2.12, <=2.17的glibc符号即可:

如图所示, 只有一个memcpy超过了本机glibc的版本.

 

三. 问题解决

现在得想办法去除对高版本(2.14)memcpy的引用, 改为引用对应的低版本.

3.1静态链接

最简单的办法无非是静态链接了,但是在链接时jemalloc跟libc有重复的符号定义:


 

去除对jemalloc的依赖, 编译通过, 但是有一堆告警, 部分告警如下:

 


考虑到多线程环境下, 最好使用jemalloc(或者tcmalloc)来管理内存分配和释放. 所以不能去除对它的依赖, 也就不能用静态链接.

 

3.2符号版本指定

3.2.1编译时符号指定

如果用动态链接的话, 就要想办法在编译的时候强制引用2.12(运行环境的glibc版本)以下版本的memcpy.

 

先看看运行环境下的memcpy的版本:


nm没有看到版本信息.

 

试试objdump:


显示当前环境的memcpy版本是GLIBC_2.2.5.

 

接下来就是想办法在动态链接的时候强制引用memcpy的2.2.5版.

用汇编指令.symver可以完成版本指定(确保在所有调用 memcpy之前完成汇编指令的版本指定):


但是编译之后发现依旧引用了2.14版的memcpy

 

一开始以为是汇编指令不管用, 后来发现链接的若干公共库(.a)也有对memcpy的引用,因为公共库在编译的时候已经指定了对memcpy的2.14版, 所以这里的汇编指令对其是没有效果的.看来还是要在链接的时候做一些手脚.

3.2.2链接时符号指定

编译时指定符号版本对编译好的公共库不管用, 可以在链接的时候对引用的符号进行接管.

 

答案是使用ld的wrap功能, 选项说明如下:

 

a)     首先创建一个wrap函数

因为是在cpp代码中引用, 所以这里需要加extern “C”, 否则链接的时候会报错:

undefinedreference to __wrap_memcpy

 

b)      然后编译的时候注意加上-Wl,--wrap=memcpy(或者-Xlinker --wrap=memcpy)选项, 将—wrap选项传递给链接器. 编译完成后检查memcpy的符号:

很好,现在没有对memcpy的高本版的引用了. 放到运行环境运行看看:

对GLIBC的引用正常了, 现在又出现对GLIBCXX的引用问题.

 

my_server引用了3个GLIBCXX_3.4.14版的符号:

而运行环境最高只支持GLIBCXX_3.4.13:

c)     对GLIBC静态链接不满足需求, 但是单独将c++库进行静态链接是没有问题的, 于是编译时加上-static-libstdc++选项.

但是链接找不到stdc++库:

 

原来是因为编译环境只有c++的so库, 没有对应的静态库:

 

最后从一台云主机(gcc 4.8.4)下载了一个libcstdc++.a到开发机(gcc4.8.2),然后再编译链接,一切变得正常了.

 

四. 总结

1.  整体静态链接可以解决符号问题,但是会导致不能使用jemalloc(或者tcmalloc)

2.  用汇编指令.symver可以指定当前编译的memcpy版本, 却无法指定已经编译好的库中使用的memcpy的版本

3.  定义一个包装函数__wrap_memcpy, 在链接阶段(需要指定相应的—wrap选项)接管所有对memcpy的引用.

4.  单独将c++库进行静态链接.

不同版本glibc 库之间并不完全兼容,一般情况下,较新版本glibc 库可以向后兼容到较旧的版本,但不能向前兼容到较新的版本。以下是一些主要 glibc 版本之间的兼容性情况: - glibc 2.1 及以上版本兼容 glibc 2.0 - glibc 2.2 及以上版本兼容 glibc 2.1 - glibc 2.3 及以上版本兼容 glibc 2.2 - glibc 2.4 及以上版本兼容 glibc 2.3 - glibc 2.5 及以上版本兼容 glibc 2.4 - glibc 2.6 及以上版本兼容 glibc 2.5 - glibc 2.7 及以上版本兼容 glibc 2.6 - glibc 2.8 及以上版本兼容 glibc 2.7 - glibc 2.9 及以上版本兼容 glibc 2.8 - glibc 2.10 及以上版本兼容 glibc 2.9 - glibc 2.11 及以上版本兼容 glibc 2.10 - glibc 2.12 及以上版本兼容 glibc 2.11 - glibc 2.13 及以上版本兼容 glibc 2.12 - glibc 2.14 及以上版本兼容 glibc 2.13 - glibc 2.15 及以上版本兼容 glibc 2.14 - glibc 2.16 及以上版本兼容 glibc 2.15 - glibc 2.17 及以上版本兼容 glibc 2.16 - glibc 2.18 及以上版本兼容 glibc 2.17 - glibc 2.19 及以上版本兼容 glibc 2.18 - glibc 2.20 及以上版本兼容 glibc 2.19 - glibc 2.21 及以上版本兼容 glibc 2.20 - glibc 2.22 及以上版本兼容 glibc 2.21 - glibc 2.23 及以上版本兼容 glibc 2.22 - glibc 2.24 及以上版本兼容 glibc 2.23 - glibc 2.25 及以上版本兼容 glibc 2.24 - glibc 2.26 及以上版本兼容 glibc 2.25 - glibc 2.27 及以上版本兼容 glibc 2.26 - glibc 2.28 及以上版本兼容 glibc 2.27 - glibc 2.29 及以上版本兼容 glibc 2.28 - glibc 2.30 及以上版本兼容 glibc 2.29 - glibc 2.31 及以上版本兼容 glibc 2.30 - glibc 2.32 及以上版本兼容 glibc 2.31 不同版本glibc 库对应的 GCC 编译器版本也是不同的。以下是一些常见 GCC 编译器版本glibc版本的对应关系: - GCC 2.95.x 对应 glibc 2.1.x - GCC 3.x.x 对应 glibc 2.2.x - GCC 4.0.x 对应 glibc 2.3.x - GCC 4.1.x、4.2.x 对应 glibc 2.4.x - GCC 4.3.x、4.4.x 对应 glibc 2.5.x - GCC 4.5.x、4.6.x 对应 glibc 2.12.x - GCC 4.7.x、4.8.x 对应 glibc 2.15.x - GCC 4.9.x、5.x.x、6.x.x 对应 glibc 2.17.x - GCC 7.x.x、8.x.x 对应 glibc 2.26.x - GCC 9.x.x、10.x.x 对应 glibc 2.27.x - GCC 11.x.x 对应 glibc 2.33.x 需要注意的是,由于不同的发行版使用的库版本不同,因此实际情况可能会有所不同。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值