linux glibc不兼容问题解决

linux glibc不兼容问题解决


如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033

文章目录

  • linux glibc不兼容问题解决
    • 前言
    • 1.预备知识
      • 1.1 查看glibc版本
      • 1.2 查看GLIBCXX版本
    • 2.示例程序
    • 3.解决方案
      • 3.1 普通编译运行
      • 3.2 打包依赖动态库并修改elf(推荐)
        • 3.2.1 打包依赖动态库
        • 3.2.2 修改elf的interpreter和dynamic loader ("ELF interpreter")
      • 3.3 静态编译
      • 3.4 docker容器
      • 3.5 升级gcc/g++版本

相关问题:
1.glibc不兼容
2. /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21’ not found
3. 跨操作系统应用程序

相关阅读:
Windows/Linux链接器加载动态库的搜索路径顺序
gcc link链接常用选项及应用

环境:
OS : deepIn 15.11/Centos 7
编译器: g++ 6.3.0/g++ 4.8.5

前言

开发环境为gcc 6.3.0,但是生产环境glibc版本为4.8.5,这种情况下该怎么运行程序呢?

本文将以一个例子来介绍如何解决这种不同版本glibc的问题。有如下几种方式:

  • 打包依赖动态库并修改elf(推荐)
  • 静态编译
  • docker容器
  • 升级gcc/g++版本

1.预备知识

1.1 查看glibc版本

  • gcc 6.3.0
$ ldd --version
ldd (Debian GLIBC 2.24-11+deb9u3) 2.24
  • gcc 4.8.5
$ ldd --version
ldd (GNU libc) 2.17

1.2 查看GLIBCXX版本

  • g++ 6.3.0
$ strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
...
GLIBCXX_3.4.22
GLIBCXX_DEBUG_MESSAGE_LENGTH
  • g++ 4.8.5
$ strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX
GLIBCXX_3.4
GLIBCXX_3.4.1
...
GLIBCXX_3.4.19
GLIBCXX_DEBUG_MESSAGE_LENGTH

2.示例程序

注意:本程序在gcc 4.8.5的环境无法正常运行

https://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions

//regex.cpp

#include
#include 

using namespace std;

int main()
{  
    // gcc 4.8.5 run error
    std::regex m_regex("[a-z]+");
    std::cout << std::regex_match("abc", m_regex) << std::endl;

    return 0;
}

3.解决方案

3.1 普通编译运行

g++ 6.3.0

$ g++ -o regex regex.cpp

$ ldd regex
        linux-vdso.so.1 (0x00007fff087f9000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fdeb0b41000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fdeb083d000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fdeb0626000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdeb0287000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fdeb1103000)

$ du -h regex
508K    regex

$ ./regex
1

使用g++ 6.3.0直接编译的程序,在g++ 4.8.5的环境上运行会报错

g++ 4.8.5

$ ldd regex
./regex: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by ./regex)
./regex: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./regex)
        linux-vdso.so.1 =>  (0x00007ffff05d7000)
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f1d59c9b000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f1d59999000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f1d59783000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f1d593b6000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f1d5a1e2000)

$ ./regex
./regex: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by ./regex)
./regex: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./regex)

3.2 打包依赖动态库并修改elf(推荐)

3.2.1 打包依赖动态库

g++ 6.3.0的开发环境上:

编写拷贝动态库的shell脚本copylib.sh

#!/bin/bash

# copylib.sh

LibDir=$PWD"/lib"

Target=$1

lib_array=($(ldd $Target | grep -o "/.*" | grep -o "/.*/[^[:space:]]*"))

$(mkdir $LibDir)

for Variable in ${lib_array[@]}
do
cp "$Variable" $LibDir
done
./copylib.sh regex

$ tree
.
├── cplib.sh
├── lib
│   ├── ld-linux-x86-64.so.2
│   ├── libc.so.6
│   ├── libgcc_s.so.1
│   ├── libm.so.6
│   └── libstdc++.so.6
└── regex

3.2.2 修改elf的interpreter和dynamic loader (“ELF interpreter”)

g++ 4.8.5的生产环境上:

源码编译patchelf

git clone https://github.com/NixOS/patchelf.git

