高版本gcc編譯出的程序在低版本glibc機(jī)器上運(yùn)行

比如我們用gcc 9.3.0編譯程序,但需要發(fā)布的機(jī)器gcc版本是4.8.5,怎么辦?

你可能想到如下方法

  1. 靜態(tài)編譯
  2. 容器發(fā)布
  3. 打包依賴(lài)的so,使用本地so運(yùn)行程序

1.靜態(tài)編譯

將libc和libstdc++靜態(tài)編譯,編譯時(shí)帶上如下參數(shù)。

g++ -static-libgcc -static-libstdc++

glibc并不推薦靜態(tài)鏈接,你依賴(lài)的其他庫(kù)可能依賴(lài)的了glibc,并且往往是動(dòng)態(tài)鏈接的,可以通過(guò)nm <bin> | grep GLIBC_確定你的程序是否依賴(lài)了glibc。

2.容器發(fā)布

使用攜帶gcc9.3.0環(huán)境的容器發(fā)布程序,是可以的。但是在一些沒(méi)有容器且沒(méi)有sudo權(quán)限的場(chǎng)合,依然不太友好。

3.打包依賴(lài)的so發(fā)布

這個(gè)方法雖然聽(tīng)起來(lái)不是很優(yōu)雅,但其實(shí)如果你對(duì)elf文件有一些了解,是不錯(cuò)的方式。下面說(shuō)下具體的方法。

3.1 方式1 在編譯時(shí)設(shè)置rpath和dynamic linker

當(dāng)你有條件獲得程序源碼,并能夠重新編譯時(shí),可以直接在編譯時(shí)指定相關(guān)參數(shù)來(lái)解決。
先說(shuō)編譯時(shí)要增加的參數(shù):

# 絕對(duì)路徑
gcc -Wl,-rpath='/my/lib',-dynamic-linker='/my/lib/ld-linux.so.2'

gcc參數(shù)

-Wl,option
Pass option as an option to the linker.

ld參數(shù)

-rpath=dir
Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects.
--dynamic-linker=file
Set the name of the dynamic linker.

這兩個(gè)參數(shù)分別設(shè)置的elf文件中的rpath和interpreter字段。

rpath
全名run-time search path,是elf文件中一個(gè)字段,它指定了可執(zhí)行文件執(zhí)行時(shí)搜索so文件的第一優(yōu)先位置,一般編譯器默認(rèn)將該字段設(shè)為空。elf文件中還有一個(gè)類(lèi)似的字段runpath,其作用與rpath類(lèi)似,但搜索優(yōu)先級(jí)稍低。搜索優(yōu)先級(jí):

rpath > LD_LIBRARY_PATH > runpath > ldconfig緩存 > 默認(rèn)的/lib,/usr/lib等

如果你需要使用相對(duì)路徑指定lib文件夾,可以使用ORIGIN變量,ld會(huì)將ORIGIN理解成可執(zhí)行文件所在的路徑。

gcc -Wl,-rpath='$ORIGIN/../lib'

interpreter
動(dòng)態(tài)庫(kù)加載器,程序啟動(dòng)時(shí),操作系統(tǒng)會(huì)先把控制權(quán)轉(zhuǎn)交給ld-linux-x86-64.so.2,該so負(fù)責(zé)加載所有程序依賴(lài)的so。。這個(gè)字段在鏈接時(shí)會(huì)幫你自動(dòng)設(shè)置,64bit程序一般為/lib64/ld-linux-x86-64.so.2。修改rpath或者LD_LIBRARY_PATH指向本地lib目錄,但通過(guò)ldd程序,發(fā)現(xiàn)/lib64/ld-linux-x86-64.so.2這個(gè)so仍然指向系統(tǒng)so。原因就是這個(gè)字段是寫(xiě)死在elf文件中的,并不受LD_LIBRARY_PATH影響。

編譯時(shí)帶上這兩個(gè)參數(shù),下面只需要將你程序依賴(lài)的so打包一份,隨程序進(jìn)行發(fā)布即可。

3.2 方式2 直接修改二進(jìn)制程序的rpath和interpreter

當(dāng)你無(wú)法編譯程序時(shí),也可以通過(guò)其他方式修改rpath和interpreter。這種情況需要使用到一個(gè)工具patchelf,通過(guò)dnf install patchelf即可安裝。你可以通過(guò)它修改elf文件的rpath和interpreter:

patchelf --set-rpath /my/lib your_program
patchelf --set-interpreter /my/lib/ld-linux.so.2 your_program

除了絕對(duì)路徑,一種比較常見(jiàn)的方式是在部署前,使用pwd獲取當(dāng)前路徑,使用相對(duì)路徑指向本地lib。

patchelf --set-rpath `pwd`/../lib your_program
patchelf --set-interpreter `pwd`/../lib/ld-linux-x86-64.so.2 ./your_program
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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