6.动态加载

  1. 对动态库的加载分为自动加载和动态加载两种
    1.1 动态加载:
    程序的执行期间,需要使用到某个动态库中的文件的时候,可以向动态链接器发出请求,将动态库文件加载到内存中。
    1.2 自动加载:
    程序在开始执行的时候,就将依赖的动态库文件加载到内存,再进行函数的链接

  2. 动态加载

2.1: dlopen()

#include
void *dlopen(const *filename, int flags)
//功能:将动态库加载到内存

参数:
- filename: 共享库的路径,如果只给定名字,将按照动态链接器的搜索路径去到指定的共享库去寻找该文件LD_LIBRARY_PATH
- flags: 加载的方式, 取值如下:

   - RTLD_LAZY: 延迟加载,使用时去加载
   - RTLD_NOW: 立即加载。函数返回时,已经加载到内存

返回值:

  • 成功: 返回动态库加载到内存的地址
  • 失败: NULL,可以使用dlerror(3)函数诊断错误的原因

注意:

  • 动态链接器的API都需要使用到dl动态库文件,所以连接的时候需要使用-ldl

2.2: dlclose

#include
int dlclose(void *handle);

功能:

  • 关闭动态库,仅仅使动态库的引用计数减一,不一定从内存移除该库文件。只有引用计数=0的时候,才会从内存移除
  • handle: 动态库加载到内存的地址
  • 返回值:
    • 0: 成功
    • 非0: 失败, 使用dlerror(3)判断出错原因
      2.3: dlerror
#include
char *dlerror(void)

功能:

  • 获取dlopenAPI的错误信息
  • 返回值: 返回错误原因的首地址
  • NULL: 没有错误

2.4: dlsym

#include
void *dlsym(void *handle, const char *symbol);

功能:从动态库的句柄中找到符号的地址
参数:

  • handle:动态库加载到内存的地址。dlopen的返回值
  • symble:符号的名字,包括函数的名字,全局变量的名字,静态局部变量的名字
    返回值:
  • 成功:返回符号的地址
  • 失败:NULL,dlerror(3)读取错误的原因

练习,基于上一节的学习,编译动态链接库libmath.so
练习一:

#include
#include

int main(int argc, char *argv[]){
    void *handle = dlopen(argv[1], RTLD_NOW);
        if(handle == NULL){
                printf("Load failed: %s\n", dlerror());
                return -1;
        }
        if(ff == NULL){
                printf("Can't find: %s\n", dlerror());
                return -1;
        }
        printf("Load sucess\n");
        dlclose(handle);
        return 0;
}

测试:

zhongjun@eclipse:~/linkTest$ gcc dynamic_load.c -ldl -o test
zhongjun@eclipse:~/linkTest$ ./test
Load sucess
zhongjun@eclipse:~/linkTest$ ./test libmath.so
Load sucess
zhongjun@eclipse:~/linkTest$ ./test libmath.soaa
Load failed: libmath.soaa: cannot open shared object file: No such file or directory

练习二:

#include
#include
typedef int (*func_t)(int, int);

int main(int argc, char *argv[]){
    void *handle = dlopen(argv[1], RTLD_NOW);
        if(handle == NULL){
                printf("Load failed: %s\n", dlerror());
                return -1;
        }
        func_t ff = (func_t)dlsym(handle, "add"); #强制转换数据类型
        if(ff == NULL){
                printf("Can't find: %s\n", dlerror());
                return -1;
        }
        printf("3 + 4 = %d\n", ff(3, 4)); #通过动态库动态加载的方式调用add函数
        printf("Load sucess\n");
        dlclose(handle);
        return 0;
}

输出:

zhongjun@eclipse:~/linkTest$ gcc dynamic_load.c -ldl -o test
zhongjun@eclipse:~/linkTest$ ./test libmath.so
3 + 4 = 7
Load sucess

说明:libmath.so动态库包含了add函数,main函数运行的时候通过dlsym找到了该库文件的地址,并找到了该函数。

你可能感兴趣的:(6.动态加载)