dlopen函式詳解

2021-06-25 09:16:59 字數 2510 閱讀 4129

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

dlopen函式詳解

linux提供了一套api來動態裝載庫。下面列出了這些api dlopen,開啟乙個庫,並為使用該庫做些準備。dlsym,在開啟的庫中查詢符號的值。dlclose,關閉庫。dlerror,返回乙個描述最後一次呼叫dlopen dlsym,或dlclose的錯誤資訊的字串。c語言使用者需要包含標頭檔案...

Android下使用dlopen函式動態呼叫

在這篇文章 09.03.25 linux環境中dlopen函式的簡單應用 中。實現了在ubuntu linux環境下使用dlopen函式動態呼叫.so鏈結庫。但是也提到了在android下未能成功。由於android也是使用linux核心,因此估計程式本身可能並沒有什麼錯誤,問題應該是出現在andr...

dlopen 和 dlsym 動態呼叫函式

dlopen 開啟乙個庫,獲取控制代碼。開啟so檔案獲取控制代碼 看作基位址 dlsym 在開啟的庫中查詢符號的值。so裡面查某個函式位址 dlclose 關閉控制代碼。dlerror 返回乙個描述最後一次呼叫dlopen dlsym,或 dlclose 的錯誤資訊的字串。import typede...