支持動態(tài)鏈接的系統(tǒng)往往都支持一種更加靈活的模塊加載方式恩伺,叫做顯示運(yùn)行時鏈接徙瓶,有時候也叫做運(yùn)行時加載。
這種運(yùn)行時加載使得程序的模塊組織變得很靈活,可以用來實(shí)現(xiàn)一些諸如插件罕伯,驅(qū)動等功能。當(dāng)程序需要用到某個插件或者驅(qū)動的時候髓梅,才將相應(yīng)的模塊裝載進(jìn)來,而不是需要從一開始就將他們?nèi)垦b載進(jìn)來绎签,從而少了程序啟動時間和內(nèi)存使用枯饿。并且程序在運(yùn)行的時候重新加載某個模塊,這樣使得程序本身不必重新啟動而實(shí)現(xiàn)模塊的增加诡必,刪除奢方,更新等。
在Linux中,而動態(tài)庫的裝載則是通過一系列的API提供:dlopen
蟋字, dlsym
稿蹲,dlerror
,dclose
鹊奖。
dlopen
dlopen函數(shù)負(fù)責(zé)打開一個動態(tài)庫苛聘,并將其加載到進(jìn)程進(jìn)程的地址空間,完成初始化過程忠聚。
void* dlopen(const char* filename, int flag);
-
第一個參數(shù)
第一個參數(shù)是被加載動態(tài)庫的路徑焰盗,如果整個路徑是絕對路徑,則該函數(shù)將會嘗試直接打開該動態(tài)庫咒林,如果是相對路徑,那么將會按照下面的順序查找:- 查找有環(huán)境變量
LD_LIBRARY_PATH
指定的一系列目錄 - 查找由
/etc/ld.so.cache
里面所指定的共享庫路徑 -
/lib
爷光,/usr/lib
- 查找有環(huán)境變量
-
第二個參數(shù)
表示函數(shù)符號的解析方式:- RTLD_LAZY
表示使用延遲綁定垫竞, - RTLD_NOW
- RTLD_LAZY
返回值
dlopen
的返回值是被加載模塊的句柄,如果加載失敗則返回NULL蛀序。
dlsym
void* dlsym(void* handle, char *symbol);
- 第一個參數(shù)
由dlopen
返回的動態(tài)庫的句柄欢瞪。 - 第二個參數(shù)
即要查找的符號的名字。 - 返回值
如果dlsym
找到了相應(yīng)的符號徐裸,則返回該符號的值遣鼓,如果查找的符號是一個函數(shù),則返回函數(shù)的地址重贺;
如果是一個變量骑祟,則返回變量的地址。
如果整個符號是一個常量气笙,那么返回的是該常量的值次企。
dlerror
每次調(diào)用以后,都可以調(diào)用dlerror函數(shù)來判斷上一次調(diào)用是否成功潜圃。
dlclose
dlclose
的作用和dlopen
相反缸棵,它的作用是將一個已經(jīng)加載的模塊卸載,系統(tǒng)會維持一個加載的引用計(jì)數(shù)器谭期,每次使用dlopen
加載模塊時堵第,相應(yīng)的計(jì)數(shù)器加1,每次使用dlclose
卸載模塊時隧出,相應(yīng)計(jì)數(shù)器減1踏志,只有當(dāng)計(jì)數(shù)器值減少到0時,模塊才真正被卸載掉胀瞪。
例子
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char **argv)
{
void* handler;
double (*func)(double);
char* error;
handler = dlopen(argv[1], RTLD_NOW);
if (handler == NULL) {
printf("Open library %s error: %s\n %s\n", argv[1], dlerror());
return -1;
}
func = dlsym(handler, "sin");
if ( (error = dlerror()) != NULL ) {
printf("Symbol sin not found: %s\n", error);
goto exit_runso;
}
printf("%f\n", func(3.1415926 / 2));
exit_runso:
dlclose(handler);
}
# gcc RunSoSimple.c -o RunSoSimple -ldl # -ldl 表示使用DL(Dynamical Loading)庫
# ./RunSoSimple /lib64/libm-2.17.so
1.000000