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的進程啟動失敗(動態鏈接在進程啟動的時候去加載動態庫失敗)。

更加深入的文章,請參考http://www.ibm.com/developerworks/cn/linux/l-dynamic-libraries/index.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM