找不到動態(tài)鏈接庫?

前言

對于經(jīng)常在服務器上跑程序或安裝程序的朋友,不可避免的會遇到一些問題。

其中最常見的問題就是,像下面這樣

version `GLIBC_2.23' not found
version `GLIBC_2.15' not found

glibc 庫找不到的問題,當然也可能會有其他庫找不到的問題。

那出現(xiàn)這種問題該怎么辦呢?

常用解決方案

針對這一問題,網(wǎng)上搜索的答案大部分都是分為以下幾步

安裝高版本的 glibc

顯然,沒有這個庫,當然先要在環(huán)境中安裝這個庫才行,比如我要安裝 glibc-2.23

  1. 下載
http://ftp.gnu.org/gnu/libc/

選擇對應的版本并下載,如 libc-2.23.tar.gz

  1. 解壓
$ tar -zxf glibc-2.23.tar.gz
  1. 生成配置文件
$ cd glibc-2.23
$ mkdir build && cd build
$ ../configure --prefix=LIB_DIR

可以用 --prefix=LIB_DIR,LIB_DIR 為你要將 glib 安裝到的路徑

通常非 root 用戶權限無法安裝到默認的 /usr/local 目錄下,需要自己手動指定

  1. 安裝
$ make
$ make install

等會吧,這個安裝還蠻久的。來杯咖啡,靜等安裝成功就行。

問題

如果在 ../configure 這一步出現(xiàn)了問題,比如我出現(xiàn) ld 版本太低的錯誤

*** These critical programs are missing or too old: as ld

也不用著急,再安裝個較高版本的 binutils 就行。

這個怎么安裝?類似上面的 1-4 步重新來一遍就行。一般像這種 C 庫的安裝過程都是這樣的,挺簡單的,只是通常拋出的異常是不簡單的 (?????_?????)。

  1. 配置環(huán)境

安裝完成后,大多數(shù)的答案都是將下面的命令添加到 ~/.bashrc 文件中

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:your glibc path

然后,執(zhí)行

source ~/.bashrc

但是這又會引入另一個問題更嚴重的問題。

glibcLinux 系統(tǒng)中最底層的 API,幾乎其他所有的庫都會依賴它。

因此當你更新了較高版本的 glibc 時,底層的庫依賴的還是低版本的 glibc 庫,因此可能會導致系統(tǒng)的嚴重故障。

我當初就是信了這些鬼話,添加到了環(huán)境變量中,導致幾乎所有的命令都無法使用。運行命令或腳本也會出現(xiàn)

Segmentation fault

最后的解決辦法就是將 ~/.bashrc 文件中的

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:your glibc path

刪除之后,才恢復原狀。

那如何解決呢,一種方法就是每次運行之前,在終端臨時將 glibc 的路徑添加到 LD_LIBRARY_PATH 變量中,但是這非常麻煩。

下面,我們介紹一款神器

PatchELF

PatchELF 是一個用于修改現(xiàn)有 ELF 可執(zhí)行文件和庫的簡單實用程序

ELF: 可執(zhí)行與可鏈接格式(Executable and Linkable Format),常被稱為 ELF 格式。

既然它能夠更改可執(zhí)行文件,那么我們就可以直接將可執(zhí)行文件需要加載的 glibc 庫的路徑修改為我們剛才安裝的路徑。

這樣就可以在既不需要添加環(huán)境變量,也不需要手動加載臨時變量的情況下使用。

下面,我們先安裝這個工具

1. 安裝

  1. 下載
https://github.com/dxsbiocc/patchelf

先從 GitHub 上下載源碼

  1. 配置環(huán)境
./bootstrap.sh
./configure
  1. 安裝
make
make check
make install

2. 使用

  1. 查看參數(shù)
$ patchelf 
syntax: patchelf
  [--set-interpreter FILENAME]
  [--page-size SIZE]
  [--print-interpreter]
  [--print-soname]              Prints 'DT_SONAME' entry of .dynamic section. Raises an error if DT_SONAME doesn't exist
  [--set-soname SONAME]         Sets 'DT_SONAME' entry to SONAME.
  [--set-rpath RPATH]
  [--remove-rpath]
  [--shrink-rpath]
  [--allowed-rpath-prefixes PREFIXES]           With '--shrink-rpath', reject rpath entries not starting with the allowed prefix
  [--print-rpath]
  [--force-rpath]
  [--add-needed LIBRARY]
  [--remove-needed LIBRARY]
  [--replace-needed LIBRARY NEW_LIBRARY]
  [--print-needed]
  [--no-default-lib]
  [--output FILE]
  [--debug]
  [--version]
  FILENAME...
  1. 參數(shù)描述
參數(shù) 描述
--set-interpreter FILENAME 設置動態(tài)庫解析器
--page-size SIZE 設置頁大小
--print-interpreter 打印解析器
--print-soname 打印 DT_SONAME
--set-soname SONAME 設置 DT_SONAME
--set-rpath RPATH 設置 RPATH
--remove-rpath 刪除 RPATH
--shrink-rpath 收縮 RPATH
--allowed-rpath-prefixes PREFIXES 添加允許的 RPATH 前綴
--print-rpath 打印 RPATH
--force-rpath 強制使用 RPATH
--add-needed LIBRARY 添加需要的動態(tài)庫
--remove-needed LIBRARY 刪除需要的動態(tài)庫
--replace-needed LIBRARY NEW_LIBRARY 替換動態(tài)庫
--print-needed 打印需要的動態(tài)庫
--no-default-lib 不鏈接默認的動態(tài)庫
--output FILE 輸出文件
--debug 輸出調(diào)試信息
--version 打印版本信息

