6.动态加载
2020-03-15 本文已影响0人
陈忠俊
-
对动态库的加载分为自动加载和动态加载两种
1.1 动态加载:
程序的执行期间,需要使用到某个动态库中的文件的时候,可以向动态链接器发出请求,将动态库文件加载到内存中。
1.2 自动加载:
程序在开始执行的时候,就将依赖的动态库文件加载到内存,再进行函数的链接 -
动态加载
2.1: dlopen()
#include<dlfcn.h>
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<dlfcn.h>
int dlclose(void *handle);
功能:
- 关闭动态库,仅仅使动态库的引用计数减一,不一定从内存移除该库文件。只有引用计数=0的时候,才会从内存移除
- handle: 动态库加载到内存的地址
- 返回值:
- 0: 成功
- 非0: 失败, 使用dlerror(3)判断出错原因
2.3:dlerror
#include<dlfcn.h>
char *dlerror(void)
功能:
- 获取
dlopen
API的错误信息 - 返回值: 返回错误原因的首地址
- NULL: 没有错误
2.4: dlsym
#include<dlfcn.h>
void *dlsym(void *handle, const char *symbol);
功能:从动态库的句柄中找到符号的地址
参数:
- handle:动态库加载到内存的地址。dlopen的返回值
- symble:符号的名字,包括函数的名字,全局变量的名字,静态局部变量的名字
返回值: - 成功:返回符号的地址
- 失败:NULL,dlerror(3)读取错误的原因
练习,基于上一节的学习,编译动态链接库libmath.so
练习一:
#include<stdio.h>
#include<dlfcn.h>
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<stdio.h>
#include<dlfcn.h>
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
找到了该库文件的地址,并找到了该函数。