Linux下動態載入

2021-07-02 14:05:07 字數 2510 閱讀 6104

linux提供了一套api來動態裝載庫。下面列出了這些api:

- dlopen,開啟乙個庫,並為使用該庫做些準備。

- dlsym,在開啟的庫中查詢符號的值。

- dlclose,關閉庫。

- dlerror,返回乙個描述最後一次呼叫dlopen、dlsym,或dlclose的錯誤資訊的字串。

c語言使用者需要包含標頭檔案dlfcn.h才能使用上述api。glibc還增加了兩個posix標準中沒有的api:

- dladdr,從函式指標解析符號名稱和所在的檔案。

- dlvsym,與dlsym類似,只是多了乙個版本字串引數。

在linux上,使用動態鏈結的應用程式需要和庫libdl.so一起鏈結,也就是使用選項-ldl。但是,編譯時不需要和動態裝載的庫一起鏈結。程式3-1是乙個在linux上使用dl*例程的簡單示例。

延遲重定位(lazy relocation)

延遲重定位/裝載是乙個允許符號只在需要時才重定位的特性。這常在各unix系統上解析函式呼叫時用到。當乙個和共享庫一起鏈結的應用程式幾乎不會用到該共享庫中的函式時,該特性被證明是非常有用的。這種情況下,只有庫中的函式被應用程式呼叫時,共享庫才會被裝載,否則不會裝載,因此會節約一些系統資源。但是如果把環境變數ld_bind_now設定成乙個非空值,所有的重定位操作都會在程式啟動時進行。也可以在鏈結器命令列通過使用-z now鏈結器選項使延遲繫結對某個特定的共享庫失效。需要注意的是,除非重新鏈結該共享庫,否則對該共享庫的這種設定會一直有效。

初始化(initializing)和終止化(finalizing)函式

有時候,以前的**可能用到了兩個特殊的函式:_init和_fini。_init和_fini函式用在裝載和解除安裝某個模組(注釋14)時分別控制該模組的構造器和析構器(或建構函式和析構函式)。他們的c語言原型如下:

void _init(void);

void _fini(void);

當乙個庫通過dlopen()動態開啟或以共享庫的形式開啟時,如果_init在該庫中存在且被輸出出來,則_init函式會被呼叫。如果乙個庫通過dlclose()動態關閉或因為沒有應用程式引用其符號而被解除安裝時,_fini函式會在庫解除安裝前被呼叫。當使用你自己的_init和_fini函式時,需要注意不要與系統啟動檔案一起鏈結。可以使用gcc選項 -nostartfiles 做到這一點。

但是,使用上面的函式或gcc的-nostartfiles選項並不是很好的習慣,因為這可能會產生一些意外的結果。相反,庫應該使用__attribute__((constructor))和__attribute__((destructor))函式屬性來輸出它的建構函式和析構函式。如下所示:

void __attribute__((constructor)) x_init(void)

void __attribute__((destructor)) x_fini(void)

建構函式會在dlopen()返回前或庫被裝載時呼叫。析構函式會在這樣幾種情況下被呼叫:dlclose()返回前,或main()返回後,或裝載庫過程中exit()被呼叫時。

我們通過乙個例子來講解dlopen系列函式的使用和操作:

主程式:

#include 

#include 

#include 

//申明結構體

typedef struct __test test;

//供動態庫使用的註冊函式

void __register(test *p)

int main(void)

return 0;}

動態庫:

#include 

#include 

//申明結構體型別

typedef struct __test test;

//申明註冊函式原型

void __register(test *p)

;static void __printf(test *p)

//動態庫申請乙個全域性變數空間

//這種 ".成員"的賦值方式為c99標準

static test config =;/

/載入動態庫的自動初始化函式

void _init(void)

主程式編譯: gcc test.c -ldl -rdynamic

動態庫編譯: gcc -shared -fpic -nostartfiles -o mylib.so mylib.c

主程式通過dlopen()載入乙個.so的動態庫檔案, 然後動態庫會自動執行 _init() 初始化函式, 初始化函式列印乙個提示資訊, 然後呼叫主程式的註冊函式給結構體重新賦值, 然後呼叫結構體的函式指標, 列印該結構體的值. 這樣就充分的達到了主程式和動態庫的函式相互呼叫和指標的相互傳遞.

gcc引數 -rdynamic 用來通知鏈結器將所有符號新增到動態符號表中(目的是能夠通過使用 dlopen 來實現向後跟蹤).

gcc引數 -fpic 作用: 當使用.so等類的庫時,當遇到多個可執行檔案共用這乙個庫時, 在記憶體中,這個庫就不會被複製多份,讓每個可執行檔案一對一的使用,而是讓多個可執行檔案指向乙個庫檔案,達到共用. 宗旨:節省了記憶體空間,提高了空間利用率.

Linux下動態載入庫

七月 9th,2011 以前看到過windows下載入動態庫的例子,linux下沒有特別關注過。動態載入庫有很多好處,比如通過讀取配置檔案,按照配置資訊來為指定型別或指定目錄下的資料使用指定的動態庫方法,既實現了程式的松耦合,也方便擴充套件。在linux下動態載入庫要使用到dl庫。使用的方法記錄如下...

Linux下指定動態庫的載入路徑

一 庫檔案的搜尋路徑 2 通過環境變數ld library path指定動態庫搜尋路徑 當通過該環境變數指定多個動態庫搜尋路徑時,路徑之間用冒號 分隔 3 在編譯目標 時指定該程式的動態庫搜尋路徑 還可以在編譯目標 時指定程式的動態庫搜尋路徑。這是通過gcc 的引數 wl,rpath,指定,當指定多...

Linux下動態庫的載入路徑問題

libiconv.so.2 cannot open shared objectroot賬戶登入驗證沒有問題,那就是許可權問題 vim etc ld.so.conf 檢視是否有使用者的動態庫載入路徑,如果存在刪除即可 最後在命令列ldconfig1.編譯目標 時指定的動態庫搜尋路徑 2.環境變數ld ...