Linux中dlfcn库相关学习

在linux中静态链接库和动态链接库是进程之间代码共享的两种方式。Linux在库中提供了加载和处理动态连接库的系统调用,使用非常方便。具体用法如下:

dlfcn库中函数说明

dlfcn库中主要包括四个函数:

1
2
3
4
5
6
7
8
9
#include <dlfcn.h>
void* dlopen(const char*, int flag);
char* dlerror();
void* dlsym(void* handler, char* symbol);
int dlclose(void* handler);

  • dlopen : 打开一个动态连接库,并返回一个类型为void*的handler,flag为打开模式,可选的模式有两种
    • RTLD_LAZY 暂缓决定,等有需要时再解出符号
    • RTLD_NOW 立即决定,返回前解除所有未决定的符号。
  • dlerror : 返回dl操作的错误,若没有出现错误,则返回NUlL,否则打印错误信息
  • dlsym : 查找动态链接库中的符号symbol,并返回该符号所在的地址
  • dlclose : 关闭动态链接库句柄

使用实例

动态链接库cal.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//cal.cpp
extern "C" {
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) {
return a / b;
}
}

生成动态链接库libcal.so

1
g++ -shared -fPIC cal.cpp libcal.so

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#define LIB_LIBRARY_PATH_1 "./libcal.so"
typedef int (*CAC_FUNC)(int ,int);
int main() {
void* handler = NULL;
char* error = NULL;
CAC_FUNC cac_func = NULL;
handler = dlopen(LIB_LIBRARY_PATH_1, RTLD_LAZY);
if (!handler) {
fprintf(stderr, "err:%s\n", dlerror());
exit(1);
}
dlerror();
//此处取对应函数地址,
*(void **) (&cac_func) = dlsym(handler, "add");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "err:%s", error);
exit(1);
}
printf("add:%d\n", cac_func(1,2));
cac_func = (CAC_FUNC)dlsym(handler, "sub");
printf("sub:%d\n", cac_func(1,2));
cac_func = (CAC_FUNC)dlsym(handler, "mul");
printf("mul:%d\n", cac_func(1,2));
cac_func = (CAC_FUNC)dlsym(handler, "div");
printf("div:%d\n", cac_func(1,2));
dlclose(handler);
return 0;
}

编译函数main:

1
g++ main.cpp -rdynamic -ldl

执行结果:

1
2
3
4
add:3
sub:-1
mul:2
div:0

注意问题

特别注意,若使用c++编译动态链接库,一定要在需要使用的符号处添加extern “C”,否则会出现符号找不到的问题。即undefined symbol