分享

linux下的动态链接库和静态链接库到底是个什么鬼?(三)动态加载库

 昵称28625772 2015-10-27
linux下的动态链接库和静态链接库到底是个什么鬼?(三)动态加载库

    前两天搞明白了动态链接库和静态链接库,后面终于也基本上搞懂了我之前不明白的“dlopen”是咋回事,怎么也要扒一扒。

    共享库,有两种形式,第一种就是在上一篇文章中说到的“动态链接库”,而共享库的另一种形式,则被称之为“动态加载库”,也就是我刚才提到的用“dlopen”方式来玩的。动态加载库在编译的时候,应该是不需要去-l引用lib,而是在可执行程序中,可以自已决定加载库的时机。比如程序跑着跑着,突然想用libabc.so库里的一个叫abc的函数了,这时就可以用dlopen去打开这个库,然后使用dlsym去找到abc的函数指针并调用即可。

   这几个以“dl”开头的函数,叫动态加载API,提供了以下这么几个接口来支持动态加载操作:

void *dlopen( const char *file, int mode ); 

    dlopen的函数功能是打开库文件并返回文件句柄,mode参数表示重定位的时机,有RTLD_NOW和RTLD_LAZY两个值 ,这个我们后面再分析是啥意思。

void *dlsym( void *restrict handle, const char *restrict name ); 

    dlsym函数的功能是从这个新加载的库里根据传入的函数名,找到该函数的地址

char *dlerror();

    dlerror没有入参,它会返回发生的上一个错误的字符串

char *dlclose( void *handle );

    dlclose关闭打开的库文件,实际上如果当前还有其他的程序引用这个库,它是不会被关闭的,多个程序共享时采用引用计数机制,当最后一个引用它的程序关闭它时才会真正的关闭。这几个函数在使用时,需要包含<dlfcn.h>头文件。

下面我依然用之前sumapp这个简单的demo程序来演示一下动态加载库的用法。

    首先libsum.so生成方式不变,具体可参考上一篇文章。main.c的代码我们需要变一下,重新以dlopen的方式去引用libsum.so,  代码如下:

    

复制代码
192:zch kane$ ls
demodlopen.c    main.c        sum.h        sumappd
libsum.so    sum.c        sum.o
192:zch kane$ 
192:zch kane$ 
192:zch kane$ 
192:zch kane$ more demodlopen.c 
#include<stdio.h>
#include<dlfcn.h>

int  main(void)
{
    int iNum1 = 1;
    int iNum2 = 2;
    void * pHandle = NULL;
    int (*pFunc)(int, int) = NULL;
    char * pcError;
    int iRet = 0;

    pHandle = dlopen("libsum.so", RTLD_LAZY);
    if (NULL == pHandle)
    {
        printf("Open libsum.so failed!, error message is %s\r\n.", dlerror());
        return 0;
    }
    
    pFunc = dlsym(pHandle, "Sum");
    if (NULL == pFunc)
    {
        printf("Find function Sum failed!, error message is %s\r\n.", dlerror());
        return 0;
    }
    
    iRet =  (*pFunc)(iNum1, iNum2);
    printf("iRet = %d\r\n", iRet);
    dlclose(pHandle);
    return 0; 
}
192:zch kane$ 
复制代码

编译demodlopen.c,执行sumappd

192:zch kane$ gcc -rdynamic -o sumappd demodlopen.c -ldl
192:zch kane$./sumappd 
iRet = 3

编译时-rdynamic用来通知链接器将所有符号添加到动态符号表中(目的是能够通过使用 dlopen 来实现向后跟踪)。-ldl 表明一定要将 dllib 链接于该程序。

 

总结:动态链接库在加载时机是进程启动,而动态加载库则由程序自行决定加载时机。看了下网上有一些同学也不太明白到底什么时候适合用动态链接库,什么时候适合用动态加载库。我说一下我在工作中遇到的一个场景就是用的动态加载。由于我们做的是基于linux的嵌入式软件平台,需要同时支持多款产品,而有些特性或者说业务,在某款产品上可能不支持,以达到产品差异化的目的。比如业务A在运行时可能会用到libabc.so, 但是 libabc.so在某款产品上可能会被裁减掉,因此对于这种情况,在编译版本及写代码的时候,就得用动态加载这种方式。因为如果你用动态链接的方式,而libabc.so刚好在这款产品上被裁掉了,会导致业务A的进程启动失败(动态链接在进程启动的时候去加载动态库失败)。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多