原来,从glibc 2.1开始,引入了一种叫做 Symbol Versioning 的机制。

具体来说每个符号会对应一个版本号,在一个libc.so.6文件中可以包含一个函数的多个版本。

  1. > nm /lib64/libc.so.6 | grep " memcpy"

  2. 000000000008e860 i memcpy@@GLIBC_2.14

  3. 0000000000089650 i memcpy@GLIBC_2.2.5

例如在上面的这个数据中,memcpy@@GLIBC_2.14代表默认版本(两个@),memcpy@GLIBC_2.2.5则代表最低版本。

所以在编译机上,链接的可执行程序会指向memcpy@@GLIBC_2.14,当它在另一台低版本的低于 2.14 版本的 glibc 机器上运行时就会找不到改符号。

在低版本的glibc机器上链接出来的可执行文件指向memcpy@GLIBC_2.2.5,依然可以在高版本 glibc 上运行,因为高版本 glibc 库中包含了该符号。

四、解决方案

我们面对一个问题,肯定需要去想办法解决了,总不能又回到c++98编译机去。

google 之后,看了大量的资料,发现有三种解决方案。

搜索结果中,99% 解决方案都是升级运行环境的 glibc 。

在个人的 VPS 或者 小公司只有几台机器的情况下,还可以接受,折腾一下就行了。

但是在几十上百台服务器上,升级 glic 是不可能的事情。

所以这个方法对我来说不可行。

然后剩下的 1% 解决方案中,又有 9 成的方法介绍在用到 memcpy 的 cpp 文件里加上__asm__(“.symver memcpy,memcpy@GLIBC_2.2.5”);

然而,我的机器的 glic 版本没有版本控制,只有一个 memcpy。

当初我以为是__asm__(“.symver memcpy,memcpy”);,结果没有解决问题。

经过查资料,最终在这里(https://gcc.gnu.org/wiki/SymbolVersioning)找到方法。

升级glibc版本_升级glibc系统崩溃_glibc升级

原来我只需要在对应的头文件里加上__asm__(“.symver memcpy,memcpy@”);即可,那个@必须加上。

这个方法的可行性测试通过了。

然而,我的项目文件不是一个,有几十个。各种库里都使用了memcpy, 这时候上面的方法也不行了。

又经过大量查阅资料,在 stackoverflow 上(http://stackoverflow.com/a/20065096/1881299)了解到链接器有一个wrap 参数,可以在链接的时候动态的替换符号。

简单来说,我们需要写一个通用的符号替换函数,然后在链接目标文件时,使用命令-Wl,–wrap=memcpy来主动指定 memcpy 的符号号版本,这样就可以对所有的文件进行符号替换了。

升级glibc系统崩溃_glibc升级_升级glibc版本

这样实现后,编译出的程序终于可以正常的运行了。

五、最后

linux 下的符号问题有很多,每次都会遇到不一样的。

对于 glibc 版本问题本以为只有升级这一个方案,没想到竟然有这么完美的不升级的方案,但是网上又是少之又少,甚是可惜。

这个问题查询资料时,发现一本不错的链接相关的电子书,分享给大家,公众号后台发送“The GNU linker”免费领取。

注:需要发送引号里面完整的名称,建议长按复制,然后去后台发送。

注2:这篇文章的参考文章,可以点击原文阅读,在原文里面可以得到相关链接。

-EOF-

———END———
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,永久会员只需98元,全站资源免费下载 点击查看详情
站 长 微 信: yjxmw518