顯式運行時鏈接

dlopen
功能:打開一個動態鏈接庫
包含頭文件:
#include <dlfcn.h>
函數定義:
void * dlopen( const char * pathname, int mode);
函數描述:
在dlopen()函數以指定模式打開指定的動態連接庫文件,並返回一個句柄給調用進程。使用dlclose()來卸載打開的庫。
mode是打開方式,其值有多個,不同操作系統上實現的功能有所不同,在linux下,按功能可分爲三類:
1、解析方式
RTLD_LAZY:在dlopen返回前,對於動態庫中的未定義的符號不執行解析(只對函數引用有效,對於變量引用總是立即解析)。
RTLD_NOW: 需要在dlopen返回前,解析出所有未定義符號,如果解析不出來,在dlopen會返回NULL,錯誤爲:: undefined symbol: xxxx.......
2、作用範圍,可與解析方式通過“|”組合使用。
RTLD_GLOBAL:動態庫中定義的符號可被其後打開的其它庫重定位。
RTLD_LOCAL: 與RTLD_GLOBAL作用相反,動態庫中定義的符號不能被其後打開的其它庫重定位。如果沒有指明是RTLD_GLOBAL還是RTLD_LOCAL,則缺省爲RTLD_LOCAL。
3、作用方式
RTLD_NODELETE: 在dlclose()期間不卸載庫,並且在以後使用dlopen()重新加載庫時不初始化庫中的靜態變量。這個flag不是POSIX-2001標準。
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庫)

dlsym
功能:
根據動態鏈接庫操作句柄與符號,返回符號對應的地址。
包含頭文件:
#include <dlfcn.h>
函數定義:
void*dlsym(void* handle,const char* symbol)
函數描述:
dlsym根據動態鏈接庫操作句柄(handle)與符號(symbol),返回符號對應的地址。使用這個函數不但可以獲取函數地址,也可以獲取變量地址。
handle是由dlopen打開動態鏈接庫後返回的指針,symbol就是要求獲取的函數或全局變量的名稱。
返回值:
1、如果查找的符號是個函數,那麼它返回函數的地址
2、如果查找的符號是個變量,那麼它返回變量的地址
3、如果查找的符號是個常量,那麼它返回的是該常量的值

dlerror
每次我們調用dlopen()、dlsym()或dlclose()以後,我們都可以調用dlerror()函數老判斷上一次調用是否成功。dlerror的返回類型是char *,如果返回NULL,則表示上一次調用成功;如果不是,則返回相應的錯誤信息。

dlclose
dlclose的作用跟dlopen剛好相反,它的作用是將一個已經加載的模塊卸載。系統會維持一個加載引用計數器,每次使用dlopen加載某模塊時,相應的計數器加1;每次使用dlclose卸載某模塊時,相應計數器減1.只有當計數器值減到0時,模塊才被真正地卸載掉。卸載的過程跟加載剛好相反,先執行“.finit" 段的代碼,然後將相應的符號從符號表中去除,取消進程空間跟模塊的映射關係,然後關閉模塊文件。

程序示例如下(RunSoSimple.c):
#include<stdio.h>
#include<dlfcn.h>
int main(int argc, char * argv[])
{
      void * handle;
      double (*func) (double);
      char * error;
      handle = dlopen(argv[1], RTLD_NOW);
      if(handle == NULL)
      {
            printf("Open library %s error: %s\n",argv[1], dlerror() );
            return -1;
      }
      func = dlsym(handle, "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(handle);
      return 0;
}
編譯運行程序
gcc -g RunSoSimple.c -o RunSoSimple -ldl
./RunSoSimple /lib/i386-linux-gnu/libm-2.13.so
結果如下:
1.000000
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章