加载动态链接库的相关接口dlopen,dlsym和dlclose等

来源:互联网 发布:nba2k14季后赛数据 编辑:程序博客网 时间:2024/06/06 21:40

nginx从1.9.11开始,支持运行时动态加载模块了,浏览了下代码实现,在类unix系统上是用dlopen,dlsym和dlclose实现的。下面看看这几个函数的功能。  


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

功能:

关闭指定句柄的动态链接库。

包含头文件:

#include <dlfcn.h>

函数定义:int dlclose(void* handle);

函数描述:

关闭由dlopen打开的动态链接库句柄,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

生成动态库:

hello.c:

#include <sys/types.h>#include <signal.h>#include <stdio.h>#include <unistd.h>typedef struct {    const char *module;    int (*getvalue)(char *val);    int (*printfhello)(void);} hello_dl_api;int getvalue(char *val){    int retval = -1;    if (val) {        retval = sprintf(val, "remain smile");printf("%s, %d, val = %s\n", __FUNCTION__, __LINE__, val);    }    return retval;}int printfhello(void){    int retval = -1;    printf("%s, %d, hello world\n", __FUNCTION__, __LINE__);    return 0;}const hello_dl_api hello = {    .module = "hello",    getvalue,    printfhello};
编译成动态库:gcc -shared -o hello.so hello.c

上面由一个全局的结构体hello指向两个函数。在dlsym的描述可知,返回的句柄不仅可以获取函数的地址,还可以获取全局变量的地址。

测试文件:

hello_dlopen.c

#include <sys/types.h>#include <signal.h>#include <stdio.h>#include <unistd.h>#include <dlfcn.h>typedef struct {    const char *module;    int (*getvalue)(char *val);    int (*printfhello)(void);} hello_dl_api;int main(int argc, char **argv){    hello_dl_api *hello;    int i = 0;    void *handle;    char value[20] = {0};    handle = dlopen("hello.so", RTLD_LAZY);    if (!handle) {        printf("%s, %d, handle == NULL\n", __FUNCTION__, __LINE__);        return -1;    }    dlerror();    hello = dlsym(handle, "hello");    if (!hello) {        printf("%s, %d, handle == NULL\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(value);        if (hello && hello->module)            printf("%s, %d, module = %s\n", __FUNCTION__, __LINE__, hello->module);    dlclose(handle);    return 0;}
编译指令:gcc -o hello_test hello_dlopen.c -ldl

执行结果:

./test

printfhello, 28, hello world

main, 37, i = 0

getvalue, 18, val = remain smile

main, 42, module = hello 

由此可见,dlsym找到全局结构体hello后,可以通过这个全局结构体指针来调用库里面的函数。

本文参考:

http://blog.csdn.net/jernymy/article/details/6903683

http://blog.csdn.net/bailyzheng/article/details/17613847

0 0
原创粉丝点击