Linux靜態(tài)庫皆怕、共享庫毅舆、動(dòng)態(tài)庫

1. 介紹

??????? 使用GNU的工具我們?nèi)绾卧贚inux下創(chuàng)建自己的程序函數(shù)庫?一個(gè)“程序函數(shù)庫”簡單的說就是一個(gè)文件包含了一些編譯好的代碼和數(shù)據(jù),這些編譯好的代碼和數(shù)據(jù)可以在事后供其他的程序使用愈腾。程序函數(shù)庫可以使整個(gè)程序更加模塊化憋活,更容易重新編譯,而且更方便升級(jí)虱黄。

????????程序函數(shù)庫可分為3種類型:靜態(tài)函數(shù)庫(static libraries)悦即、共享函數(shù)庫(shared libraries)、動(dòng)態(tài)加載函數(shù)庫(dynamically loaded?libraries)。靜態(tài)函數(shù)庫是在程序執(zhí)行前就加入到目標(biāo)程序中去了盐欺,動(dòng)態(tài)函數(shù)庫同共享函數(shù)庫是一個(gè)東西(在linux上叫共享對象庫农渊, 文件后綴是.so ,windows上叫動(dòng)態(tài)加載函數(shù)庫庶艾,?文件后綴是.dll)掸屡。

2. 靜態(tài)函數(shù)庫

??????? 靜態(tài)函數(shù)庫實(shí)際上就是簡單的一個(gè)普通的目標(biāo)文件的集合,一般來說習(xí)慣用“.a”作為文件的后綴粉洼〗谠ぃ可以用ar這個(gè)程序來產(chǎn)生靜態(tài)函數(shù)庫文件。Ar是archiver的縮寫属韧。靜態(tài)函數(shù)庫現(xiàn)在已經(jīng)不在像以前用得那么多了安拟,主要是共享函數(shù)庫與之相比較有很多的優(yōu)勢的原因。慢慢地宵喂,大家都喜歡使用共享函數(shù)庫了糠赦。不過,在一些場所靜態(tài)函數(shù)庫仍然在使用锅棕,一來是保持一些與以前某些程序的兼容拙泽,二來它描述起來也比較簡單。?

??????? 靜態(tài)庫函數(shù)允許程序員把程序link起來而不用重新編譯代碼裸燎,節(jié)省了重新編譯代碼的時(shí)間顾瞻。不過,在今天這么快速的計(jì)算機(jī)面前德绿,一般的程序的重新編譯也花費(fèi)不了多少時(shí)間荷荤,所以這個(gè)優(yōu)勢已經(jīng)不是像它以前那么明顯了。靜態(tài)函數(shù)庫對開發(fā)者來說還是很有用的移稳,例如你想把自己提供的函數(shù)給別人使用蕴纳,但是又想對函數(shù)的源代碼進(jìn)行保密,你就可以給別人提供一個(gè)靜態(tài)函數(shù)庫文件秒裕。理論上說袱蚓,使用ELF格式的靜態(tài)庫函數(shù)生成的代碼可以比使用共享函數(shù)庫(或者動(dòng)態(tài)函數(shù)庫)的程序運(yùn)行速度上快一些,大概1-5%几蜻。?

????????創(chuàng)建一個(gè)靜態(tài)函數(shù)庫文件喇潘,或者往一個(gè)已經(jīng)存在地靜態(tài)函數(shù)庫文件添加新的目標(biāo)代碼,可以用下面的命令:?

????????ar rcs my_library.a file1.o file2.o?

????????這個(gè)例子中是把目標(biāo)代碼file1.o和file2.o加入到my_library.a這個(gè)函數(shù)庫文件中梭稚,如果my_library.a不存在則創(chuàng)建一個(gè)新的文件颖低。在用ar命令創(chuàng)建靜態(tài)庫函數(shù)的時(shí)候,還有其他一些可以選擇的參數(shù)弧烤,可以參加ar的使用幫助忱屑。這里不再贅述。

????????一旦你創(chuàng)建了一個(gè)靜態(tài)函數(shù)庫,你可以使用它了莺戒。你可以把它作為你編譯和連接過程中的一部分用來生成你的可執(zhí)行代碼伴嗡。如果你用gcc來編譯產(chǎn)生可執(zhí)行代碼的話,你可以用“-l”參數(shù)來指定這個(gè)庫函數(shù)从铲。你也可以用ld來做瘪校,使用它的“-l”和“-L”參數(shù)選項(xiàng)。具體用法可以參考info:gcc名段。

