制作so文件
首先先制作制作so文件:libadd_c.so
[ add.c]
int add(int a, int b) {
return a + b;
}
編譯:
gcc -shared -fpic -o libadd_c.so add.c
- -shared 生成共享目標文件与纽,通常用在建立共享庫時
- -fpic 作用于編譯階段放吩,告訴編譯器產(chǎn)生與位置無關(guān)代碼(Position-Independent Code),則產(chǎn)生的代碼中退盯,沒有絕對地址买猖,全部使用相對地址膨蛮,故而代碼可以被加載器加載到內(nèi)存的任意位置,都可以正確的執(zhí)行竖慧。
這正是共享庫所要求的嫌套,共享庫被加載時,在內(nèi)存的位置不是固定的圾旨。
執(zhí)行編譯任務(wù)踱讨,輸出相應(yīng)的libadd_c.so文件。
編寫測試函數(shù)
[ test.cpp]
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int main()
{
int a = 0;
void *handle = dlopen("./libadd_c.so", RTLD_LAZY);
if(!handle) {
printf("open lib error\n");
cout<<dlerror()<<endl;
return -1;
}
typedef int (*add_t)(int a, int b);
add_t add = (add_t) dlsym(handle, "add");
if(!add) {
cout<<dlerror()<<endl;
dlclose(handle);
return -1;
}
a = add(4, 4);
printf("a = %d\n",a);
dlclose(handle);
return 0;
}
編譯:
g++ test.cpp -ldl -o test
運行
./test
輸出為:8
注意:
typedef int (*add_t)(int a, int b);
聲明一個函數(shù)指針砍的。
首先你要明白函數(shù)指針的概念
int *p(int ,int );
//聲明一個函數(shù)
int (*p)(int ,int);
//聲明一個函數(shù)指針
typedef int(*add_t)(int, int);
就是把這個類型的函數(shù)指針的聲明變?yōu)?code>add_t
在使用動態(tài)鏈接庫libadd_c.so文件的時候痹筛,主要使用到了四個函數(shù):
(1) dlopen()
-
函數(shù)原型:
void *dlopen(const char *libname,int flag);
- 功能描述:dlopen必須在dlerror,dlsym和dlclose之前調(diào)用廓鞠,表示要將庫裝載到內(nèi)存帚稠,準備使用。如果要裝載的庫依賴于其它庫床佳,必須首先裝載依賴庫滋早。如果dlopen操作失敗,返回NULL值砌们;如果庫已經(jīng)被裝載過杆麸,則dlopen會返回同樣的句柄。
參數(shù)中的libname
一般是庫的全路徑浪感,這樣dlopen會直接裝載該文件角溃;如果只是指定了庫名稱,在dlopen會按照下面的機制去搜尋:
a.根據(jù)環(huán)境變量LD_LIBRARY_PATH
查找
b.根據(jù)/etc/ld.so.cache
查找
c.查找依次在/lib
和/usr/lib
目錄查找篮撑。
flag
參數(shù)表示處理未定義函數(shù)的方式减细,可以使用RTLD_LAZY或RTLD_NOW。RTLD_LAZY表示暫時不去處理未定義函數(shù)赢笨,先把庫裝載到內(nèi)存未蝌,等用到?jīng)]定義的函數(shù)再說驮吱;RTLD_NOW表示馬上檢查是否存在未定義的函數(shù),若存在萧吠,則dlopen以失敗告終左冬。
(2) dlerror()
-
函數(shù)原型:
char *dlerror(void);
- 功能描述:dlerror可以獲得最近一次dlopen,dlsym或dlclose操作的錯誤信息纸型,返回NULL表示無錯誤拇砰。dlerror在返回錯誤信息的同時,也會清除錯誤信息狰腌。
(3) dlsym()
-
函數(shù)原型:
void *dlsym(void *handle, const char *symbol);
- 功能描述:在dlopen之后除破,庫被裝載到內(nèi)存。dlsym可以獲得指定函數(shù)(symbol)在內(nèi)存中的位置(指針)琼腔。如果找不到指定函數(shù)瑰枫,則dlsym會返回NULL值。但判斷函數(shù)是否存在最好的方法是使用dlerror函數(shù)丹莲。
注意:個人感覺從dlsym()尋找到內(nèi)存中指針位置這個操作還是很麻煩的光坝。
(4) dlclose
-
函數(shù)原型:
int dlclose(void *);
- 功能描述:將已經(jīng)裝載的庫句柄減一,如果句柄減至零甥材,則該庫會被卸載盯另。如果存在析構(gòu)函數(shù),則在dlclose之后洲赵,析構(gòu)函數(shù)會被調(diào)用土铺。