美文网首页
dlopen、dlsym、dlclose

dlopen、dlsym、dlclose

作者: forping | 来源:发表于2020-12-28 16:48 被阅读0次

    为了使程序方便扩展,具备通用性,可以采用插件形式。采用异步事件驱动模型,保证主程序逻辑不变,将各个业务已动态链接库的形式加载进来,这就是所谓的插件。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 加载动态库的可执行文件.

    相关文章

      网友评论

          本文标题:dlopen、dlsym、dlclose

          本文链接:https://www.haomeiwen.com/subject/iejmnktx.html