3. 共享庫

? ??????共享庫是程序啟動(dòng)時(shí)加載的庫阱扬。共享庫安裝正確后,所有啟動(dòng)的程序?qū)⒆詣?dòng)使用新的共享庫伸辟。它實(shí)際上比這更靈活和復(fù)雜麻惶,因?yàn)長inux使用的方法允許您:

????????更新庫并且仍然支持希望使用這些庫的舊版,非后向兼容版本的程序信夫。

????????在執(zhí)行特定程序時(shí)窃蹋,重寫特定庫或甚至庫中的特定函數(shù)。

????????在程序使用現(xiàn)有庫運(yùn)行時(shí)執(zhí)行所有這些操作静稻。

Linux中命名系統(tǒng)中共享庫的規(guī)則

? ??3.1 約定

????????對于共享庫來支持所有這些所需的屬性脐彩,必須遵循許多約定和準(zhǔn)則。您需要了解圖書館名稱之間的區(qū)別姊扔,特別是“soname”和“實(shí)名”(以及它們的相互作用)。您還需要了解它們應(yīng)該放在文件系統(tǒng)中的位置梅誓。

????????每個(gè)共享庫都有一個(gè)名為“soname”的特殊名稱恰梢。soname具有前綴``lib'',庫的名稱梗掰,短語“.so”嵌言,后跟一個(gè)句點(diǎn)和一個(gè)版本號(hào),每當(dāng)界面改變時(shí)都會(huì)遞增(作為一個(gè)特殊的例外及穗,級(jí)別C庫不以“l(fā)ib”開頭)摧茴。一個(gè)完全合格的soname包含作為前綴的目錄;?在一個(gè)工作系統(tǒng)上,一個(gè)完全合格的soname只是一個(gè)與共享庫的“真實(shí)姓名”的符號(hào)鏈接埂陆。

????????每個(gè)共享庫還有一個(gè)“實(shí)名”苛白,它是包含實(shí)際庫代碼的文件名。真正的名字增加了一個(gè)時(shí)期焚虱,次要號(hào)碼购裙,另一個(gè)時(shí)期和發(fā)行號(hào)碼。最后一個(gè)期間和發(fā)行號(hào)碼是可選的鹃栽。次要號(hào)碼和發(fā)行號(hào)碼通過讓您準(zhǔn)確知道安裝了哪些版本的庫躏率,來支持配置控制。請注意,這些數(shù)字可能與用于在文檔中描述庫的數(shù)字不同薇芝,盡管這樣做更容易蓬抄。

????????另外,編譯器在請求庫時(shí)使用的名稱(我將其稱為“鏈接器名稱”)夯到,這只是沒有任何版本號(hào)的soname嚷缭。

????????管理共享庫的關(guān)鍵是這些名稱的分離。程序在內(nèi)部列出他們需要的共享庫時(shí)黄娘,應(yīng)該只列出他們需要的soname峭状。相反,創(chuàng)建共享庫時(shí)逼争,只能創(chuàng)建具有特定文件名的庫(具有更詳細(xì)的版本信息)优床。當(dāng)您安裝新版本的庫時(shí),將其安裝在幾個(gè)特殊目錄之一中誓焦,然后運(yùn)行程序ldconfig(8)胆敞。ldconfig檢查現(xiàn)有文件,并將聲名創(chuàng)建為真實(shí)名稱的符號(hào)鏈接杂伟,以及設(shè)置緩存文件/etc/ld.so.cache(稍后描述)移层。

????????ldconfig不設(shè)置鏈接器名稱;?通常這是在庫安裝期間完成的,鏈接器名稱簡單地創(chuàng)建為“最新”的soname或最新的真實(shí)名稱的符號(hào)鏈接赫粥。我建議將鏈接器名稱作為與soname的符號(hào)鏈接观话,因?yàn)樵诖蠖鄶?shù)情況下,如果您更新庫越平,那么您希望在鏈接時(shí)自動(dòng)使用它频蛔。我問HJ Lu為什么ldconfig不會(huì)自動(dòng)設(shè)置鏈接器名稱。他的解釋基本上是你可能想使用最新版本的庫來運(yùn)行代碼秦叛,但是可能需要??開發(fā)?鏈接到舊的(可能不兼容的)庫晦溪。因此,ldconfig不會(huì)對您希望程序鏈接的任何假設(shè)挣跋,因此安裝程序必須特別修改符號(hào)鏈接以更新鏈接器將用于庫三圆。

