彻底解决 "/lib64/libc.so.6: version `GLIBC_2.18' not found (required by /lib64/libstdc++.so.6)" 的问题

时间:2022-01-15 15:30:30

环境

# cat /etc/redhat-release 
CentOS Linux release 7.2.1511 (Core)

# strings /usr/lib64/libc.so.6 | grep ^GLIBC_
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_2.13
GLIBC_2.14
GLIBC_2.15
GLIBC_2.16
GLIBC_2.17
GLIBC_PRIVATE
GLIBC_PRIVATE
GLIBC_2.8
GLIBC_2.3
GLIBC_2.5
GLIBC_2.4
GLIBC_2.9
GLIBC_2.7
GLIBC_2.6
GLIBC_2.3.2
GLIBC_2.3.4
GLIBC_2.3.3
GLIBC_2.15
GLIBC_2.14
GLIBC_2.11
GLIBC_2.16
GLIBC_2.10
GLIBC_2.17
GLIBC_2.12
GLIBC_2.13
GLIBC_2.2.5
GLIBC_2.2.6

没有GLIBC_2.18

编译glibc-2.18

curl -O http://ftp.gnu.org/gnu/glibc/glibc-2.18.tar.gz
tar zxf glibc-2.18.tar.gz
cd glibc-2.18/
mkdir build
cd build/
../configure --prefix=/opt/glibc-2.18
make -j2
make install

cd /opt/glibc-2.18/lib

替换libc.so.6

# ln -sf /opt/glibc-2.18/lib/libc-2.18.so /usr/lib64/libc.so.6
# ls
ls: relocation error: /lib64/libpthread.so.0: symbol __getrlimit, version GLIBC_PRIVATE not defined in file libc.so.6 with link time reference

LD_LIBRARY_PATH 未设置, /usr/lib64下的libpthread.so.0版本对不上

# export LD_LIBRARY_PATH=/opt/glibc-2.18/lib:/usr/lib64
# ls
ls: relocation error: /opt/glibc-2.18/lib/libc.so.6: symbol _dl_find_dso_for_object, version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2 with link time reference

对应的动态链接库找到了, 但ld-linux.so版本对不上

# ln -sf /opt/glibc-2.18/lib/ld-2.18.so /usr/lib64/ld-linux-x86-64.so.2
Segmentation fault (core dumped)

还是libc.so.6的原因

# LD_PRELOAD=/usr/lib64/libc-2.17.so ln -sf /opt/glibc-2.18/lib/ld-2.18.so /usr/lib64/ld-linux-x86-64.so.2
# ls
bin etc include lib libexec sbin share var

OK

再次确认

# strings /usr/lib64/libc.so.6 | grep ^GLIBC_
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_2.13
GLIBC_2.14
GLIBC_2.15
GLIBC_2.16
GLIBC_2.17
GLIBC_2.18
GLIBC_PRIVATE
GLIBC_PRIVATE
GLIBC_2.8
GLIBC_2.3
GLIBC_2.5
GLIBC_2.4
GLIBC_2.9
GLIBC_2.7
GLIBC_2.6
GLIBC_2.3.2
GLIBC_2.3.4
GLIBC_2.3.3
GLIBC_2.18
GLIBC_2.15
GLIBC_2.14
GLIBC_2.11
GLIBC_2.16
GLIBC_2.10
GLIBC_2.17
GLIBC_2.12
GLIBC_2.13
GLIBC_2.2.5
GLIBC_2.2.6

GLIBC_2.18

知识点

  • 运行程序时, 系统默认使用的glibc库和动态链接器分别为:
[root@localhost glibc-2.18]# ls -l /usr/lib64/ | grep -E "libc.so|ld-linux"
lrwxrwxrwx. 1 root root 30 May 22 05:58 ld-linux-x86-64.so.2 -> /opt/glibc-2.18/lib/ld-2.18.so
lrwxrwxrwx. 1 root root 32 May 22 05:46 libc.so.6 -> /opt/glibc-2.18/lib/libc-2.18.so
  • 链接器加载动态链接库的顺序, 见man ld.so
When  resolving  library  dependencies,  the  dynamic  linker first inspects each dependency string to see if it contains a slash (this can occur if a library pathname containing slashes was specified at link time).  If a slash is found, then the dependency string is interpreted as a (relative or absolute) pathname, and the library is  loaded  using  that pathname.

If a library dependency does not contain a slash, then it is searched for in the following order:

o (ELF only) Using the directories specified in the DT_RPATH dynamic section attribute of the binary if present and DT_RUNPATH attribute does not exist. Use of DT_RPATH is dep-recated.

o Using the environment variable LD_LIBRARY_PATH. Except if the executable is a set-user-ID/set-group-ID binary, in which case it is ignored.

o (ELF only) Using the directories specified in the DT_RUNPATH dynamic section attribute of the binary if present.

o From the cache file /etc/ld.so.cache, which contains a compiled list of candidate libraries previously found in the augmented library path. If, however, the binary was linked with the -z nodeflib linker option, libraries in the default library paths are skipped. Libraries installed in hardware capability directories (see below) are preferred to other libraries.

o In the default path /lib, and then /usr/lib. If the binary was linked with the -z nodeflib linker option, this step is skipped.
  • 指定搜索路径
    1. 在配置文件 /etc/ld.so.conf 中指定动态库搜索路径. 每次编辑完该文件后, 都必须运行命令 ldconfig 使修改后的配置生效 . /etc/ld.so.cache包含了在/etc/ld.so.conf中指定的目录中查找到所有连接库, 按顺序存储.
    2. 通过环境变量 LD_LIBRARY_PATH 指定动态库搜索路径.
    3. 在编译目标代码时指定该程序的动态库搜索路径. 通过 gcc 的参数 -Wl,-rpath 指定. 当指定多个动态库搜索路径时, 路径之间用冒号 ‘:分隔.-Wl, 表示后面的参数将传给 link 程序ld(因为gcc可能会自动调用ld` ).

其他

动态库加载路径之RPATH与RUNPATH