dlopen、dlsym、dlclose

2020-12-28  本文已影响0人  forping

为了使程序方便扩展,具备通用性,可以采用插件形式。采用异步事件驱动模型,保证主程序逻辑不变,将各个业务已动态链接库的形式加载进来,这就是所谓的插件。linux提供了加载和处理动态链接库的系统调用,非常方便。

创建动态链接库

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

#include <stdio.h>
#include <unistd.h>
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){
    if(b != 0){
        return (a / b);
    }
    return 0;
}

注意:这里的编译指令无法编译Cpp文件

 gcc -fPIC -shared test.c -o test.so

dlopen、dlsym函数介绍

#import <dlfcn.h>

// dlclose来卸载打开的库。
extern int dlclose(void * __handle) __DYLDDL_DRIVERKIT_UNAVAILABLE;
// dlerror返回出现的错误,
extern char * dlerror(void) __DYLDDL_DRIVERKIT_UNAVAILABLE;
/*
RTLD_LAZY 表示:使用延迟绑定,当函数第一次被用到时,才进行绑定,即 PLT 机制。
优点:加载速度快
缺点:如果后面有符号绑定出错将难以发现

RTLD_NOW 当模块加载时,即完成所有的函数绑定工作。
优点:慢
缺点:有错误及时发现
*/
// dlopen以指定模式打开指定的动态连接库文件,将其加载到进程地址空间中,并返回一个句柄给调用进程,
extern void * dlopen(const char * __path, int __mode) __DYLDDL_DRIVERKIT_UNAVAILABLE;
// dlsym通过句柄和连接符名称获取函数名或者变量名,
extern void * dlsym(void * __handle, const char * __symbol) __DYLDDL_DRIVERKIT_UNAVAILABLE;
测试代码
#include <stdio.h>

//依赖的头文件
#include <dlfcn.h>
#include <stdlib.h>

//动态链接库路径
#define LIB_TEST_PATH "路径/test.so"
//声明函数指针
typedef int(*CAC_FUNC)(int,int);

int main(int argc, const char * argv[]) {
    // 句柄
    void  *handle;
    // error
    char *error;
    
    // 声明函数指针
    CAC_FUNC cac_func = NULL;
    
    //打开动态链接库
    handle = dlopen(LIB_TEST_PATH,RTLD_LAZY);
    if(!handle){
        // 打开失败
        printf("handle is null!\n");
        return -1;
    }
     //是否有错误
    char* szerror = dlerror();
    if(szerror != NULL){
        printf("error message:%s\n",szerror);
        dlclose(handle);
        return -1;
    }
    
    //获取一个函数
    cac_func =(CAC_FUNC)dlsym(handle,"add");
    if(cac_func != NULL){
        int num = cac_func(5,5);
        printf("add_num:%d\n",num);
    }
    cac_func = (CAC_FUNC)dlsym(handle,"sub");
    if(cac_func != NULL){
        int num = cac_func(6,5);
        printf("cac_num:%d\n",num);
    }
    cac_func = (CAC_FUNC)dlsym(handle,"mul");
    if(cac_func != NULL){
        int num = cac_func(5,5);
        printf("mul_num:%d\n",num);

    }
    cac_func = (CAC_FUNC)dlsym(handle,"div");
    if(cac_func != NULL) {
        int num = cac_func(6,2);
        printf("div_num:%d\n",num);
    }
     //关闭动态链接库
    dlclose(handle);
    cac_func = NULL;
    
    return 0;
}

运行结果

add_num:10
cac_num:1
mul_num:25
div_num:3
Program ended with exit code: 0

对于oc也是一样的,可以通过 dlopen 加载动态库的可执行文件.

上一篇 下一篇

猜你喜欢

热点阅读