????????因此,/usr/lib/libreadline.so.3是一個(gè)完全限定的soname避咆,其中l(wèi)dconfig將被設(shè)置為與/usr/lib/libreadline.so.3.0之類的一些真實(shí)名稱的符號(hào)鏈接??舟肉。還應(yīng)該有一個(gè)鏈接器名稱??/usr/lib/libreadline.so??,它可以是引用/usr/lib/libreadline.so.3的符號(hào)鏈接??查库。

????????共享庫必須位于文件系統(tǒng)的某個(gè)位置度气。大多數(shù)開源軟件往往遵循GNU標(biāo)準(zhǔn);?有關(guān)更多信息,請參閱info:standards#Directory_Variables上的信息文件文檔??膨报。GNU標(biāo)準(zhǔn)建議默認(rèn)安裝/usr/local/lib中的所有庫磷籍,當(dāng)分發(fā)源代碼(所有命令都應(yīng)該進(jìn)入/usr/local/bin)時(shí)适荣。它們還定義了覆蓋這些默認(rèn)值和調(diào)用安裝例程的約定。

????????文件系統(tǒng)層次標(biāo)準(zhǔn)(FHS)討論了在分發(fā)中應(yīng)該去哪里(請參閱?http://www.pathname.com/fhs)院领。根據(jù)FHS弛矛,大多數(shù)庫應(yīng)該安裝在/usr/lib中,但啟動(dòng)所需的庫應(yīng)該在/lib中比然,不屬于系統(tǒng)的庫應(yīng)該在/usr/local/lib中丈氓。

????????這兩個(gè)文件之間沒有真正的沖突;?GNU標(biāo)準(zhǔn)建議開發(fā)人員使用默認(rèn)的源代碼,而FHS則建議分銷商使用默認(rèn)值(通常通過系統(tǒng)的軟件包管理系統(tǒng)來選擇覆蓋源代碼默認(rèn)值)强法。在實(shí)踐中万俗,這很好地工作:您下載的“最新”(可能是buggy!)源代碼自動(dòng)安裝在“本地”目錄(/usr/local)饮怯,一旦該代碼已經(jīng)成熟闰歪,軟件包管理器可以輕松地覆蓋默認(rèn)值,以將代碼放置在標(biāo)準(zhǔn)的發(fā)行版中蓖墅。請注意库倘,如果您的庫調(diào)用只能通過庫調(diào)用的程序,則應(yīng)將這些程序放在/usr/local/libexec(在/usr/libexec中)论矾。一個(gè)復(fù)雜的情況是教翩,Red Hat派生的系統(tǒng)在搜索庫時(shí)默認(rèn)不包括/usr/local/lib;?請參閱下面關(guān)于/etc/ld.so.conf的討論。其他標(biāo)準(zhǔn)庫位置包括用于X-windows的/usr/X11R6/lib贪壳。請注意饱亿,/lib/security用于PAM模塊,但通常會(huì)作為DL庫加載(下面也將討論)闰靴。

? ? 3.2 如何使用共享庫

????????在基于GNU glibc的系統(tǒng)(包括所有Linux系統(tǒng))上路捧,啟動(dòng)ELF二進(jìn)制可執(zhí)行文件會(huì)自動(dòng)導(dǎo)致程序加載器被加載并運(yùn)行。在Linux系統(tǒng)上传黄,此加載程序名為/lib/ld-linux.so.X(其中X是版本號(hào))。反過來队寇,這個(gè)裝載器可以找到并加載程序使用的所有其他共享庫膘掰。

????????要搜索的目錄列表存儲(chǔ)在文件/etc/ld.so.conf中。許多Red Hat派生的發(fā)行版通常不會(huì)在/etc/ld.so.conf文件中包含/usr/local/lib佳遣。我認(rèn)為這是一個(gè)錯(cuò)誤识埋,并在/etc/ld.so.conf中添加/usr/local/lib是在Red Hat派生系統(tǒng)上運(yùn)行許多程序所需的常見“修復(fù)”。

????????如果您只想覆蓋庫中的一些函數(shù)零渐,但保留庫的其余部分窒舟,則可以在/etc/ld.so.preload中輸入覆蓋庫(.o文件)的名稱。這些“預(yù)加載”庫將優(yōu)先于標(biāo)準(zhǔn)集诵盼。此預(yù)加載文件通常用于緊急補(bǔ)丁;?分發(fā)通常不會(huì)在交付時(shí)包含這樣的文件惠豺。

????????在程序啟動(dòng)時(shí)搜索所有這些目錄將是非常低效的银还,因此實(shí)際使用了緩存安排。程序ldconfig(8)默認(rèn)讀入/etc/ld.so.conf文件洁墙,在動(dòng)態(tài)鏈接目錄中設(shè)置適當(dāng)?shù)姆?hào)鏈接(因此它們將遵循標(biāo)準(zhǔn)約定)蛹疯,然后將緩存寫入/ etc / ld.so.cache,然后被其他程序使用热监。這極大地加快了訪問圖書館的速度捺弦。這意味著,每當(dāng)添加一個(gè)DLL孝扛,當(dāng)一個(gè)DLL被刪除或一組DLL目錄發(fā)生變化時(shí)列吼,ldconfig必須運(yùn)行;?運(yùn)行l(wèi)dconfig通常是軟件包管理器在安裝庫時(shí)執(zhí)行的步驟之一。在啟動(dòng)時(shí)苦始,動(dòng)態(tài)加載器實(shí)際上使用文件/etc/ld.so.cache寞钥,然后加載它需要的庫。

