运行时(动态)加载

本文详细介绍了动态库加载的四个关键API:dlopen、dlsym、dlerror和dlclose。dlopen用于打开并加载动态库,dlsym查找动态库中的符号,dlerror检查错误,dlclose卸载动态库。讨论了dlopen的参数flag,如RTLD_LAZY和RTLD_NOW,以及如何处理动态库依赖和符号查找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    动态库的加载涉及到4个API接口:打开动态库(dlopen)、查找符号(dlsym)、错误处理(dlerror)以及关闭动态库(dlclose),程序可以通过这几个API对动态库进行操作。

1.dlopen()

    dlopen()函数用来打开一个动态库,并将其加载到进程地址空间,完成初始化的过程,它的C原型定义为:

void * dlopen(const char *filename, int flag);

    第一个参数是加载动态库的路径,如果这个路径是绝对路径(以"/"开始的路径),则该函数将尝试直接打开该动态库;如果是相对路径,那么dlopen()会尝试在以一定的顺序去查找该动态库文件:

1.查找有环境变量 LD_LIBRARY_PATH 指定的一系列目录。

2.查找由/etc/ld.so.cache里面所指定的共享库路径。

3./lib、/usr/lib。

    当然,这在理论上不应该成为一个问题,因为所有的库都应该只存在于某个目录中,而不应该在多个目录中有不同的副本,这将会导致系统变得极为不可靠。

    很有意思的是,如果我们将filename这个参数设置为0,那么dlopen返回的将是全局符号表的句柄,也就是说我们可在运行时找到全局符号表里面的任何一个符号,并且可以执行它们,这有些类似高级语言反射(Reflection)的特性。全局符号表包括了程序的可执行文件本身、被动态链接器加载到进程中的所有共享模块以及在运行时通过dlopen打开且使用了RTLD_GLOBAL方式的模块中的符号。

    第二个参数flag表示函数符号的解析方式,常量RTLD_LAZY表示使用延迟绑定,当函数第一次被调用到时才进行绑定,即PLT机制;而RTLD_NOW表示当模块被加载时即完成所有函数的绑定工作,如果有任何未定义符号的引用导致绑定工作没法完成,那么dlopen()会返回错误。上面的两种绑定方式必须选其一。另外还有一个常量RTLD_GLOBAL可以跟上面的两者中的任意一个仪器使用(通过常量的“或”操作),它表示将被加载模块的全局符号合并到进程的全局符号表中,使得以后加载的模块可以使用这些符号。(使用 RTLD_NOW会导致加载动态库的速度变慢)

    dlopen的返回值是被加载模块的句柄,这个句柄dlsym或者dlclose会用到。如果加载模块失败,则返回NULL。如果模块已经通过dlopen被加载过了,那么返回的是同一个句柄。另外如果被加载模块有依赖关系,比如模块A依赖于模块B,那么程序员需手工加载被依赖的模块,比如先加载B,再加载A。

 

2.dlsym()

    dlsym函数基本上是运行时装载的核心部分,我们可以通过这个函数找到所需要的符号。它的定义如下:

void * dlsym(void *handle, char *symbol);

    第一个参数是有dlopen返回的动态库句柄;第二个参数即所要查找的符号的名字,一个以“\0”结尾的C字符串。如果dlsym()找到了相应的符号,则返回该符号的值;没找到相应的符号,则返回NULL。dlsym()返回值对于不同类型的符号意义是不同的。如果查找的符号是个函数,那么它返回函数的地址;如果是个变量,它返回变量的地址;如果这个符号是个常量,那么它返回的是该常量的值。这里有一个问题是:如果常量的值刚好是NULL或者0呢?我们该如何判断dlsym()是否找到了该符号呢?通过dlerror()函数可以确认,如果符号找到了,那么dlerror()返回NULL,如果没找到,dlerror()就会返回相应的错误信息。

 

3.dlerror()

    在调用dlopen()、dlsym()、dlclose()以后,我们都可以调用dlerror()函数来判断上一次调用是否成功。dlerror()的返回值类型是char*,如果返回NULL,则表示上一次调用成功;如果不是,则返回相应的错误信息。

 

4.dlclose()

    dlclose()的作用跟dlopen()刚好相反,它的作用是将一个已经加载的模块卸载。系统会维持一个加载引用计数器,每次使用dlopen()加载某个模块时,相应的计数器加一;每次使用dlclose()卸载某个模块时,相应的计数器减一。只有当计数器值减到0时,模块才被真正地卸载掉,相应的符号从符号表中去除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值