dlopen、dlsym和dlclose的使用和举例 (转)

转自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是由 dlopen打开 动态链接库后返回的 指针,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 <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

//动态链接库路径
#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 <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,
 };

 

 

编译的时候用指令:

gcc -shared -o hello.so hello.c

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

然后是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啊?

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值