您的位置:首页 > 运维架构

dlopen dlsym dlclose

2017-03-12 19:01 459 查看

dlopen、dlsym和dlclose的使用和举例  

  之前用过这三个函数一直没时间整理一下。今天抽时间整理一下。

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、生成动态库
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 retv
4000
al = -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来获取全局变量的地址。好处自己慢慢体会。

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啊?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: