如题,不要改系统的glibc版本,否则!你的系统可能崩掉!

踩坑经历

因为Ubuntu20.04(GBLIC 2.31)和Ubuntu16.04(GLIBC 2.23)版本不兼容。在20.04上面编译的二进制无法在16.04上面运行。报错,

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.2 LTS
Release:        16.04
Codename:       xenial

$ ./feeder_handler 
./feeder_handler: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by ./feeder_handler)
./feeder_handler: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by ./libmdl_api.so)

因为feeder_handler是在20.04上面编译的。你可以通过以下方法查看glibc版本,

$ ldd --version | head -1
ldd (Ubuntu GLIBC 2.23-0ubuntu11.3) 2.23
 
$ strings /lib/x86_64-linux-gnu/libm.so.6 | grep GLIBC
GLIBC_2.2.5
GLIBC_2.4
GLIBC_2.15
GLIBC_2.18
GLIBC_2.23
GLIBC_PRIVATE

可见,系统上的glibc是2.23版本。而二进制文件需要glibc2.29版本。解决方法有二:

  1. 把源码放到16.04的机器上编译
  2. 在16.04上装一个glibc2.29,通过patchelf修改动态库指向

对于频繁更新代码,编译,放到目标机器上跑的任务来说,每次都要patchelf有点过于恼人。两种方案可参考:

  1. 如何安装其他版本的glibc:https://stackoverflow.com/a/73188338
  2. 如何修改动态库指向新的glibc版本:https://stackoverflow.com/a/851229

Attention

但是,千万注意,不要动系统的glibc相关文件!否则,很可能必定会把系统弄崩掉。

我就替换了一个符号链接,将libpthread.so.0换了一个指向就引发了雪崩。

ll /lib/x86_64-linux-gnu/libpthread*
-rwxr-xr-x 1 root root  157224 Jan 29 22:41 /lib/x86_64-linux-gnu/libpthread-2.31.so*
-rw-r--r-- 1 root root 6590210 Jan 29 22:41 /lib/x86_64-linux-gnu/libpthread.a
lrwxrwxrwx 1 root root      37 Jan 29 22:41 /lib/x86_64-linux-gnu/libpthread.so -> /lib/x86_64-linux-gnu/libpthread.so.0*
lrwxrwxrwx 1 root root      18 Mar  7 09:23 /lib/x86_64-linux-gnu/libpthread.so.0 -> libpthread-2.31.so*

可以看到libpthread.so.0指向正确版本的libpthread-2.31.so,如果这里改为指向一个低版本的动态库。你会发现一连串奇怪的问题接踵而来,连ls都不能正常工作。不能切用户,不能sudo,无法校验密码(输入用户名直接报鉴权失败)。重启一下立马启不动,无法正常开机。进入修复模式,直接报kernel panic. 下面欣赏一部分截图,

从上面一些截图中可见端倪,系统的很多命令依赖这个动态库,而你改了不兼容的版本,导致寻址错误,找不到对应的符号,大部分程序都会崩溃。据同事说低版本指向高版本是ok的(按时高版本兼容低版本),但是who knows!万一替换了一个不兼容的版本,GG!

修复建议

找一个bootable的live cd,比如archliux的安装盘,进去之后挂在相应目录,把软连接指向正确的文件即可。