暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【技术】GLIBC_2.14 not found

天空的代码世界 2019-03-06
1842
对于 glibc 版本问题本以为只有升级这一个方案,没想到竟然有这么完美的不升级的方案,但是网上又是少之又少,甚是可惜

零、背景的背景

在Linux 后台开发中,最常见的问题就是符号问题了。
之前曾写过不少相关主题的文章,比如《符号的那些问题》、以及《静态库遇到静态库系列》,都是介绍符号的某个问题,今天遇到了另一个问题,简单记录一下。

一、背景

最近一年一直处于搭建中台的过度期,其中一步就是开发机 docker 化。
之前几百号人都在一台机器上开发编译程序,甚至一些新的毕业生或者实习生还在上面跑程序,往往会因为一个人的操作开发机要么CPU满了,要么磁盘满了,影响所有人开发与编译。
现在计划使用 docker 开发机,每人都是独立的环境:CPU、内存、磁盘都是独立的,再也没人来影响自己了。

当然,迁移 docker 后最最最重要的是可以使用  c++11 了, 原先的开发机只支持 c++98,万年不变的98终于可以被淘汰了。

开开心心的搭建自己的 docker 开发编译环境,实现计划中的业务功能,传到测试环境发现服务跑不起来。
原来遇到了 libc 版本不兼容问题,报这样的错误: /lib64/libc.so.6: version GLIBC_2.14' not found
 。

二、问题分析

这个问题看错误提示就可以知道,是由于运行环境 Glibc 版本 比 编译环境 Glibc 版本低的缘故

在运行环境下查看 glib 版本

  1. > strings /lib64/libc.so.6 |grep "^GLIBC_" | sort -u

  2. GLIBC_2.10

  3. GLIBC_2.11

  4. GLIBC_2.12

  5. GLIBC_2.2.5

  6. GLIBC_2.2.6

  7. GLIBC_2.3

  8. GLIBC_2.3.2

  9. GLIBC_2.3.3

  10. GLIBC_2.3.4

  11. GLIBC_2.4

  12. GLIBC_2.5

  13. GLIBC_2.6

  14. GLIBC_2.7

  15. GLIBC_2.8

  16. GLIBC_2.9

  17. GLIBC_PRIVATE

复制

在编译环境下查看 glib 版本

  1. > strings /lib64/libc.so.6 |grep "^GLIBC_" | sort -u

  2. GLIBC_2.10

  3. GLIBC_2.11

  4. GLIBC_2.12

  5. GLIBC_2.13

  6. GLIBC_2.14

  7. GLIBC_2.15

  8. GLIBC_2.16

  9. GLIBC_2.17

  10. GLIBC_2.2.5

  11. GLIBC_2.2.6

  12. GLIBC_2.3

  13. GLIBC_2.3.2

  14. GLIBC_2.3.3

  15. GLIBC_2.3.4

  16. GLIBC_2.4

  17. GLIBC_2.5

  18. GLIBC_2.6

  19. GLIBC_2.7

  20. GLIBC_2.8

  21. GLIBC_2.9

  22. GLIBC_PRIVATE

复制

原来运行环境的 glic 最高版本还是 2.12, 编译环境已经到2.17 了。

那看看编译出的程序呢

这里可以猜测: memcpy 符号可能有问题,用到了 glic2.14,运行机器没有这个版本。

再来看看 glibc里面 memcpy 的相关信息。

运行环境符号如下:

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

  2. 0000000000088320 T memcpy

  3. 00000000000a4030 t memcpy_uppcase


  4. > objdump -T /lib64/libc.so.6 | grep " memcpy"

  5. 0000000000088320 g DF .text 0000000000000465 GLIBC_2.2.5 memcpy

复制

编译环境符号如下:

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

  2. 000000000008e860 i memcpy@@GLIBC_2.14

  3. 0000000000089650 i memcpy@GLIBC_2.2.5


  4. > objdump -T /lib64/libc.so.6 | grep " memcpy"

  5. 000000000008e860 g iD .text 0000000000000055 GLIBC_2.14 memcpy

  6. 0000000000089650 g iD .text 000000000000004b (GLIBC_2.2.5) memcpy

复制

这里大概可以确定,编译程序的 memcpy 依赖于 GLIBC_2.14
,而我们的运行系统版本太低,不支持 GLIBC_2.14

三、符号版本

看到memcpy@@GLIBC_2.14
第一眼时,我们很容易粗略的猜测这个是符号的版本控制。
但是这些信息又是什么意思呢? 你有没有想去了解这些符号的版本到底是如何工作呢?

在这个文档(https://akkadia.org/drepper/symbol-versioning 里,我们可以查阅到符号版本的详细信息。

原来,从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 )找到方法。

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

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

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

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

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

五、最后

linux 下的符号问题有很多,每次都会遇到不一样的。
对于 glibc 版本问题本以为只有升级这一个方案,没想到竟然有这么完美的不升级的方案,但是网上又是少之又少,甚是可惜。

这个问题查询资料时,发现一本不错的链接相关的电子书,分享给大家,公众号后台发送“The GNU linker”免费领取。
注:需要发送引号里面完整的名称,建议长按复制,然后去后台发送。
注2:这篇文章的参考文章,可以点击原文阅读,在原文里面可以得到相关链接。

-EOF-

本文首发于公众号:天空的代码世界

个人微信号:tiankonguse

相关文章:

符号的那些问题

静态库遇到静态库

静态库遇到静态库2 ABI

静态库遇到静态库3 举两个例子

静态库遇到静态库4 两个解决方案

❖ 点好看、留言、分享朋友圈  ❖

❖都是对笔者的一种支持  ❖

文章转载自天空的代码世界,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论