dlopen动态装载共享库

上传人:桔**** 文档编号:460234096 上传时间:2022-08-14 格式:DOC 页数:5 大小:105KB
返回 下载 相关 举报
dlopen动态装载共享库_第1页
第1页 / 共5页
dlopen动态装载共享库_第2页
第2页 / 共5页
dlopen动态装载共享库_第3页
第3页 / 共5页
dlopen动态装载共享库_第4页
第4页 / 共5页
dlopen动态装载共享库_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

《dlopen动态装载共享库》由会员分享,可在线阅读,更多相关《dlopen动态装载共享库(5页珍藏版)》请在金锄头文库上搜索。

1、dlopen动态装载共享库、基本说明显式运行时链接(ExplicitRun-timeLinking),有时候也叫做运行时加载,程序自己在运行时控制加载指定的模块,即动态库,并且可以在不需要该模块时将其卸载。和普通的动态链接相比,显式运行时链接,可以使程序在需要使用到某个插件或驱动时,才将相应的模块加载进来,而不需要在一开始就将所有插件和驱动的模块进行加载,从未减少了程序启动的时间和内存使用。并且程序可以在运行过程中动态的重新加载模块,从而实现程序在不重启的前提下,实现模块的增加、删除、更新等需求。普通的动态链接,是由动态链接器在程序启动之前完成模块的装载和链接的,这一过程自动完成(eg:gcc

2、-odemodemo.c-Itest);但是动态库的显式运行链接则是通过一系列的动态链接器提供的API(dlopen,dlsym,dlerror,dlclose),手动干预完成。二、接口介绍运行时加载,一共由四个函数完成:打开动态库(dlopen)、查找符号(dlsym)、错误处理(dierror)、卸载动态库(dlclose)。这四个API实现在/lib/libdl.so.2中,声明和相关常量被定义在系统标准头文件dlfcn.h。1. dlopen:打开一个动态库,并将其加载到进程的地址空间,完成初始化过程1-函数原型:void*dlopen(constchar*filename,intfl

3、ag);2. 参数说明:3. constchar*filename:被加载的动态库的路径该路径可以是绝对路径,如果使用了绝对路径,那么dlopen函数会尝试直接打开对应路径的动态库;也可以使用相对路径,在该情况下,dlopen则会尝试按一定顺序去寻找该动态库,若找到则打开,并返回对应句柄。以下为使用相对路径情况下,dlopen函数查找的顺序:(1) (仅限ELF)如果程序的可执行文件中包含DT_RPATH标签并且没有包含DT_RUNPATH标签,那么查找DT_RPATH中指定的目录(2) 查找环境变量LD_LIBRARY_PATH指定的一系列目录(3) (仅限ELF)如果可执行文件中包含了DT

4、_RUNPATH标签,那么查找DT_RUNPATH中指定的目录(4) 查找由/etc/ld.so.cache里面所指定的共享库路径(5) /lib、/usr/lib(1和3,来自于LinuxProgrammersManual,也有人说这里的描述是错误的,正确性尚未明确)filename还可以被设置为0,那么dlopen返回的将是全局符号表的句柄,也就是说,可以在运行时找到全局符号表里的任何一个符号,并且可以执行他们。全局符号表包括了:程序可执行文件本身、被动态链接库加载到进程中的所有共享模块,以及在运行时通过dlopen()打开并且使用了RTLD_GLOBAL方式的模块中的所有符号。4. in

5、tflag:函数符号的解析方式,有以下几种,部分方式在使用时可以通过“或”运算一起使用1. RTLD_LAZY:使用延迟绑定。当函数在第一次被调用的时候才执行绑定(符号查找、重定位等),如果没有用到则不进行绑定。所以在dlopen()函数返回的时候,模块间调用的函数调用都没有进行绑定,而是需要用到时才由动态链接器来负责绑定,这样能提高模块的加载速度。2. RTLD_NOW:当模块被加载完时即完成所有函数的绑定工作,如果有任何未定义的符号引用的绑定工作没法完成,那么dlopen()就会返回错误。3. RTLD_GLOBAL:3. RTLD_GLOBAL:被加载的模块的全局符号合并到进程的全局符号

