Linux 靜態庫與共享庫的使用
阿新 • • 發佈:2019-02-08
申明: 正如題如示,本篇講的是Linux下是靜態庫與共享庫,而Window下的動態連結庫詳細情況可見這篇文章:windows動態連結庫 DLL 淺析。雖然原理,思想差不多,但是細節卻各有不同。
一、靜態庫
1、概念:靜態庫指將所有相關的目標檔案打包成為一個單獨的檔案-即靜態庫檔案,以.a結尾。靜態庫可作為連結器的輸入,連結器會將程式中使用的到函式的程式碼從庫檔案中拷貝到應用程式中。一旦連結完成,在執行程式的時候就不需要靜態庫了。 注1:由於每個使用靜態庫的應用程式都需要拷貝所用函式的程式碼,所以靜態連結的檔案會比較大。 注2:在Unix系統中,靜態庫以一種稱為存檔(archive)的特殊檔案格式存放在磁碟中。存檔檔案 // addvec.c
void addvec(int* x, int* y, int*z, int n)
{
int i=0;
for(; i< n;++i)
z[i] = x[i] + y[i];
}
// multvec.c void multvec(int*x, int* y, int* z, int n) { int i = 0; for(; i < n; ++i) z[i] = x[i] * y[i]; }
使用AR工具建立靜態庫檔案:
為了使用這個庫,編寫一個應用(其呼叫addvec庫中的函式):
/* main2.c */
#include <stdio.h>
int x[2] = {1, 2};
int y[2] = {3, 4};
int z[2]={0};
int main()
{
addvec(x, y, z, 2);
printf("z = [%d %d]\n", z[0], z[1]);
return 0;
}
編譯-連結-執行程式:
注1:-static 引數告訴編譯器驅動程式,連結器應該構建一個完全的可執行目標檔案,它可以載入到儲存器並執行,在載入時無需進一步的連結 -即一次性靜態連結完畢,不允許存在動態連結
二、共享庫 1、概念:共享庫是一個目標模組(以.so字尾表示),在執行時,可以載入到任意的儲存器地址,並和一個在儲存器中的程式連結起來,這個過程稱為動態連結,是由一個叫做動態連結器的程式來執行的。 2、分類:根據載入和連結共享庫的時機又可分為:A)應用程式自身載入時動態連結和載入共享庫;B)應用程式執行過程中動態連結和載入共享庫兩種情況。 2-A:應用程式自身載入時動態連結和載入共享庫 2-A.1 基本思路是:當建立可執行檔案時,靜態執行一些連結(共享庫的重定位和符號表資訊,而非程式碼和資料),然後在應用程式載入時,動態完成連結過程。 2-A.2 建立與應用 建立類似於靜態庫的建立,假設我們現在想在一個叫做libvector.so的共享庫庫中提供以下addvec和multvec函式: 下面使用-shared選項來指示連結器建立一個共享的目標檔案(即共享庫),連結並執行程式:
注1:-fPIC選項指示編譯器生成與位置無關的程式碼 其動態連結過程可如下圖所示:
注2:在可執行檔案p2中沒有拷貝任何libvector.so真正的程式碼和資料節,而是由連結器拷貝了一些重定位和符號表資訊,它們使得執行時動態連結器可以解析libvector.so中程式碼和資料的引用,重定位完成連結任務。其中需要重定位的有:
- 1)重定位libc.so的文字和資料到某個儲存器段;
- 2)重定位libvector.so的文字和資料到另一個儲存器段;
- 3)重定位p2中所有對libc.so和libvector.so定義的符號的引用。
#include<dlfcn.h>
/* 載入和連結共享庫 filename
filename:共享庫的名字
flag有:RTLD_LAZY, RTLD_NOW,二者均可以和RTLD_GLOBAL表示取或
*/
void *dlopen(const char *filename, int flag); // 若成功則返回執行控制代碼的指標,否則返回NULL
/*根據共享庫操作控制代碼與符號,返回符號對應的地址
handle:共享庫操作控制代碼
symbol:需要引用的符號名字
*/
void *dlsym(void *handle, char *symbol); // 若成功則返回執行符號的指標(即地址),若出錯則返回NULL
/* 如果沒有程式正在使用這個共享庫,解除安裝該共享庫 */
int dlclose(void *handle); // 若解除安裝成功,則返回0,否則返回-1
/* 捕捉最近發生的錯誤 */
const char *dlerror(void); // 若前面對dlopen,dlsym或dlclose呼叫失敗,則返回錯誤訊息,否則返回NULL
例子:
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int x[2] = {1, 2};
int y[2] = {3, 4};
int z[2] ={0};
int main()
{
void *handle;
void (*addvec)(int *, int *, int *,int);
char *error;
handle = dlopen("./libvector.so", RTLD_LAZY);
if(!handle){
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
addvec = dlsym(handle, "addvec");
if((error = dlerror()) != NULL){
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
addvec(x, y, z, 2);
printf("z = [%d %d]\n", z[0], z[1]);
if(dlclose(handle) < 0){
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
return 0;
}
執行結果:-ldl引數:表示生成的物件模組需要用到共享庫
Referebces:
1.《深入理解計算機系統》第7章:連結 P448-P479