在dlopen()函數以指定模式打開指定的動態鏈接庫文件,並返回一個句柄給dlsym()的調用進程。使用dlclose()來卸載打開的庫。
dlopen:
dlopen()
The function dlopen() loads the dynamic library file named by the null-terminated string filename and returns an opaque "handle" for the dynamic
library. If filename is NULL, then the returned handle is for the main program. If filename contains a slash ("/"), then it is interpreted as a
(relative or absolute) pathname. Otherwise, the dynamic linker searches for the library as follows (see ld.so(8) for further details)
dlopen:功能:打開一個動態鏈接庫
包含頭文件:
#include <dlfcn.h>
函數定義:
void * dlopen( const char * pathname, int mode );
編譯時候要加入 -ldl (指定dl庫)
dlclose()dlclose用於關閉指定句柄的動態鏈接庫,只有當此動態鏈接庫的使用計數為0時,才會真正被系統卸載。
dlerror()當動態鏈接庫操作函數執行失敗時,dlerror可以返回出錯信息,返回值為NULL時表示操作函數執行成功。
示例:
void hello(void)
{
printf("hello\n");
}
編譯命令:
代碼#include <stdio.h> #include <stdlib.h> #include <dlfcn.h> int main(int argc, char **argv) { void *handle; void (*callfun)(); char *error; handle = dlopen("/root/tmp/hello.so",RTLD_LAZY); //如果hello.so不是在LD_LIBRARY_PATH所申明 //的路徑中必須使用全路徑名 if(!handle) { printf("%s \n",dlerror()); exit(1); } dlerror(); callfun=dlsym(handle,"hello"); if((error=dlerror())!=NULL) { printf("%s \n",error); exit(1); } callfun(); dlclose(handle); return 0; }
編譯命令:
gcc -o hello_dlopen hello_dlopen.c -ldl
執行:./hello_dlopen
從中可以體會到編譯時不需要庫的好處。另外一種在編譯的時候需要動態庫的使用方法:
示例2:
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
typedef struct {
const char *module;
int (*GetValue)(char *pszVal);
int (*PrintfHello)();
} hello_ST_API;
int GetValue(char *pszVal)
{
int retval = -1;
if (pszVal)
retval = sprintf(pszVal, "%s", "123456");
printf("%s, %d, pszVer = %s\n", __FUNCTION__, __LINE__, pszVal);
return retval;
}
int PrintfHello()
{
int retval = -1;
printf("%s, %d, hello everyone\n", __FUNCTION__, __LINE__);
return 0;
}
const hello_ST_API Hello = {
.module = "hello",
GetValue,
PrintfHello,
};
編譯的時候用指令:
上面的函數是用一個全局結構體hello來指向。在dlsym定義中說不僅可以獲取函數的地址,還可以獲取全局變量的地址。所以此處是想通過dlsym來獲取全局變量的地址。好處自己慢慢體會。
3、dlopen代碼
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
typedef struct {
const char *module;
int (*GetValue)(char *pszVal);
int (*PrintfHello)();
} hello_ST_API;
int main(int argc, char **argv)
{
hello_ST_API *hello;
int i = 0;
void *handle;
char psValue[20] = {0};
handle = dlopen(“庫存放的絕對路徑,你可以試試相對路徑是不行的", RTLD_LAZY);
if (! handle) {
printf("%s,%d, NULL == handle\n", __FUNCTION__, __LINE__);
return -1;
}
dlerror();
hello = dlsym(handle, "Hello");
if (!hello) {
printf("%s,%d, NULL == handle\n", __FUNCTION__, __LINE__);
return -1;
}
if (hello && hello->PrintfHello)
i = hello->PrintfHello();
printf("%s, %d, i = %d\n", __FUNCTION__, __LINE__, i);
if (hello && hello->GetValue)
i = hello->GetValue(psValue);
if (hello && hello->module)
{
printf("%s, %d, module = %s\n", __FUNCTION__, __LINE__, hello->module);
}
dlclose(handle);
return 0;
}
編譯指令:gcc -o test hello_dlopen.c -ldl
運行./test結果如下。
PrintfHello, 27, hello everyone
main, 36, i = 0
GetValue, 19, pszVer = 123456
main, 42, module = hello
可以看到結果正常出來了。
看到沒用?dlsym找到全局結構體hello后,可以直接用這個全局結構體指針來使用庫里面的函數了,因為我們有時候提供的庫不僅僅是一個兩個函數的,一般的一個庫都會存在多個函數,用這種方式就可以直接使用了。不然找函數名稱的話要寫多少個dlsym啊?
參考:
http://www.cnblogs.com/leaven/archive/2011/01/28/1947180.html