Linux提供一组函数用来支持显示运行时链接,具体来说,有四个函数:打开动态链接库(dlopen),查找符号(dlsym),错误处理(dlerror),以及关闭动态库(dlclose)。这几个函数的声明与相关常量定义在系统标准头文件<dlfcn.h>中。
1. void * dlopen(const char * filename,int flag);
该函数用来打开动态库,并将其加载到进程的地址空间,完成初始化过程。
返回值:由第一个参数指定的被加载模块的句柄
第一个参数:指定被加载的动态链接库的路径,如果是绝对路径,则直接查找;如果是相对路径,则按以下顺序查找:
(1)查找由环境变量 LD_LIBRARY_PATH 指令的一系列目录
(2)查找由 /etc/ld.so.cache 里面指定的共享库路径
(3)/lib、/usr/lib
*若该值为0,则返回全局符号表的句柄,也就是说可以在运行时找到全局符号表中的任意一个符号。
第二个参数:表示函数符号的解析方式
RTLD_LAZY:表示使用延迟绑定,当函数第一次被用到时才进行绑定。使用该参数,会导致符号未绑定的错误会在加载后发生,难以查到
RTLD_NOW:模块被加载时即完成所有函数的绑定工作。若模块加载时有任何符号未绑定,可以使用dlerror立即捕获。但加载速度变慢
RTLD_GLOBAL:与上述两者中一个一起使用,表示被加载的模块中的全局符号合并到全局符号表中
2.void * dlsym(void *handle,const char * symble)
该函数用来在打开的动态库中查找指定符号。
返回值:
(1)如果查找的是函数,则返回函数的地址
(2)如果查找的是变量,则返回变量的地址
(3)如果查找的是常量,则返回该常量的值
(4)如果没有找到符号,则返回NULL
*若查找的常量是NULL 或 0,可以通过dlerror判断是未查找到符号,还是返回的常量。如果符号找到了,dlerror() 返回NULL
第一个参数:使用dlopen打开的动态链接库的句柄
第二个参数:查找的符号,可以是函数,变量或常量
3.char * dlerror()
每次调用dlopen()、dlsym()、dlclose()以后,都可以调用dlerror()函数来判断上次调用是否成功。成功返回NULL,否则返回错误信息
4.int dlclose(void * handler)
将一个已经加载的模块卸载。使用引用计数的原理卸载。
一个例子:
动态链接文件:a.so。编译方式:g++ a.cpp -fPIC -shared -o a.so (-shared 指定共享对象,-fPIC 指定与代码无关性)
/* a.cpp */
extern "C" //该句很重要,指定编译器不要对min使用C++符号修饰规则
{
int min(int a,int b)
{
return a < b ? a : b;
}
}
测试文件:main.cpp 编译方式:g++ main.cpp -o main -ldl (不加 -ldl 将无法找到 dlopen等函数)
#include <iostream>
#include <dlfcn.h>
using namespace std;
int main(int argc,char** argv)
{
void * handle;
int (*func)(int,int);
char * error;
handle = dlopen(argv[1],RTLD_NOW); //打开链接库句柄
if(NULL == handle)
{
cout << "can not open hanle" << endl;
return -1;
}
func = reinterpret_cast< int(*)(int,int) >(dlsym(handle,"min")); //查找符号Min,返回函数地址
if((error = dlerror()) != NULL)
{
cout << "find symble min error : " << error << endl;
return -1;
}
cout << "the test value is : " << (*func)(2,3) << endl; //根据返回地址调用函数
dlclose(handle);
return 0;
}
执行指令:./main ./a.so
输出结果:2