./bootstrap.sh
./configure
make
sudo make install

查看patchelf版本

$ patchelf --version
patchelf 0.11

修改可执行程序的动态库搜索路径rpath和动态库加载器dynamic loader (“ELF interpreter”)

patchelf --set-rpath `pwd`/lib regex
patchelf --set-interpreter `pwd`/lib/ld-linux-x86-64.so.2 regex

$ ldd regex
        linux-vdso.so.1 =>  (0x00007ffd12ddd000)
        libstdc++.so.6 => /home/dev1/regex/pack/lib/libstdc++.so.6 (0x00007f6b30f1b000)
        libm.so.6 => /home/dev1/regex/pack/lib/libm.so.6 (0x00007f6b30c17000)
        libgcc_s.so.1 => /home/dev1/regex/pack/lib/libgcc_s.so.1 (0x00007f6b30a00000)
        libc.so.6 => /home/dev1/regex/pack/lib/libc.so.6 (0x00007f6b30661000)
        /home/dev1/regex/pack/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f6b314e0000)

执行程序

$ ./regex
1

特别说明:

  • 动态库加载器dynamic loader(“ELF interpreter”)必须要修改吗?

答案是肯定的。

动态库加载器dynamic loader(“ELF interpreter”),程序启动时,操作系统会把控制权转交给ld-linux-x86-64.so.2,而不是交给程序正常的进入地址,ld-linux-x86-64.so.2会寻找并加载所有需要的库文件,然后再将控制权交给应用的起始入口。

经过查看文件头,可以看出ld-linux-x86-64.so.2的位置信息写死在ELF中,并不受rpath和LD_LIBRARY_PATH的影响。

$ readelf -l regex

Elf 文件类型为 DYN (共享目标文件)
入口点 0x44b0
共有 9 个程序头,开始于偏移量64

程序头:
  Type           Offset             VirtAddr           PhysAddr
...
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
...

这里可以通过
方式1:(有源码,指定ld-linux-x86-64.so.2的路径)

g++ -o regex regex.cpp -Wl,-dynamic-linker='./lib/ld-linux-x86-64.so.2'

方式2:(无源码,通过patchelf修改elf中ld-linux-x86-64.so.2路径)

patchelf --set-interpreter `pwd`/lib/ld-linux-x86-64.so.2 regex
  • 动态库搜索路径rpath必须要修改吗?

答案是否定的

可以通过LD_LIBRARY_PATH设置搜索路径

export LD_LIBRARY_PATH=`pwd`/lib:$LD_LIBRARY_PATH

./regex

查看程序elf动态库信息

$ readelf -d regex

Dynamic section at offset 0x80000 contains 30 entries:
  标记        类型                         名称/值
 0x000000000000001d (RUNPATH)            Library runpath: [/home/dev1/regex/lib]
 0x0000000000000001 (NEEDED)             共享库:[libstdc++.so.6]
 0x0000000000000001 (NEEDED)             共享库:[libm.so.6]
 0x0000000000000001 (NEEDED)             共享库:[libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             共享库:[libc.so.6]
...

3.3 静态编译

注意:准确说应该是半静态编译,真正静态编译选项为-static

g++ 6.3.0

$ g++ -o regex regex.cpp -static-libgcc -static-libstdc++

$ ldd regex
        linux-vdso.so.1 (0x00007ffc627db000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f57f4985000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f57f45e6000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f57f4fbd000)

$ du -h regex
1.8M    regex

$ ./regex
1

g++ 4.8.5

$ ldd regex
        linux-vdso.so.1 =>  (0x00007ffd67757000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f60167ec000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f601641f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f6016e22000)

$ ./regex
1

3.4 docker容器

docker容器是一种解决方式,但是由于其需要先安装docker,所以不太建议使用该方式。

3.5 升级gcc/g++版本

该方式虽然可以解决问题,但是在生产环境中该方式风险极大,所以极不推荐使用该方式。


License

License under CC BY-NC-ND 4.0: 署名-非商业使用-禁止演绎

如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033


Reference:
NULL

你可能感兴趣的:(Linux,GLIBCXX,ld-linux.so,patchelf,glibc不兼容,不同版本gcc)