庫 連線 裝載

2021-09-30 11:27:02 字數 4477 閱讀 7745

1.什麼是庫 

在windows平台和linux 平台下都大量存在著庫。 

本質上來說庫是一種可執行**的二進位制形式,可以被作業系統載入記憶體執行。 

由於windows和linux 的本質不同,因此二者庫的二進位制是不相容的。 

本文僅限於介紹linux 下的庫。 

2.庫的種類 

linux 下的庫有兩種:靜態庫和共享庫(動態庫)。 

二者的不同點在於**被載入的時刻不同。 

靜態庫的**在編譯過程中已經被載入可執行程式,因此體積較大。 

共享庫的**是在可執行程式執行時才載入記憶體的,在編譯過程中僅簡單的引用,因此**體積較小。 

3.庫存在的意義 

庫是別人寫好的現有的,成熟的,可以復用的**,你可以使用但要記得遵守許可協議。 

現實中每個程式都要依賴很多基礎的底層庫,不可能每個人的**都從零開始,因此庫的存

在意義非同尋常。 

共享庫的好處是,不同的應用程式如果呼叫相同的庫,那麼在記憶體裡只需要有乙份該共享庫

的例項。 

4.庫檔案是如何產生的在linux 下 

靜態庫的字尾是.a ,它的產生分兩步 

step 1.由原始檔編譯生成一堆.o ,每個.o 裡都包含這個編譯單元的符號表 

step 2.ar命令將很多.o 轉換成.a ,成文靜態庫 

動態庫的字尾是.so ,它由gcc 加特定引數編譯產生。 

例如: 有乙個print.c檔案,內容如下:

###########################################

#include

###########################################

#gcc  -c print.c

#gcc -shared -fpic -o libprint.so print.o5.庫檔案是如何命名的,有沒有什麼規範

在linux 下,庫檔案一般放在/usr/lib /lib 下, 

靜態庫的名字一般為lib***x.a ,其中***x是該lib的名稱 

動態庫的名字一般為lib***x.so.major.minor ,***x是該lib的名稱,major是主版本號, 

minor是副版本號 

6.如何知道乙個可執行程式依賴哪些庫

ldd 命令可以檢視乙個可執行程式依賴的共享庫,

#gcc -o hello hello.c -lprint 

[root@localhost testdir]# ldd hello

linux-gate.so.1 =>  (0x00c0b000)

libprint.so => /usr/lib/libprint.so (0x00767000)

libc.so.6 => /lib/libc.so.6 (0x00110000)

可以看到hello依賴的 庫 

7.可執行程式在執行的時候如何定位共享庫檔案 

當系統載入可執行**時候,能夠知道其所依賴的庫的名字,但是還需要知道絕對路徑 

此時就需要系統動態載入器(dynamic linker/loader) 

對於elf格式的可執行程式,是由ld-linux.so* 來完成的,它先後搜尋elf檔案的 dt_rpath

段—環境變數ld_library_path—/etc/ld.so.cache 檔案列表—/lib/,/usr/lib目錄找

到庫檔案後將其載入記憶體 

8.在新安裝乙個庫之後如何讓系統能夠找到他

基本概念

庫有動態與靜態兩種,動態通常用.so 為字尾,靜態用.a 為字尾。  

例如:libhello.so libhello.a  為了在同一系統中使用不同版本的庫,可以在庫檔名後加上版本號為字尾, 例如: libhello.so.1.0, 由於程式連線預設以.so 為檔案字尾名。所以為了使用這些庫,通常使用建立符號連線的方式。  

ln -s libhello.so.1.0 libhello.so.1   

ln -s libhello.so.1 libhello.so   

1、使用庫  

當要使用靜態的程式庫時,聯結器會找出程式所需的函式,然後將它們拷貝到執行檔案,由於這種拷貝是完整的,所以一旦連線成功,靜態程式庫也就不再需要了。然  而,對動態庫而言,就不是這樣。動態庫會在執行程式內留下乙個標記指明當程式執行時,首先必須載入這個庫。由於動態庫節省空間,linux 下進行連線的預設操作是首先連線動態庫,也就是說,如果同時存在靜態和動態庫,不特別指定的話,將與動態庫相連線。  現在假設有乙個叫hello的程式開發包,它提供乙個靜態庫libhello.a  乙個動態庫libhello.so, 乙個標頭檔案hello.h,標頭檔案中提供sayhello() 這個函式  /* hello.h */ void sayhello();  另外還有一些說明文件。  

這乙個典型的程式開發包結構  與動態庫連線 linux 預設的就是與動態庫連線,下面這段程式testlib.c 使用hello庫中的sayhello() 函式  

/*testlib.c*/  

