博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
dlopen、dlsym和dlclose的使用和举例 (转)
阅读量:6633 次
发布时间:2019-06-25

本文共 4967 字,大约阅读时间需要 16 分钟。

转自http://blog.csdn.net/bailyzheng/article/details/17613847 & http://www.cnblogs.com/Anker/p/3746802.html

 

1、函数简介

dlopen

基本定义

功能:打开一个动态链接库    

包含头文件:    #include <dlfcn.h>    

函数定义:    void * dlopen( const char * pathname, int mode );    

函数描述:    在dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。使用dlclose()来卸载打开的库。    

mode:分为这两种    

RTLD_LAZY 暂缓决定,等有需要时再解出符号    

RTLD_NOW 立即决定,返回前解除所有未决定的符号。    

RTLD_LOCAL    

RTLD_GLOBAL 允许导出符号    

RTLD_GROUP    

RTLD_WORLD 

  返回值   

打开错误返回NULL    

成功,返回库引用    

编译时候要加入 -ldl (指定dl

dlsym()

   功能:

根据动态链接库操作句柄与符号,返回符号对应的地址。
包含头文件:
#include <dlfcn.h>
函数定义:
void*dlsym(void* handle,const char* symbol)
函数描述:
dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以
获取函数地址,也可以
获取变量地址
handle是由 打开 后返回的 ,symbol就是要求获取的函数或 的名称。

dlclose()

 

dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
 
上述都是摘抄,总结为链接的时候需要用到dl库,编译的时候需要加上dlfcn.h头文件。才能保证编译不会报错。
 
 
 
有2中方式可以使用,一 种是
利用dlsym 找到库中提供的函数,使用方式如下:
转自http://www.cnblogs.com/Anker/p/3746802.html
首先
生产动态链接库

编译参数 gcc -fPIC -shared 

例如将如下程序编译为动态链接库libcaculate.so,程序如下:

int add(int a,int b){    return (a + b);}int sub(int a, int b){    return (a - b);}int mul(int a, int b){    return (a * b);}int div(int a, int b){    return (a / b);}

编译如下: gcc -fPIC -shared caculate.c -o libcaculate.so 

 
采用上面生成的libcaculate.so,写个测试程序如下:
#include 
#include
#include
//动态链接库路径#define LIB_CACULATE_PATH "./libcaculate.so"//函数指针typedef int (*CAC_FUNC)(int, int);int main(){ void *handle; char *error; CAC_FUNC cac_func = NULL; //打开动态链接库 handle = dlopen(LIB_CACULATE_PATH, RTLD_LAZY); if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(EXIT_FAILURE); } //清除之前存在的错误 dlerror(); //获取一个函数/*void *dlsym(void *handle, const char *symbol);返回值为void*(void **)&(cac_func)是将函数指针的地址强制转换void**类型然后使用*取值,获取dlsym的返回值实际这个地方没有必要这样,函数指针本来就是地址,可以直接用cac_func = dlsym(handle, "add");*/ *(void **) (&cac_func) = dlsym(handle, "add"); if ((error = dlerror()) != NULL) { fprintf(stderr, "%s\n", error); exit(EXIT_FAILURE); } printf("add: %d\n", (*cac_func)(2,7)); cac_func = (CAC_FUNC)dlsym(handle, "sub"); printf("sub: %d\n", cac_func(9,2)); cac_func = (CAC_FUNC)dlsym(handle, "mul"); printf("mul: %d\n", cac_func(3,2)); cac_func = (CAC_FUNC)dlsym(handle, "div"); printf("div: %d\n", cac_func(8,2)); //关闭动态链接库 dlclose(handle); exit(EXIT_SUCCESS);}

编译选项如下:gcc -rdynamic -o main main.c -ldl

测试结果如下所示:

 

 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

 

另一种方式是利用dlsym 找到库中提供全局变量

首先生成动态库
hello.c函数原型:
  
#include 
#include
#include
#include
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, };

 

 

编译的时候用指令:

gcc -shared -o hello.so hello.c

上面的函数是用一个全局结构体hello来指向。在dlsym定义中说不仅可以获取函数的地址,还可以获取全局变量的地址。所以此处是想通过dlsym来获取全局变量的地址。好处自己慢慢体会。

然后是dlopen代码

#include 
#include
#include
#include
#include
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啊?

转载于:https://www.cnblogs.com/chenxf0619/p/4864534.html

你可能感兴趣的文章