????????順便說一句盈简,F(xiàn)reeBSD對這個(gè)緩存使用稍微不同的文件名凑耻。在FreeBSD中,ELF緩存為/var/run/ld-elf.so.hints柠贤,a.out緩存為/var/run/ld.so.hints香浩。這些仍然由ldconfig(8)更新,所以這個(gè)位置的差異只能在幾個(gè)異乎尋常的情況下重要臼勉。

? ??3.3 環(huán)境變量

????????各種環(huán)境變量可以控制此過程邻吭,并且有一些環(huán)境變量允許您覆蓋此過程。

????????LD_LIBRARY_PATH

????????您可以臨時(shí)替換不同的庫進(jìn)行此特定執(zhí)行宴霸。在Linux中囱晴,環(huán)境變量LD_LIBRARY_PATH是一個(gè)冒號(hào)分隔的目錄庫,首先要在庫文件的標(biāo)準(zhǔn)目錄集之前進(jìn)行搜索;?當(dāng)調(diào)試新庫或?yàn)樘厥饽康氖褂梅菢?biāo)準(zhǔn)庫時(shí)瓢谢,這非常有用畸写。環(huán)境變量LD_PRELOAD列出了覆蓋標(biāo)準(zhǔn)集的函數(shù)的共享庫,就像/etc/ld.so.preload一樣氓扛。這些由加載器/lib/ld-linux.so實(shí)現(xiàn)枯芬。我應(yīng)該注意,雖然LD_LIBRARY_PATH適用于許多類Unix系統(tǒng)采郎,但它并不適用;?例如千所,此功能在HP-UX上可用,但作為環(huán)境變量SHLIB_PATH蒜埋,在AIX上淫痰,此功能是通過變量LIBPATH(具有相同的語法,

????????LD_LIBRARY_PATH適用于開發(fā)和測試整份,但不應(yīng)由正常用戶正常使用的安裝過程進(jìn)行修改;?請參閱http://www.visi.com/~barr/ldpath.html上的“為什么LD_LIBRARY_PATH為壞”待错,以??了解為什么籽孙。但它仍然可用于開發(fā)或測試,以及解決不能解決的問題朗鸠。如果您不想設(shè)置LD_LIBRARY_PATH環(huán)境變量蚯撩,那么在Linux上,您甚至可以直接調(diào)用程序加載器并傳遞參數(shù)烛占。例如胎挎,以下將使用給定的PATH而不是環(huán)境變量LD_LIBRARY_PATH的內(nèi)容,并運(yùn)行給定的可執(zhí)行文件:

? ????????/lib/ld-linux.so.2? - 文件路徑路徑可執(zhí)行

????????只需執(zhí)行l(wèi)d-linux.so而不使用參數(shù)即可提供更多的使用幫助忆家,但是再一次不要使用它來進(jìn)行正常使用 - 這些都是用于調(diào)試的犹菇。

????????LD_DEBUG

????????GNU C加載器中的另一個(gè)有用的環(huán)境變量是LD_DEBUG。這會(huì)觸發(fā)dl *函數(shù)芽卿,以便他們提供關(guān)于他們正在做什么的相當(dāng)詳細(xì)的信息揭芍。例如:

????????導(dǎo)出LD_DEBUG =文件? command_to_run

????????在處理庫時(shí)顯示文件和庫的處理,告訴您哪些依賴關(guān)系被檢測到卸例,哪些SO以什么順序加載称杨。將LD_DEBUG設(shè)置為“bindings”顯示有關(guān)符號(hào)綁定的信息,將其設(shè)置為“l(fā)ibs”筷转,顯示庫搜索路徑姑原,并將ti設(shè)置為“`versions”顯示版本依賴。

????????將LD_DEBUG設(shè)置為“幫助”呜舒,然后嘗試運(yùn)行程序?qū)⒘谐隹赡艿倪x項(xiàng)锭汛。再次,LD_DEBUG不適用于正常使用袭蝗,但在調(diào)試和測試時(shí)可以方便唤殴。

? ? ? ? 其他環(huán)境變量

????????實(shí)際上還有一些控制加載過程的其他環(huán)境變量;?他們的名字以LD_或RTLD_開頭到腥。大多數(shù)其他的是用于低級(jí)別的加載程序調(diào)試或用于實(shí)現(xiàn)專門的功能乡范。他們大多沒有文件證明;?如果您需要了解它們,了解它們的最佳方式是讀取裝載器的源代碼(gcc的一部分)。

????????如果不采取特殊措施栈拖,允許用戶控制動(dòng)態(tài)鏈接的庫對于setuid/setgid程序?qū)⑹菫?zāi)難性的涩哟。因此,在GNU加載程序(程序啟動(dòng)時(shí)加載程序的其余部分)中潜腻,如果程序?yàn)閟etuid或setgid融涣,那么這些變量(和其他類似的變量)將被忽略或受到很大的限制精钮。加載程序通過檢查程序的憑據(jù)來確定程序是否被setuid或setgid;?如果uid和euid不同轨香,或者gid和egid不同,那么加載器會(huì)假定程序是setuid/setgid(或者從一個(gè)下降的)科雳,因此極大地限制了其控制鏈接的能力糟秘。如果您閱讀GNU glibc庫源代碼丽已,可以看到這一點(diǎn);?特別看到文件elf/ rtld.c和sysdeps/generic/dl-sysdep.c沛婴。這意味著如果你使uid和gid等于euid和egid嘁灯,然后調(diào)用一個(gè)程序,這些變量就會(huì)有效果性雄。其他類Unix系統(tǒng)處理不同的情況秒旋,但出于同樣的原因:setuid/setgid程序不應(yīng)該受到環(huán)境變量集的不當(dāng)影響迁筛。

? ??3.4 創(chuàng)建共享庫

????????創(chuàng)建共享庫很容易耕挨。首先,使用gcc -fPIC或-fpic標(biāo)志創(chuàng)建將進(jìn)入共享庫的對象文件蜘犁。-fPIC和-fpic選項(xiàng)可以實(shí)現(xiàn)“位置獨(dú)立代碼”生成这橙,這是共享庫的一個(gè)要求;?見下文的差異析恋。您使用-Wl gcc選項(xiàng)傳遞soname盛卡。-Wl選項(xiàng)將選項(xiàng)傳遞給鏈接器(在這種情況下為-soname鏈接器選項(xiàng)) - -Wl之后的逗號(hào)不是打字錯(cuò)誤,并且您不能在選項(xiàng)中包含未轉(zhuǎn)義的空格并村。然后使用以下格式創(chuàng)建共享庫:

????????gcc -shared -Wl哩牍,-soname令漂,your_soname \? ? -o library_name file_list library_list

????????這是一個(gè)例子叠必,它創(chuàng)建兩個(gè)對象文件(ao和bo)纬朝,然后創(chuàng)建一個(gè)包含它們的共享庫。請注意判没,此編譯包括調(diào)試信息(-g)澄峰,并將生成警告(-Wall)辟犀,這些共享庫不是必需的,但建議使用。編譯生成對象文件(使用-c)漱牵,并包含所需的-fPIC選項(xiàng):

????????gcc -fPIC -g -c -Wall acgcc -fPIC -g -c -Wall bcgcc -shared -Wl,-soname闻镶,????libmystuff.so.1 \? ? -o libmystuff.so.1.0.1 ao bo -lc

????????這里有幾點(diǎn)值得注意:

????????不要?jiǎng)冸x生成的庫铆农,并且不要使用編譯器選項(xiàng)-fomit-frame-pointer墩剖,除非你真的必須岭皂。生成的庫將工作爷绘,但這些操作使調(diào)試器大多沒有用土至。

????????使用-fPIC或-fpic生成代碼毙籽。是否使用-fPIC或-fpic生成代碼是依賴于目標(biāo)的。-fPIC選項(xiàng)始終有效么抗,但是可能產(chǎn)生比-fpic更大的代碼(請記住蝇刀,這是PIC在更大的情況下捆探,因此可能產(chǎn)生更大量的代碼)然爆。使用-fpic選項(xiàng)通常會(huì)生成更小更快的代碼,但會(huì)有平臺(tái)相關(guān)的限制黍图,例如全局可見符號(hào)的數(shù)量或代碼的大小曾雕。鏈接器將告訴您,創(chuàng)建共享庫時(shí)是否適合助被。如果有疑問剖张,我選擇-fPIC,因?yàn)樗偸怯行А?/p>

????????在某些情況下揩环,調(diào)用gcc來創(chuàng)建對象文件也需要包含“-Wl搔弄,-export-dynamic”選項(xiàng)。通常丰滑,動(dòng)態(tài)符號(hào)表僅包含動(dòng)態(tài)對象使用的符號(hào)顾犹。此選項(xiàng)(創(chuàng)建ELF文件時(shí))將所有符號(hào)添加到動(dòng)態(tài)符號(hào)表(有關(guān)詳細(xì)信息,請參閱ld(1))褒墨。當(dāng)有“反向相關(guān)性”時(shí)蹦渣,您需要使用此選項(xiàng),即貌亭,DL庫具有未解決的符號(hào)柬唯,按照慣例,必須在要加載這些庫的程序中定義它們圃庭。對于“反向相關(guān)性”工作锄奢,主程序必須使其符號(hào)動(dòng)態(tài)可用。請注意剧腻,如果您只使用Linux系統(tǒng)拘央,則可以使用“-rdynamic”而不是“-Wl,export-dynamic”书在,但根據(jù)ELF文檔灰伟,“-rdynamic”

????????在開發(fā)過程中,修改也被許多其他程序使用的庫的潛在問題 - 您不希望其他程序使用“開發(fā)”庫儒旬,只是您正在測試的特定應(yīng)用程序栏账。您可能使用的一個(gè)鏈接選項(xiàng)是ld的“rpath”選項(xiàng),它指定正在編譯的特定程序的運(yùn)行時(shí)庫搜索路徑栈源。從gcc挡爵,您可以通過這樣指定來調(diào)用rpath選項(xiàng):

????????-Wl,-rpath甚垦,$(DEFAULT_LIB_INSTALL_PATH)

????????如果您在構(gòu)建庫客戶機(jī)程序時(shí)使用此選項(xiàng)茶鹃,則不需要再打擾LD_LIBRARY_PATH(下文將介紹)涣雕,除了確保它不沖突,或者使用其他技術(shù)來隱藏庫闭翩。

? ??3.5 安裝和使用共享庫

????????創(chuàng)建共享庫后挣郭,您需要安裝它。簡單的方法是將庫復(fù)制到標(biāo)準(zhǔn)目錄(例如/usr/lib)中疗韵,并運(yùn)行l(wèi)dconfig(8)丈屹。

????????首先,您需要在某個(gè)地方創(chuàng)建共享庫伶棒。然后,您將需要設(shè)置必要的符號(hào)鏈接彩库,特別是從soname到真實(shí)名稱的鏈接(以及從無版本的soname肤无,即以“.so”結(jié)尾的soname)為用戶誰沒有指定版本)。最簡單的方法是運(yùn)行:

????????ldconfig -n directory_with_shared_libraries

????????最后骇钦,當(dāng)你編譯你的程序時(shí)宛渐,你需要告訴鏈接器你正在使用的任何靜態(tài)和共享庫。使用-l和-L選項(xiàng)眯搭。

????????如果您不能或不想在標(biāo)準(zhǔn)位置安裝庫(例如窥翩,您沒有權(quán)限修改/usr/lib),則需要更改方法鳞仙。在這種情況下寇蚊,您需要將其安裝在某個(gè)地方,然后為您的程序提供足夠的信息棍好,以便程序可以找到庫...并且有幾種方法可以做到這一點(diǎn)仗岸。您可以在簡單的情況下使用gcc的-L標(biāo)志。您可以使用“rpath”方法(如上所述)借笙,特別是如果您只有一個(gè)特定的程序?qū)旆胖迷凇胺菢?biāo)準(zhǔn)”位置扒怖。您也可以使用環(huán)境變量來控制事物。特別是业稼,您可以設(shè)置LD_LIBRARY_PATH盗痒,這是一個(gè)冒號(hào)分隔的目錄列表,用于在通常的位置之前搜索共享庫低散。如果你使用bash俯邓,

????????LD_LIBRARY_PATH =。:$ LD_LIBRARY_PATH my_program

????????如果要僅覆蓋幾個(gè)選定的函數(shù)熔号,可以通過創(chuàng)建一個(gè)覆蓋目標(biāo)的文件并設(shè)置LD_PRELOAD來實(shí)現(xiàn);?此對象文件中的函數(shù)將僅覆蓋這些函數(shù)(留下其他函數(shù))看成。

????????通常你可以不需要更新庫;?如果有API更改,則庫創(chuàng)建者應(yīng)該更改soname跨嘉。這樣川慌,多個(gè)庫可以在單個(gè)系統(tǒng)上吃嘿,并為每個(gè)程序選擇正確的庫。但是梦重,如果一個(gè)程序中斷更新到保持相同soname的庫兑燥,您可以強(qiáng)制它使用舊的庫版本通過將舊的庫復(fù)制到某個(gè)地方,重命名該程序(比如說舊的名稱加上“.orig '')琴拧,然后創(chuàng)建一個(gè)小的“包裝器”腳本降瞳,該腳本重置庫以使用并調(diào)用真實(shí)(重命名)程序。您可以將舊圖書館放在自己的特殊區(qū)域蚓胸,如果您愿意挣饥,盡管編號(hào)約定允許多個(gè)版本生活在同一目錄中。包裝腳本可能看起來像這樣:

????????#沛膳!/ bin / sh的? 導(dǎo)出LD_LIBRARY_PATH = /usr/local/my_lib:$ LD_LIBRARY_PATH? exec /usr/bin/my_program.orig $ *

????????編寫自己的程序時(shí)請不要依賴這個(gè);?嘗試確保您的庫向后兼容扔枫,或者您??每次進(jìn)行不兼容的更改時(shí)都會(huì)在soname中增加版本號(hào)。這只是處理最壞情況問題的“緊急”方法锹安。

????????您可以使用ldd(1)查看程序使用的共享庫列表短荐。所以,例如叹哭,您可以通過鍵入以下方式查看ls使用的共享庫:

????????ldd /bin/ ls

????????一般來說忍宋,您將看到依賴的聲名的列表,以及這些名稱解析的目錄风罩。在幾乎所有情況下糠排,您至少有兩個(gè)依賴關(guān)系:

????????/lib/ld-linux.so.N(其中N為1或更多,通常至少為2)超升。這是加載所有其他庫的庫乳讥。

????????libc.so.N(N為6以上)。這是C庫廓俭。即使是其他語言也傾向于使用C庫(至少要實(shí)現(xiàn)自己的庫)云石,所以大多數(shù)程序至少包括這個(gè)庫。

????????請注意:千萬不能對你不信任的程序運(yùn)行LDD研乒。如ldd(1)手冊中明確指出的汹忠,ldd通過設(shè)置特殊環(huán)境變量(對于ELF對象,LD_TRACE_LOADED_OBJECTS)雹熬,然后執(zhí)行程序(在某些情況下)工作宽菜。不可信程序可能強(qiáng)制ldd用戶運(yùn)行任意代碼(而不是簡單地顯示ldd信息)。所以竿报,為了安全起見铅乡,不要在不信任的程序上使用ldd來執(zhí)行。

4. 動(dòng)態(tài)加載的函數(shù)庫 Dynamically Loaded (DL) Libraries

????????動(dòng)態(tài)加載的函數(shù)庫Dynamically loaded (DL) libraries是一類函數(shù)庫烈菌,它可以在程序運(yùn)行過程中的任何時(shí)間加載阵幸。它們特別適合在函數(shù)中加載一些模塊和plugin擴(kuò)展模塊的場合花履,因?yàn)樗梢栽诋?dāng)程序需要某個(gè)plugin模塊時(shí)才動(dòng)態(tài)的加載。例如挚赊,Pluggable Authentication?Modules(PAM)系統(tǒng)就是用動(dòng)態(tài)加載函數(shù)庫來使得管理員可以配置和重新配置身份驗(yàn)證信息诡壁。

????????Linux系統(tǒng)下,DL函數(shù)庫與其他函數(shù)庫在格式上沒有特殊的區(qū)別荠割,我們前面提到過妹卿,它們創(chuàng)建的時(shí)候是標(biāo)準(zhǔn)的object格式。主要的區(qū)別就是這些函數(shù)庫不是在程序鏈接的時(shí)候或者啟動(dòng)的時(shí)候加載蔑鹦,而是通過一個(gè)API來打開一個(gè)函數(shù)庫夺克,尋找符號(hào)表,處理錯(cuò)誤和關(guān)閉函數(shù)庫嚎朽。通常C語言環(huán)境下铺纽,需要包含這個(gè)頭文件。

????????Linux中使用的函數(shù)和Solaris中一樣火鼻,都是dlpoen()? API。當(dāng)然不是所有的平臺(tái)都使用同樣的接口雕崩,例如HP-UX使用shl_load()機(jī)制魁索,而Windows平臺(tái)用另外的其他的調(diào)用接口。如果你的目的是使得你的代碼有很強(qiáng)的移植性盼铁,你應(yīng)該使用一些wrapping函數(shù)庫粗蔚,這樣的wrapping函數(shù)庫隱藏不同的平臺(tái)的接口區(qū)別。一種方法是使用glibc函數(shù)庫中的對動(dòng)態(tài)加載模塊的支持饶火,它使用一些潛在的動(dòng)態(tài)加載函數(shù)庫界面使得它們可以夸平臺(tái)使用鹏控。具體可以參考https://developer.gnome.org/。另外一個(gè)方法是使用libltdl肤寝,是GNU?libtool的一部分当辐,可以進(jìn)一步參考CORBA相關(guān)資料。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鲤看,一起剝皮案震驚了整個(gè)濱河市缘揪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌义桂,老刑警劉巖找筝,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異慷吊,居然都是意外死亡袖裕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門溉瓶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來急鳄,“玉大人谤民,你說我怎么就攤上這事≡艿海” “怎么了赖临?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長灾锯。 經(jīng)常有香客問我兢榨,道長,這世上最難降的妖魔是什么顺饮? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任吵聪,我火速辦了婚禮,結(jié)果婚禮上兼雄,老公的妹妹穿的比我還像新娘吟逝。我一直安慰自己,他們只是感情好赦肋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布块攒。 她就那樣靜靜地躺著,像睡著了一般佃乘。 火紅的嫁衣襯著肌膚如雪囱井。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天趣避,我揣著相機(jī)與錄音庞呕,去河邊找鬼。 笑死程帕,一個(gè)胖子當(dāng)著我的面吹牛住练,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播愁拭,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼讲逛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了岭埠?” 一聲冷哼從身側(cè)響起妆绞,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎枫攀,沒想到半個(gè)月后括饶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡来涨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年图焰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蹦掐。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡技羔,死狀恐怖僵闯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情藤滥,我是刑警寧澤鳖粟,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站拙绊,受9級(jí)特大地震影響向图,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜标沪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一榄攀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧金句,春花似錦檩赢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至趁曼,卻和暖如春军浆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背彰阴。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工瘾敢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拍冠,地道東北人尿这。 一個(gè)月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像庆杜,于是被迫代替她去往敵國和親射众。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354