#include   

#include   

int main()   

使用如下命令進行編譯  $gcc -c testlib.c -o testlib.o   

用如下命令連線:  $gcc testlib.o -lhello -o testlib   

$gcc testlib.o -o testlib -wi,-bstatic -lhello   

注:這個特別的"-wi,-bstatic"引數,實際上是傳給了聯結器ld 。指示它與靜態庫連線,如果系統中只有靜態庫當然就不需要這個引數了。  如果要和多個庫相連線,而每個庫的連線方式不一樣,比如上面的程式既要和libhello 進行靜態連線,又要和libbye 進行動態連線,其命令應為:  

$gcc testlib.o -o testlib  -wi,-bstatic -lhello  -wi,-bdynamic  -lbye   

2、動態庫的路徑問題  為了讓執行程式順利找到動態庫,有三種方法:  

(1) 把庫拷貝到/usr/lib 和/lib 目錄下。  

(2) 在ld_library_path環境變數中加上庫所在路徑。  

例如動態庫libhello.so在/home/ting/lib目錄下,以bash為例,使用命令:   

$export ld_library_path=$ld_library_path:/home/ting/lib   

(3)  修改/etc/ld.so.conf檔案,把庫所在的路徑加到檔案末尾,並執行ldconfig 重新整理。這

樣,加入的目錄下的所有庫檔案都可見。   

3、檢視庫中的符號  

有時候可能需要檢視乙個庫中到底有哪些函式,nm命令可以列印出庫中的涉及到的所有符

號。庫既可以是靜態的也可以是動態的。nm列出的符號有很多,常見的有三種:  

一種是在庫中被呼叫,但並沒有在庫中定義(表明需要其他庫支援),用u表示;  

一種是庫中定義的函式,用t 表示,這是最常見的;  

另外一種是所謂的「弱  態」 符號,它們雖然在庫中被定義,但是可能被其他庫中的同名符號

覆蓋,用w表示。  

4、生成庫   

第一步要把源**編繹成目標**。  

以下面的**為例,生成上面用到的hello庫:  

/* hello.c */   

#include     

void sayhello()   

用gcc 編繹該檔案,在編繹時可以使用任何全法的編繹引數,例如-g加入除錯**等: gcc 

-c hello.c -o hello.o   

(1) 連線成靜態庫  連線成靜態庫使用ar命令,其實ar是archive 的意思  

$ar crv libhello.a hello.o   

(2) 連線成動態庫  生成動態庫用gcc 來完成,由於可能存在多個版本,因此通常指定版本號:  

$gcc -shared -wl,-soname,libhello.so.1 -o libhello.so.1.0 hello.o   

另外再建立兩個符號連線:  

$ln -s libhello.so.1.0 libhello.so.1   

$ln -s libhello.so.1 libhello.so   

這樣乙個libhello 的動態連線庫就生成了。最重要的是傳gcc -shared 引數使其生成是動態庫而不是普通執行程式。 -wl  表示後面的引數也就是-soname,libhello.so.1 直接傳給聯結器ld 進行處理。實際上,每乙個庫都有乙個soname ,當聯結器發現它正在查詢的程式庫中有這樣乙個名稱,聯結器便會將soname 嵌入鏈結中的二進位制檔案內,而不是它正在執行的實際檔名,在程式執行期間,程式會查詢擁有 soname名字的檔案,而不是庫的檔名,換句話說,soname 是庫的區分標誌。  這樣做的目的主要是允許系統中多個版本的庫檔案共存,習慣上在命名庫檔案的時候通常與soname 相同 lib***x.so.major.minor 其中,***x是庫的名字,major是主版本號,minor 是次版本號

鏈結裝載庫

一般應用程式記憶體空間有如下區域 棧棧儲存了乙個函式呼叫所需要的維護資訊,常被稱為堆疊幀 stack frame 或活動記錄 activate record 一般包含以下幾方面 堆堆分配演算法 段錯誤 segment fault 或 非法操作,該記憶體位址不能 read write 典型的非法指標解...

裝載 鏈結與庫

第五部分 windows動態鏈結 1 dll函式和變數必須在檔案顯示是匯入還是匯出,declspec dllexport 匯出,declspec dllimport 匯入.建立dll檔案的時候.c檔案生成.dll,lib,exp檔案,然後用.lib檔案和exe中的.c檔案生成的目標檔案鏈結在一起,生...

鏈結 裝載與庫

鏈結 裝載與庫 在linux下,當我們使用 gcc來編譯 helloword 程式時,只需要 gcc hello.c a.out hello world 其中實際包括4步驟 預處理 prepressinng 編譯 compliation 彙編 assembly 鏈結 linking 1.預編譯 gc...