patchelf 的主要功能與動態(tài)庫解析器、RPATH 以及動態(tài)庫有關。

  1. 使用方式
  • 更改可執(zhí)行文件的動態(tài)庫解析器
$ patchelf --set-interpreter /lib/my-ld-linux.so.2 my-program
  • 更改可執(zhí)行文件和庫的RPATH
$ patchelf --set-rpath /opt/my-libs/lib:/other-libs my-program
  • 收縮可執(zhí)行文件和庫的RPATH
$ patchelf --shrink-rpath my-program

該命令會刪除可執(zhí)行文件中所有不包含 DT_NEEDED 字段指定的庫的路徑。

例如:

一個可執(zhí)行文件引用一個庫 libfoo.so,它的 RPATH/lib:/usr/lib:/foo/lib,而 libfoo.so 只能在 /foo/lib 中找到,那么新的 RPATH 將是 /foo/lib

其中 RPATH 指定的是可執(zhí)行文件的動態(tài)鏈接庫的搜索路徑

  • 刪除動態(tài)庫上聲明的依賴項(DT_NEEDED),可多次使用
$ patchelf --remove-needed libfoo.so.1 my-program
  • 添加動態(tài)庫上聲明的依賴項(DT_NEEDED),可多次使用
$ patchelf --add-needed libfoo.so.1 my-program
  • 替換動態(tài)庫聲明的依賴項(DT_NEEDED),可多次使用
$ patchelf --replace-needed liboriginal.so.1 libreplacement.so.1 my-program
  • 更改動態(tài)庫的 SONAME
$ patchelf --set-soname libnewname.so.3.4.5 path/to/libmylibrary.so.1.2.3
  1. 示例

我有一個 msi 分析的可執(zhí)行文件 msisensor-blood

在終端執(zhí)行時,出現(xiàn)錯誤

$ ./msisensor-blood
./msisensor-blood: /lib64/libm.so.6: version `GLIBC_2.23' not found (required by ./msisensor-blood)
./msisensor-blood: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ./msisensor-blood)
./msisensor-blood: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./msisensor-blood)

從輸出信息可以看出,需要兩個庫

  • glibc-2.15libc.so.6
  • glibc-2.23libm.so.6

首先, 我們用 ldd 命令列出其動態(tài)庫依賴關系

./msisensor-blood: /lib64/libm.so.6: version `GLIBC_2.23' not found (required by ./msisensor-blood)
./msisensor-blood: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ./msisensor-blood)
./msisensor-blood: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./msisensor-blood)
        linux-vdso.so.1 =>  (0x00007ffc75beb000)
        libz.so.1 => /home/dengxs/software/zlib-1.2.11/lib/libz.so.1 (0x00007f7594351000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00000033dee00000)
        libstdc++.so.6 => /home/dengxs/software/anaconda3/lib/libstdc++.so.6 (0x00007f75941c4000)
        libm.so.6 => /lib64/libm.so.6 (0x00000033de600000)
        libgomp.so.1 => /home/dengxs/software/anaconda3/lib/libgomp.so.1 (0x00007f7594196000)
        libgcc_s.so.1 => /home/dengxs/software/anaconda3/lib/libgcc_s.so.1 (0x00007f7594182000)
        libc.so.6 => /lib64/libc.so.6 (0x00000033de200000)
        /lib64/ld-linux-x86-64.so.2 (0x00000033dde00000)
        librt.so.1 => /lib64/librt.so.1 (0x00000033df200000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00000033dea00000)

OK!就是把下面兩個動態(tài)庫替換掉

libm.so.6 => /lib64/libm.so.6
...
libc.so.6 => /lib64/libc.so.6

更換 libm.so.6 的路徑

patchelf --replace-needed libm.so.6 /home/dengxs/software/glibc-2.23/lib/libm.so.6 msisensor-blood 

更換 libc.so.6 的路徑

patchelf --replace-needed libc.so.6 /share/software/glibc/2.15/lib/libc.so.6 msisensor-blood

再看下動態(tài)庫列表

$ ldd msisensor-blood
        linux-vdso.so.1 =>  (0x00007ffde0199000)
        libz.so.1 => /home/dengxs/software/zlib-1.2.11/lib/libz.so.1 (0x00007f6a786df000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00000033dee00000)
        libstdc++.so.6 => /home/dengxs/software/anaconda3/lib/libstdc++.so.6 (0x00007f6a78552000)
        /home/dengxs/software/glibc-2.23/lib/libm.so.6 (0x00007f6a7844b000)
        libgomp.so.1 => /home/dengxs/software/anaconda3/lib/libgomp.so.1 (0x00007f6a7841d000)
        libgcc_s.so.1 => /home/dengxs/software/anaconda3/lib/libgcc_s.so.1 (0x00007f6a78409000)
        /share/software/glibc/2.15/lib/libc.so.6 (0x00007f6a78062000)
        /lib64/ld-linux-x86-64.so.2 (0x00000033dde00000)
        librt.so.1 => /lib64/librt.so.1 (0x00000033df200000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00000033dea00000)

OK,已經(jīng)替換成功了

接下去看看能不能直接運行

$ ./msisensor-blood 


Program: msisensor-blood (homopolymer and miscrosatelite analysis using cfDNA bam files)
Version: v0.1
Author: Beifang Niu && Kai Ye

Usage:   msisensor-blood <command> [options]

Key commands:

 scan            scan homopolymers and miscrosatelites
 msi             msi scoring

沒問題,一切順利。(^?^)??

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容