运行时导入动态库
动态库
-
在Linux下的动态库值得通常是.so文件, windows下的动态库通常时.dll文件
-
动态库与静态库相比, 通常在编译时和运行时都需要该动态库
-
在编译时可以指定
-l
来链接动态库, 在运行调用函数时则会自动调用动态库中的函数
模块化/插件化
在很多工程中视功能分为多个模块, 而且可以动态的指定加载那些模块甚至于实时卸载模块, 这又是怎么实现的呢?
dlopen族函数
#include <dlfcn.h>
void *dlopen(const char *filename, int flags);
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);
-
dlopen: 动态导入指定动态库
- flags可以指定一些FLAG, 通常为RTLD_NOW即可
-
dlsym: 通过dlopen获得的句柄以及符号名字来获得指定函数的句柄
-
dlclose: 关闭dlopen获得的句柄
-
编译时需要指定动态库
-ldl
windows下
#define dlopen(p, f) LoadLibraryA(p)
#define dlsym(h, n) GetProcAddress(h, n)
#define dlclose(h) FreeLibrary(h)
代码实例
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <assert.h>
typedef int (*fun)(int, int);
int main() {
void *f = dlopen("./libadd.so", RTLD_LAZY);
assert(f);
fun add = (fun)dlsym(f, "add");
assert(add);
printf("add: %d\n", add(1, 2));
dlclose(f);
//printf("add: %d\n", add(1, 2));
return 0;
}
//编译命令
gcc test.cpp -ldl
动态库代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int add(int a, int b)
{
return a + b;
}
//编译命令
gcc -fPIC -shared add.c -o libadd.so
nm命令
bogon:~/winsf$ nm libadd.so
00003f28 d _DYNAMIC
00004000 d _GLOBAL_OFFSET_TABLE_
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
000020b0 r __FRAME_END__
00002000 r __GNU_EH_FRAME_HDR
00004010 d __TMC_END__
w __cxa_finalize@@GLIBC_2.1.3
000010e0 t __do_global_dtors_aux
00003f24 t __do_global_dtors_aux_fini_array_entry
0000400c d __dso_handle
00003f20 t __frame_dummy_init_array_entry
w __gmon_start__
00001150 t __x86.get_pc_thunk.ax
00001040 t __x86.get_pc_thunk.bx
00001135 t __x86.get_pc_thunk.dx
00001154 t _fini
00001000 t _init
00001139 T add
00004010 b completed.6886
00001050 t deregister_tm_clones
00001130 t frame_dummy
00001090 t register_tm_clones
-
可以看到上面的
add
函数符号, 当dlopen成功但是dlsym失败时可以通过nm命令看一下函数的符号到底是什么 -
注意的是c/cpp编译出的符号是不一样的, 需要额外注意(C++有重载)
-
注意: 我之前用的cpp文件、gcc命令、debian环境, 发现编译出的符号是:
_Z3addii
;
问题注意
-
动态库符号问题
-
当使用了dlclose后, 之前获得的句柄也不能再用了; 会出现段错误
网友评论