linux glibc不兼容問題解決

linux glibc不兼容問題解決


如需轉載請標明出處:http://blog.csdn.net/itas109
QQ技術交流羣:129518033

相關問題:
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<iostream>
#include <regex>

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章