• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            tqsheng

            go.....
            隨筆 - 366, 文章 - 18, 評論 - 101, 引用 - 0
            數(shù)據(jù)加載中……

            linux下動態(tài)庫so文件的一些認識

            個人創(chuàng)作,歡迎指錯。 
            牽扯到ELF格式,gcc編譯選項待補,簡單實用的說明一下,對Linux下的so文件有個實際性的認識。 
            1.so文件是什么? 
            2.怎么生成以及使用一個so動態(tài)庫文件? 
            3.地址空間,以及線程安全. 
            4.庫的初始化,解析: 
            5.使用我們自己庫里的函數(shù)替換系統(tǒng)函數(shù): 
            //------------------------------------------------------------------------------- 
            1.so文件是什么? 
            也是ELF格式文件,共享庫(動態(tài)庫),類似于DLL。節(jié)約資源,加快速度,代碼升級簡化。 
            知道這么多就夠了,實用主義。等有了印象再研究原理。 
            2.怎么生成以及使用一個so動態(tài)庫文件? 
            先寫一個C文件:s.c 
            C代碼  
            #include <stdio.h>  
            int count;  
            void out_msg(const char *m)  
            {//2秒鐘輸出1次信息,并計數(shù)  
             for(;;) {printf("%s %d\n", m, ++count); sleep(2);}  
            }  
            編譯:得到輸出文件libs.o 
            gcc -fPIC -g -c s.c -o libs.o 
              
            鏈接:得到輸出文件libs.so 
            gcc -g -shared -Wl,-soname,libs.so -o libs.so libs.o -lc 
            一個頭文件:s.h 
            C代碼  
            #ifndef _MY_SO_HEADER_  
            #define _MY_SO_HEADER_  
            void out_msg(const char *m);  
            #endif  
            再來一個C文件來引用這個庫中的函數(shù):ts.c 
            C代碼  
            #include <stdio.h>  
             #include "s.h"  
             int main(int argc, char** argv)  
             {  
              printf("TS Main\n");  
              out_msg("TS ");  
              sleep(5);  //這句話可以注釋掉,在第4節(jié)的時候打開就可以。  
              printf("TS Quit\n");  
             }  
            編譯鏈接這個文件:得到輸出文件ts 
            gcc -g ts.c -o ts -L. -ls 
            執(zhí)行./ts,嗯:成功了。。。還差點 
            得到了ts:error while loading shared libraries: libs.so: cannot open shared object file: No such file or directory 
            系統(tǒng)不能找到我們自己定義的libs.so,那么告訴他,修改變量LD_LIBRARY_PATH,為了方便,寫個腳本:e(文件名就叫e,懶得弄長了) 
            #!/bin/sh 
            export LD_LIBRARY_PATH=${pwd}:${LD_LIBRARY_PATH} 
            ./ts 
            執(zhí)行:./e & 
            屏幕上就開始不停有信息輸出了,當然TS Quit你是看不到的,前面是個死循環(huán),后面會用到這句 
            3.地址空間,以及線程安全: 
            如果這樣: 
            ./e &開始執(zhí)行后,稍微等待一下然后再 ./e&, 
            這個時候屏幕信息會怎么樣呢?全局變量count會怎么變化? 
            會是兩個進程交叉輸出信息,并且各自的count互不干擾,雖然他們引用了同一個so文件。 
            也就是說只有代碼是否線程安全一說,沒有代碼是否是進程安全這一說法。 
            4.庫的初始化,解析: 
            windows下的動態(tài)庫加載,卸載都會有初始化函數(shù)以及卸載函數(shù)來完成庫的初始化以及資源回收,linux當然也可以實現(xiàn)。 
            ELF文件本身執(zhí)行時就會執(zhí)行一個_init()函數(shù)以及_fini()函數(shù)來完成這個,我們只要把自己的函數(shù)能讓系統(tǒng)在這個時候執(zhí)行 
            就可以了。 
            修改我們前面的s.c文件: 
            C代碼  
            #include <stdio.h>  
             void my_init(void) __attribute__((constructor)); //告訴gcc把這個函數(shù)扔到init section  
             void my_fini(void) __attribute__((destructor));  //告訴gcc把這個函數(shù)扔到fini section  
             void out_msg(const char *m)  
             {  
              printf(" Ok!\n");   
             }  
             int i; //仍然是個計數(shù)器  
             void my_init(void)  
             {  
              printf("Init ... ... %d\n", ++i);  
             }  
             void my_fini(void)  
             {  
              printf("Fini ... ... %d\n", ++i);  
             }  
            重新制作 libs.so,ts本是不用重新編譯了,代碼維護升級方便很多。 
            然后執(zhí)行: ./e & 
            可以看到屏幕輸出:(不完整信息,只是順序一樣) 
            Init 
            Main 
            OK 
            Quit 
            Fini 
            可以看到我們自己定義的初始化函數(shù)以及解析函數(shù)都被執(zhí)行了,而且是在最前面以及最后面。 
            如果s.c中的sleep(5)沒有注釋掉,那么有機會: 
            ./e& 
            ./e&連續(xù)執(zhí)行兩次,那么初始化函數(shù)和解析函數(shù)也會執(zhí)行兩次,雖然系統(tǒng)只加載了一次libs.so。 
            如果sleep時候kill 掉后臺進程,那么解析函數(shù)不會被執(zhí)行。 
            5.使用我們自己庫里的函數(shù)替換系統(tǒng)函數(shù): 
            創(chuàng)建一個新的文件b.c:我們要替換系統(tǒng)函數(shù)malloc以及free(可以自己寫個內(nèi)存泄露檢測工具了) 
            C代碼  
            #include <stdio.h>  
             void* malloc(int size)  
             {  
              printf("My malloc\n");  
              return NULL;  
             }  
             void free(void* ad)  
             {  
              printf("My free\n");  
             }  
            老規(guī)矩,編譯鏈接成一個so文件:得到libb.so 
            gcc -fPIC -g -c b.c -o libb.o 
            gcc -g -shared -Wl,-soname,libb.so -o libb.so -lc 
            修改s.c:重新生成libs.so 
            C代碼  
            void out_msg()  
             {  
              int *p;  
              p = (int*)malloc(100);  
              free(p);  
              printf("Stop Ok!\n");  
             }  
            修改腳本文件e: 
            #!/bin/sh 
            export LD_PRELOAD=${pwd}libb.so:${LD_PRELOAD} 
            export LD_LIBRARY_PATH=${pwd}:${LD_LIBRARY_PATH} 
            ./ts 
            關(guān)鍵就在LD_PRELOAD上了,這個路徑指定的so將在所有的so之前加載,并且符號會覆蓋后面加載的so文件中的符號。如果可執(zhí)行文件的權(quán)限不合適(SID),這個變量會被忽略。 
            執(zhí)行:./e & 
            嗯,可以看到我們的malloc,free工作了。 
            暫時就想到這么多了。

            posted on 2012-12-07 22:33 tqsheng 閱讀(721) 評論(0)  編輯 收藏 引用


            只有注冊用戶登錄后才能發(fā)表評論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久中文字幕精品| 国产精品免费久久久久影院| 久久只有这精品99| 久久久久国产精品熟女影院| 国产亚洲精品自在久久| 国产激情久久久久影院老熟女| 久久久久99精品成人片三人毛片| 一本色道久久88综合日韩精品 | 亚洲国产精品久久久久婷婷软件 | 色综合久久天天综线观看| 精品久久久无码人妻中文字幕| 久久久久久久久无码精品亚洲日韩| 久久精品免费观看| 中文精品久久久久人妻不卡| 国产精品99久久久久久猫咪| 7777精品久久久大香线蕉| 久久天天躁狠狠躁夜夜2020| 国产午夜免费高清久久影院| 欧美日韩中文字幕久久久不卡 | 久久er国产精品免费观看8| 伊人久久大香线蕉成人| 色综合久久中文色婷婷| 久久热这里只有精品在线观看| 狠狠久久综合| 久久久久久免费一区二区三区| 国产A三级久久精品| 亚洲国产成人精品久久久国产成人一区二区三区综 | 成人久久免费网站| 久久精品国产一区二区三区| 久久福利青草精品资源站免费| 97久久国产综合精品女不卡| 色诱久久av| 亚洲一区精品伊人久久伊人| 亚洲精品成人久久久| 九九久久精品无码专区| 久久综合综合久久97色| 国内精品久久久久久99蜜桃| 久久ZYZ资源站无码中文动漫| 伊人色综合久久天天人手人婷 | 亚洲国产精品成人久久| 国产成人综合久久精品红|