6、表中,使得以后加载的模块可以使用这些符号。4. RTLD_LOCAL:与RTLD_GLOBAL作用相反,该动态库内定义的符号不能被在其后加载的动态库重定位,即后续加载的动态库不可使用该库中的符号。注:RTLD_LAZY和RTLD_NOW必须使用一个;RTLD_GLOBAL和RTLD_LOCLA可以与RTLD_LAZY和RTLD_NOW任意一个一起使用,通常操作为“或“,RTLD_LOCLA和RTLD_GLOBAL在缺省的情况下,默认为RTLD_LOCLA5.注意事项:dlopen的返回值是被加载模块的句柄,该句柄在后续使用dlsym()和dlclose()时需要用到。如果加载失败,则返回NUL

7、L。如果模块已经被加载过了,那么将返回与上一次加载相同的句柄。如果加载的模块之间存在依赖关系,那么该依赖需要手动干预。比如模块A依赖于模块B,那么必须先加载B,再进行加载A的操作。2. dlsym:运行时装载的核心,通过该函数找到所需符号1-函数原型:void*dlsym(void*handle,char*symbol);2.参数介绍:1. void*handle:dlopen()返回的动态库句柄;2. char*symbol:需要查找的符号名字,一个以、0结尾的C字符串。3. 使用说明:如果dlsym()找到对应的符号,则返回该符号的值;没有找到,则返回NULL。dlsym()返回的值对于不

8、同类型的符号,意义不同。如果查找的符号是函数,那么将返回该函数的地址;如果是变量,则返回该变量的地址;如果是常量,那么返回的是常量的值,如果常量的值恰好是NULL或0,那么将通过dlerror()函数来进行判断,如果找到符号,那么dlerror()将返回NULL;如果没找到,dlerror()会返回对应的错误信息。3.注意事项:在查找动态库符号时,存在符号优先级问题。常规的动态链接采用的优先级方式为装载序列,即先装入的符号优先。但是dlsym()对符号的查找优先级存在两种情况:(1) 如果在全局符号表中进行符号查找,即dlopen()的filename参数为NULL,那么由于全局符号表使用的是

9、装载序列,所以dlsym()使用的也是装载序列;(2) 如果是对某个通过dlopen()打开的共享对象进行符号查找的话,那么采用的是一种叫做依赖序列的优先级。依赖序列,是以被dlopen()打开的共享对象为根节点,对它所有依赖的共享对象进行广度优先遍历,直到找到符号为止。3. dlerror1-函数原型:char*dlerror(void);2.使用说明:每次调用dlopen()、dlsym()或dlclose()以后,都可以调用dlerror()函数来判断上一次调用是否成功。如果成功,则dlerror()返回NULL;如果失败,则返回对应的错误信息。4. dlclose1-函数原型:intd

10、lclose(void*handle);2使用说明:dlclose()的作用与dlopen()相反,它的作用是将一个已经加载的模块卸载。系统会维持一个加载引用计数器,每次使用dlopen()加载某模块时,相应的计数器加1;每次使用dlclose()卸载某模块时,相应计数器减1。只有当计数器减至0时,模块才被真正地卸载掉。卸载过程与加载相反,先执行“finit”段代码,然后将相应的符号从符号表中去除,取消进程空间与模块的映射关系,然后关闭模块文件。附录以下为dlopen等接口的简单使用demo:/main.c#include#include#includeypedefint(*func_add)

11、(int,int);/相对路径constchar*relativePath_a=./libadd.so;/绝对路径constchar*absPath_a=/home/44124/test/libadd.so;ntmain(intargc,char*argv)Hvoid*handle=dlopen(absPath_a,RTLD_LAZY);dlerror();if(!handle)fprintf(stderr,%s(%d)dlopengeterror:%sn:_FILE_,_LINEexit(EXIT_FAILURE);dofunc_addadd=(func_add)dlsym(handle,add);printf(1add2is%dn,add(1,2);while(0);dlclose(handle);return0;/cmd:gccodemogmain.cldl;./demo/output:1add2is

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 解决方案

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号