参考:https://blog.csdn.net/Bluenapa/article/details/119205993
使用dlopen接口动态加载共享库 ,函数原型如下
void * dlopen( const char * pathname, int mode)
其第一个参数是包含so名称的路径,可以是相对路径;第二个参数mode是选项配置,可以结合实际场景需求配置,接下来认识下具体功能。
1、RTLD_NOW和RTLD_LAZY
mode必须包含上述其中一个,表示解析方式,RTLD_NOW是调用dlopen后就解析所有函数符号,RTLD_LAZY是延时加载函数符号,使用的时候才解析,这样即使有一些未定义的函数符号,也能通过dlopen加载动态库。如下:main调用libA.so, 但是libA.so里面的函数里有未实现的函数,看看两个选项有啥区别。
main.cpp
#include <unistd.h> #include <dlfcn.h> #include <stdio.h> int main() { // RTLD_NOW RTLD_LAZY void* handle = dlopen("./libA.so",RTLD_NOW); if (!handle) { printf("dlopen libA.so failed,err:%s\n",dlerror()); return -1; } void (*func)(void) = (void (*)(void))dlsym(handle,"funcA"); if (!func) { printf("dlsym funcA failed, err: %s\n",dlerror()); return -1; } func(); return 0; }
A.cpp
#include <unistd.h>
#include <dlfcn.h>
#include <stdio.h>
extern "C" void funcB();
extern "C" void funcA()
{
funcB();
printf("this is funcA\n");
}
编译命令:
g++ -fpic --shared A.cpp -o libA.so -ldl
g++ main.cpp -o main -ldl
执行./main ,会在dlopen时就报错: dlopen libA.so failed,err:./libA.so: undefined symbol: funcB
如果将dlopen参赛mode改成RTLD_LAZY,就会发现调用dlopen和调用dlsym时都未报错,执行funcA时才报错:./main: symbol lookup error: ./libA.so: undefined symbol: funcB, 如果你不使用funcA,就不会出错
2、RTLD_LOCAL和RTLD_GLOBAL
表示加载的函数符号的作用范围,RTLD_LOCAL与RTLD_GLOBAL作用相反,RTLD_GLOBAL 动态库中符号表全局打开,因此符号可被其后打开的其它库重定位;RTLD_LOCAL 动态库中符号表非全局打开,定义的符号不能被其后打开的其它库重定位。
不填此选项,默认是RTLD_LOCAL
如下:main加载libA.so,main加载libB.so并调用其函数funcB,而funcB调用A中funcA。(如果是mainmain加载libA.so,并调用funcA, libA.so动态加载libB.so, 并调用funcB,效果也是一样)
main.cpp
#include <unistd.h> #include <dlfcn.h> #include <stdio.h> int main() { // RTLD_NOW RTLD_LAZY // RTLD_LOCAL和RTLD_GLOBAL void* handle = dlopen("./libA.so",RTLD_NOW|RTLD_LOCAL); if (!handle) { printf("dlopen libA.so failed,err:%s\n",dlerror()); return -1; } void* handleB = dlopen("./libB.so",RTLD_NOW); if (!handleB) { printf("dlopen libB.so failed,err:%s\n",dlerror()); return -1; } void (*func)(void) = (void (*)(void))dlsym(handleB,"funcB"); if (!func) { printf("dlsym funcB failed, err: %s\n",dlerror()); return -1; } func(); return 0; }
A.cpp
#include <unistd.h> #include <dlfcn.h> #include <stdio.h> extern "C" void funcC(); extern "C" void funcA() { printf("this is funcA\n"); }
B.cpp
#include <unistd.h> #include <dlfcn.h> #include <stdio.h> extern "C" void funcA(); extern "C" void funcB() { printf("this is funcB\n"); funcA(); }
编译命令:
g++ -fpic --shared A.cpp -o libA.so -ldl
g++ -fpic --shared B.cpp -o libB.so -ldl
g++ main.cpp -o main -ldl
执行./main.cpp, 会报错:dlopen libB.so failed,err:./libB.so: undefined symbol: funcA, 将dlopen libA.so的参数改成RTLD_GLOBAL,funcB就可以找到funcA符号,程序执行就没问题了。
3、RTLD_NODELETE、RTLD_NOLOA、DRTLD_DEEPBIND
RTLD_NODELETE表示在dlclose()期间不卸载库,并且在以后使用dlopen()重新加载库时不初始化库中的静态变量
RTLD_NOLOAD用于验证动态库是否已加载,dlopen()返回NULL表示未加载,否则已加载;也可用于改变已加载库的flag,如:先前加载库的flag为RTLD_LOCAL,用dlopen(RTLD_NOLOAD|RTLD_GLOBAL)后flag将变成RTLD_GLOBAL
RTLD_DEEPBIND在规避同名符号冲突是很有用的,如果定义了此标志,在搜索全局符号时会优先搜索库内的符号,如下:main调用A里的funcA, funcA调用B里面的funcB函数,funcB调用funcC函数, libA.so和libB.so里面都有funcC函数
mian.cpp
#include <unistd.h> #include <dlfcn.h> #include <stdio.h> int main() { // RTLD_NOW RTLD_LAZY // RTLD_LOCAL和RTLD_GLOBAL void* handle = dlopen("./libA.so",RTLD_NOW|RTLD_GLOBAL); if (!handle) { printf("dlopen libA.so failed,err:%s\n",dlerror()); return -1; } void (*func)(void) = (void (*)(void))dlsym(handle,"funcA"); if (!func) { printf("dlsym funcA failed, err: %s\n",dlerror()); return -1; } func(); return 0; }
A.cpp
#include <unistd.h> #include <dlfcn.h> #include <stdio.h> extern "C" void funcC() { printf("this is libA funcC\n"); } extern "C" void funcA() { printf("this is funcA\n"); // RTLD_NOW RTLD_LAZY // RTLD_LOCAL和RTLD_GLOBAL // RTLD_DEEPBIND void* handle = dlopen("./libB.so",RTLD_NOW|RTLD_GLOBAL|RTLD_DEEPBIND); if (!handle) { printf("dlopen libB.so failed,err:%s\n",dlerror()); return; } void (*func)(void) = (void (*)(void))dlsym(handle,"funcB"); if (!func) { printf("dlsym funcB failed, err: %s\n",dlerror()); return; } func(); }
B.cpp
#include <unistd.h> #include <dlfcn.h> #include <stdio.h> extern "C" void funcC() { printf("this is libB funcC\n"); } extern "C" void funcB() { printf("this is funcB\n"); funcC(); }
编译命令:
g++ -fpic --shared B.cpp -o libB.so -ldl
g++ -fpic --shared A.cpp -o libA.so -ldl
g++ main.cpp -o main -ldl
A.cpp里面的dlopen使用了RTLD_DEEPBIND选项,输出打印是this is libB funcC, 如果去掉RTLD_DEEPBIND选项,输出打印是 this is libA funcC
标签:void,flag,so,dlopen,参数,include,libA,RTLD From: https://www.cnblogs.com/ho966/p/17366207.html