dlopen 方式呼叫 Linux 的動態鏈結庫

2021-07-04 06:45:44 字數 3349 閱讀 4760

在dlopen()函式以指定模式開啟指定的動態鏈結庫檔案,並返回乙個控制代碼給 

dlsym

()的呼叫程序。使用 

dlclose

()來解除安裝

開啟的庫。

包含標頭檔案:

#include 函式定義:

void * dlopen( const char * pathname, int mode);

函式描述:

mode是開啟方式,其值有多個,不同作業系統上實現的功能有所不同,在linux下,按功能可分為三類:

1、解析方式

rtld_lazy:在dlopen返回前,對於動態庫中的未定義的符號不執行解析(只對函式引用有效,對於變數引用總是立即解析)。

rtld_now: 需要在dlopen返回前,解析出所有未定義符號,如果解析不出來,在dlopen會返回null,錯誤為:: undefined symbol: ***x.......

2、作用範圍,可與解析方式通過「|」組合使用。

rtld_global:動態庫中定義的符號可被其後開啟的其它庫解析。

rtld_local: 與rtld_global作用相反,動態庫中定義的符號不能被其後開啟的其它庫重定位。如果沒有指明是rtld_global還是rtld_local,則預設為rtld_local。

3、作用方式

rtld_noload: 不載入庫。可用於測試庫是否已載入(dlopen()返回null說明未載入,否則說明已載入),也可用於改變已載入庫的flag,如:先前載入庫的flag為rtld_local,用dlopen(rtld_noload|rtld_global)後flag將變成rtld_global。這個flag不是posix-2001標準。

rtld_deepbind:在搜尋全域性符號前先搜尋庫內的符號,避免同名符號的衝突。這個flag不是posix-2001標準。

返回值:

開啟錯誤返回null

成功,返回庫引用

編譯時候要加入 -ldl (指定dl庫)

例如gcc test.c -o test -ldl

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

dlsym函式:

函式原型是

void* dlsym(void* handle,const char* symbol)

該函式在檔案中。

匯入庫函式用法:#

include

void

* handle = dlopen(

"./hello.so"

, rtld_lazy)

;typedef

void

(*hello_t)()

;hello_t hello =

(hello_t) dlsym(handle,

"hello");

hello();

dlclose(handle)

;

注意庫函式在庫中的定義要用extern「c」來申明,這樣在主函式中才能通過「hello」來查詢函式。申明的方式有以下兩種:

extern

"c"int foo;

extern

"c"void bar();

andextern

"c"

匯入類庫方法:

#

include

"polygon.hpp"

//類定義處

#include

void

* ******** = dlopen(

"./********.so"

, rtld_lazy)

;create_t* create_******** =

(create_t*

) dlsym(********,

"create");

destroy_t* destroy_******** =

(destroy_t*

) dlsym(********,

"destroy");

polygon* poly = create_********();

// use the class

poly-

>set_side_length(7)

;cout

<

<

"the area is: "

<

< poly-

>area(

)<

<

'\n'

;// destroy the class

destroy_********(poly)

;// unload the ******** library

dlclose(********)

;

dlopen 和 dlsym 動態呼叫函式

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

Linux 動態裝載庫(dlopen)

linux有時我們需要在執行時指定庫的路徑去載入庫,而不是依賴於系統自動動態鏈結。比如說我們在需要做到動態載入庫外掛程式時就會用到動態裝載庫的特性 比如像lighthttpd和nginx的動態mod功能 linux提供了函式來幫助我們做到這件事,主要的幾個函式為 dlopen,dlsym,dlclo...

dlopen呼叫動態庫單例項類,巨集定義重名問題測試

main.cpp include include include include include include include using namespace std typedef void check func void test printa void test call string pa...