亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 807 | 回復: 0
打印 上一主題 下一主題

為 Linux 應(yīng)用程序編寫 DLL [復制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2009-07-09 20:00 |只看該作者 |倒序瀏覽
為 Linux 應(yīng)用程序編寫 DLL
Allen Wilson
(
[email=wilsona@us.ibm.com?subject=%E4%B8%BA%20Linux%20%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%BC%96%E5%86%99%20DLL&cc=wilsona@us.ibm.com]wilsona@us.ibm.com[/email]
), 電子商務(wù)設(shè)計師, IBM
插件和 DLL 通常是用來無須編寫整個新應(yīng)用程序而添加功能的極好方法。在 Linux 中,插件和 DLL
是以動態(tài)庫形式實現(xiàn)的。電子商務(wù)顧問兼設(shè)計師 Allen Wilson
介紹了動態(tài)庫,并且向您演示了如何在某一個應(yīng)用程序正在運行之后使用動態(tài)庫來更改該應(yīng)用程序。
      
Internet 瀏覽器用戶非常熟悉插件的概念。從 Web
上下載插件,通常這些插件為瀏覽器的音頻、視頻以及特殊效果提供增強支持。一般來講,在不更改原有應(yīng)用程序的情況下,插件為現(xiàn)有應(yīng)用程序提供新功能。
      
DLL
是程序函數(shù),它們在設(shè)計和構(gòu)建應(yīng)用程序時為該程序所知。設(shè)計應(yīng)用程序的主程序時使用程序框架或底板,這些程序框架或底板在運行時選擇性地裝入所需的
dll,這些 dll
位于磁盤上同主程序分離的一些文件中。這一打包和動態(tài)裝入提供了靈活的升級、維護、以及許可策略。
      
隨 Linux 一起交付的還有幾千條命令和應(yīng)用程序,它們至少都需要 libc
庫函數(shù)。如果 libc
函數(shù)與每一個應(yīng)用程序都打包在一起,那么磁盤上將會出現(xiàn)幾千個相同函數(shù)的副本。Linux
構(gòu)建這些應(yīng)用程序,以使用通常所需的系統(tǒng)庫的單個系統(tǒng)級副本,而不浪費磁盤空間。Linux
甚至做得更好,每個需要公共系統(tǒng)庫函數(shù)的進程使用單個的系統(tǒng)級內(nèi)的副本,一次性將該副本裝入到內(nèi)存并為各進程所共享。
      
在 Linux 中,插件和 dll
以動態(tài)庫形式實現(xiàn)。本文的余下部分是在應(yīng)用程序運行之后使用動態(tài)庫更改該應(yīng)用程序的示例。
      
Linux 動態(tài)鏈接
      
Linux
中的應(yīng)用程序以以下兩種方式之一鏈接到外部函數(shù):要么在構(gòu)建時與靜態(tài)庫(
        
lib*.a )
        靜態(tài)地鏈接,并且將庫代碼包含在該應(yīng)用程序的可執(zhí)行文件里;要么在運行時與共享庫(
        
lib*.so )
        動態(tài)地鏈接。通過動態(tài)鏈接裝入器,將動態(tài)庫映射進應(yīng)用程序的可執(zhí)行內(nèi)存中。在啟動應(yīng)用程序之前,動態(tài)鏈接裝入器將所需的共享目標庫映射到應(yīng)用程序的內(nèi)存,或者使用系統(tǒng)共享的目標并為應(yīng)用程序解析所需的外部引用,F(xiàn)在應(yīng)用程序就可以運行了。
      
      
作為示例,下面有一個演示 Linux
中對動態(tài)鏈接庫的缺省使用的小程序:

      main()
{
   printf("Hello world
");
}

      
當使用 gcc 編譯 hello.c 時,就創(chuàng)建了一個名為
        a.out
的可執(zhí)行文件。通過使用 Linux 命令
        ldd
a.out (該命令打印出共享庫的相互依賴性),可以看出所需的共享庫是:
      

              libc.so.6 => /lib/libc.so.6 (0x4001d000)
         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

      
使用相同的動態(tài)鏈接裝入器在應(yīng)用程序運行之后將 dll
映射進應(yīng)用程序的內(nèi)存。通過使用 Linux
動態(tài)裝入器例程,應(yīng)用程序控制裝入哪一個動態(tài)庫以及調(diào)用庫中的哪一個函數(shù),以執(zhí)行裝入和鏈接以及返回所需入口點的地址。
      




回頁首
Linux dll 函數(shù)
      
Linux 提供 4 個庫函數(shù)(
        dlopen ,
        dlerror ,
        dlsym 和
        dlclose ),一個 include
文件(
        dlfcn.h )以及兩個共享庫(靜態(tài)庫
        libdl.a 和動態(tài)庫
        libdl.so ),以支持動態(tài)鏈接裝入器。這些庫函數(shù)是:
      
      

  •           dlopen
    將共享目標文件打開并且映射到內(nèi)存中,并且返回句柄
            

  •           dlsym返回一個指向被請求入口點的指針
            

  •           dlerror 返回 NULL 或者一個指向描述最近錯誤的 ASCII
    字符串的指針
            

  •           dlclose關(guān)閉句柄并且取消共享目標文件的映射
            

      
動態(tài)鏈接裝入器例程 dlopen
需要在文件系統(tǒng)中查找共享目標文件以打開文件并創(chuàng)建句柄。有 4
種方式用以指定文件的位置:
      


  •           dlopen call 中的絕對文件路徑
            
  • 在 LD_LIBRARY_PATH 環(huán)境變量中指定的目錄中
  • 在 /etc/ld.so.cache 中指定的庫列表之中
  • 先在 /usr/lib 之中,然后在 /lib 之中

      




回頁首
dll 示例:小的 C 程序和 dlTest
      
動態(tài)鏈接裝入器示例程序是一個小的 C 程序,該程序被設(shè)計用來練習 dl
例程。該程序基于每個人都編寫過的一個 C 程序,它將“Hello
World”打印到控制臺上。最初打印的消息是“HeLlO
WoRlD”。該測試程序鏈接到再次打印該消息的兩個函數(shù)上:第一次都用大寫字符,第二次都用小寫字符。
      
以下是該程序的概要:
      
  • 定義 dll include 文件
              dlfcn.h 和所需的變量。
    至少需要這些變量:
             
    • 到共享庫文件的句柄
    • 指向被映射函數(shù)入口點的指針
    • 指向錯誤字符串的指針

            
  • 打印初始消息,“HeLlO WoRlD”。
  • 使用絕對路徑“/home/dlTest/UPPERCASE.so”和選項
    RTLD_LAZY,
              dlopen 打開 UPPERCASE dll
    的共享目標文件并返回句柄。
             
    • 選項 RTLD_LAZY 推遲解析 dll 的外部引用,直到 dll 被執(zhí)行。
    • 選項 RTLD_NOW 在
                    dlopen
      返回之前解析所有的外部引用。
                  

            


  •           dlsym 返回入口點 printUPPERCASE 的地址。
             
            
  • 調(diào)用 printUPPERCASE 并且打印修改過的消息“HELLO WORLD”。


  •           dlclose 關(guān)閉到 UPPERCASE.so
    的句柄,并且從內(nèi)存中取消 dll 映射。
             
            


  •           dlopen 使用基于環(huán)境變量 LD_LIBRARY_PATH
    的相對路徑查找共享目標路徑,來打開 lowercase dll 的共享目標文件
    lowercase.so,并且返回句柄。
             
            


  •           dlsym 返回入口點 printLowercase 的地址。
             
            
  • 調(diào)用 printLowercase 并且打印修改過的信息“hello world”。


  •           dlclose 關(guān)閉到 lowercase.so
    的句柄,并且從內(nèi)存中取消 dll 映射。
            
          
    注意,每次調(diào)用
            dlopen 、
            dlsym 或
            dlclose 之后,調(diào)用
            dlerror
    以獲取最后的錯誤信息,并且打印該錯誤信息字符串。以下是 dlTest
    的測試運行:
          

             dlTest  2-Original message
    HeLlO WoRlD
        dlTest  3-Open Library with absolute path return-(null)-
        dlTest  4-Find symbol printUPPERCASE return-(null)-
    HELLO WORLD
        dlTest  5-printUPPERCASE return-(null)-
        dlTest  6-Close handle return-(null)-
        dlTest  7-Open Library with relative path return-(null)-
        dlTest  8-Find symbol printLowercase return-(null)-
    hello world
        dlTest  9-printLowercase return-(null)-
        dlTest 10-Close handle return-(null)-

          
    完整的 dlTest.c、UPPERCASE.c 和 lowercase.c
    源代碼清單在本文后面的
            
    清單
    里。
          
          




    回頁首
    構(gòu)建 dlTest
          
    啟用運行時動態(tài)鏈接需要三步:
          
  • 將 dll 編譯為位置無關(guān)代碼
  • 創(chuàng)建 dll 共享目標文件
  • 編譯主程序并同 dl 庫相鏈接
          
    編譯 UPPERCASE.c 和 lowercase.c 的 gcc 命令包含 -fpic 選項。選項
    -fpic 和 -fPIC
    導致生成的代碼是位置無關(guān)的,重建共享目標庫需要位置無關(guān)。-fPIC
    選項產(chǎn)生位置無關(guān)的代碼,這類代碼支持大偏移。用于 UPPERCASE.o 和
    lowercase.o 的第二個 gcc 命令,帶有 -shared
    選項,該選項產(chǎn)生適合于動態(tài)鏈接的共享目標文件 a*.so。
          
    用于編譯和執(zhí)行 dltest 的 ksh 腳本如下:

          #!/bin/ksh
    #  Build shared library
    #
    #set -x
    clear
    #
    #  Shared library for dlopen absolute path test
    #
    if [ -f UPPERCASE.o ]; then rm UPPERCASE.o
    fi
    gcc  -c -fpic UPPERCASE.c
    if [ -f UPPERCASE.so ]; then rm UPPERCASE.so
    fi
    gcc -shared -lc  -o UPPERCASE.so  UPPERCASE.o
    #
    #  Shared library for dlopen relative path test
    #
    export LD_LIBRARY_PATH=`pwd`
    if [ -f lowercase.o ]; then rm lowercase.o
    fi
    gcc  -c -fpic lowercase.c
    if [ -f lowercase.so ]; then rm lowercase.so
    fi
    gcc -shared -lc  -o lowercase.so  lowercase.o
    #
    #  Rebuild test program
    #
    if [ -f dlTest ]; then rm dlTest
    fi
    gcc -o dlTest dlTest.c -ldl
    echo Current LD_LIBRARY_PATH=$LD_LIBRARY_PATH
    dlTest

          




    回頁首
    結(jié)束語
          
    創(chuàng)建能在運行時被動態(tài)鏈接到 Linux
    系統(tǒng)上的應(yīng)用程序的共享目標代碼是一項非常簡單的練習。應(yīng)用程序通過使用對動態(tài)鏈接裝入器的
    dlopen、dlsym 和 dlclose
    函數(shù)調(diào)用來獲取對共享目標文件的訪問。dlerror
    以字符串的形式返回任何錯誤,這些錯誤信息字符串描述 dl
    函數(shù)碰到的最后一個錯誤。在運行時,主應(yīng)用程序使用絕對路徑或相對于
    LD_LIBRARY_PATH 的相對路徑找到共享目標庫,并且請求所需的 dll
    入口點的地址。當需要時,也可對 dll
    進行間接函數(shù)調(diào)用,最后,關(guān)閉到共享目標文件的句柄,并且從內(nèi)存中取消該目標文件映射,使之不可用。
          
    使用附加選項 -fpic 或 -fPIC
    編譯共享目標代碼,以產(chǎn)生位置無關(guān)的代碼,使用 -shared
    選項將目標代碼放進共享目標庫中。
          
    Linux
    中的共享目標代碼庫和動態(tài)鏈接裝入器向應(yīng)用程序提供了額外的功能。減少了磁盤上和內(nèi)存里的可執(zhí)行文件的大小。可以在需要時,裝入可選的應(yīng)用程序功能,可以在無須重新構(gòu)建整個應(yīng)用程序的情況下修正缺陷,并且應(yīng)用程序可以包含第三方的插件。
          




    回頁首
    清單(應(yīng)用程序和 dll)
          
          
    dlTest.c:

          
    /*************************************************************/
    /*     Test Linux Dynamic Function Loading              */
    /*                                      */
    /*     void       *dlopen(const char *filename, int flag)           */
    /*          Opens dynamic library and return handle     */
    /*                                      */
    /*     const char *dlerror(void)                    */
    /*          Returns string describing the last error.           */
    /*                                      */
    /*     void       *dlsym(void *handle, char *symbol)            */
    /*          Return pointer to symbol's load point.          */
    /*          If symbol is undefined, NULL is returned.           */
    /*                                      */
    /*     int        dlclose (void *handle)                    */
    /*          Close the dynamic library handle.               */
    /*                                      */
    /*                                      */
    /*                                      */
    /*************************************************************/
    #include
    #include   

    /*                              */
    /* 1-dll include file and variables */
    /*                              */
    #include   
    void  *FunctionLib;     /*  Handle to shared lib file   */
    int   (*Function)();        /*  Pointer to loaded routine   */
    const char *dlError;        /*  Pointer to error string     */
    main( argc, argv )
    {
      int   rc;             /*  return codes            */
      char HelloMessage[] = "HeLlO WoRlD\n";

    /*                              */
    /* 2-print the original message                 */
    /*                              */
      printf("  dlTest  2-Original message \n");
      printf("%s", HelloMessage);
    /*                                               */
    /*  3-Open Dynamic Loadable Libary with absolute path      */
    /*                                              */
      FunctionLib = dlopen("/home/dlTest/UPPERCASE.so",RTLD_LAZY);
      dlError = dlerror();
      printf("  dlTest  3-Open Library with absolute path return-%s- \n", dlError);
      if( dlError ) exit(1);
    /*                              */
    /* 4-Find the first loaded function */
    /*                              */
      Function    = dlsym( FunctionLib, "printUPPERCASE");
      dlError = dlerror();
      printf("  dlTest  4-Find symbol printUPPERCASE return-%s- \n", dlError);
      if( dlError ) exit(1);
    /*                              */
    /* 5-Execute the first loaded function              */
    /*                              */
      rc = (*Function)( HelloMessage );
      printf("  dlTest  5-printUPPERCASE return-%s- \n", dlError);
    /*                              */
    /* 6-Close the shared library handle                    */
    /* Note:  after the dlclose, "printUPPERCASE" is not loaded     */
    /*                              */
      rc = dlclose(FunctionLib);
      dlError = dlerror();
      printf("  dlTest  6-Close handle return-%s-\n",dlError);
      if( rc ) exit(1);
    /*                              */
    /*  7-Open Dynamic Loadable Libary using LD_LIBRARY path        */
    /*                              */
      FunctionLib = dlopen("lowercase.so",RTLD_LAZY);
      dlError = dlerror();
      printf("  dlTest  7-Open Library with relative path return-%s- \n", dlError);
      if( dlError ) exit(1);
    /*                              */
    /* 8-Find the second loaded function                */
    /*                              */
      Function    = dlsym( FunctionLib, "printLowercase");
      dlError = dlerror();
      printf("  dlTest  8-Find symbol printLowercase return-%s- \n", dlError);
      if( dlError ) exit(1);
    /*                              */
    /* 8-execute the second loaded function             */
    /*                              */
      rc = (*Function)( HelloMessage );
      printf("  dlTest  9-printLowercase return-%s- \n", dlError);
    /*                              */
    /* 10-Close the shared library handle               */
    /*                              */
      rc = dlclose(FunctionLib);
      dlError = dlerror();
      printf("  dlTest 10-Close handle return-%s-\n",dlError);
      if( rc ) exit(1);
      return(0);
    }

          
          
    UPPERCASE.c:

          /************************************************/
    /*      Function to print input string as UPPER case.         */
    /*      Returns 1.                                                            */
    /*********************************************** */
    int printUPPERCASE ( inLine )
    char inLine[];
    {
       char UPstring[256];
       char *inptr, *outptr;
       
       inptr = inLine;
       outptr = UPstring;
       while ( *inptr != '\0' )
          *outptr++ = toupper(*inptr++);
      *outptr++ = '\0';
       printf(UPstring);
       return(1);
    }

          
          
    lowercase.c

          /********************************************/
    /*     Function to print input string as lower case.      */
    /*     Returns 2.                                                      */
    /******************************************* */
    int printLowercase( inLine )
    char inLine[];
    {
       char lowstring[256];
       char *inptr, *outptr;
       inptr = inLine;
       outptr = lowstring;
       while ( *inptr != '' )
          *outptr++ = tolower(*inptr++);
      *outptr++ = '';
       printf(lowstring);
       return(2);
    }

       
    參考資料
          
    • 您可以參閱本文在 developerWorks 全球站點上的
               
      英文原文
      .
              
    • 下載
                IBM
      developer kit for Linux.
               
              
    • 同樣在
                developerWorks上,請閱讀相關(guān)文章
                "shared
      objects for the object disoriented!".
               
              

    •           developerWorks上瀏覽
                更多 Linux
      參考資料。
               
              

    •           developerWorks上瀏覽
               
      更多開放源碼參考資料。
              

       
    關(guān)于作者


    Allen Wilson 在位于美國堪薩斯州奧斯汀的 IBM
    任電子商務(wù)設(shè)計師兼顧問。他的專長領(lǐng)域包括 Linux、AIX、WebSphere
    Application Server 和應(yīng)用程序托管。您可以通過
            
    [email=wilsona@us.ibm.com?cc=wilsona@us.ibm.com]wilsona@us.ibm.com[/email]
    同他聯(lián)系。
          
                   
                   
                   

    本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u2/76419/showart_1991129.html
  • 您需要登錄后才可以回帖 登錄 | 注冊

    本版積分規(guī)則 發(fā)表回復

      

    北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年舉報專區(qū)
    中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
    感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP