您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“Linux系統(tǒng)so文件內(nèi)容有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Linux系統(tǒng)so文件內(nèi)容有哪些”吧!
也是ELF格式文件,共享庫(動(dòng)態(tài)庫),類似于DLL。節(jié)約資源,加快速度,代碼升級(jí)簡(jiǎn)化。 知道這么多就夠了,實(shí)用主義。等有了印象再研究原理。
先寫一個(gè)C文件:s.c
#include int count; void out_msg(const char *m) {//2秒鐘輸出1次信息,并計(jì)數(shù) for(;;) {printf("%s %d\n", m, ++count); sleep(2);} }
編譯:得到輸出文件libs.o gcc -fPIC -g -c s.c -o libs.o
與位置無關(guān)代碼(Position-Independent Code),則產(chǎn)生的代碼中,沒有絕對(duì)地址,全部使用相對(duì)地址,故而代碼可以被加載器加載到內(nèi)存的任意 位置,都可以正確的執(zhí)行。這正是共享庫所要求的,共享庫被加載時(shí),在內(nèi)存的位置不是固定的。
: -fPIC作用于編譯階段,告訴編譯器產(chǎn)生: 令 gcc 生成調(diào)試信息,該選項(xiàng)可以利用操作系統(tǒng)的“原生格式(native format)”生成調(diào)試信息。GDB 可以直接利用這個(gè)信息,其它調(diào)試器也可以使用這個(gè)調(diào)試信息
-c: 僅執(zhí)行編譯操作,不進(jìn)行連接操作。 -o: 指定生成的輸出文件名稱
注意!-c,-o不是指.c文件和.o文件?。?/p>
得到輸出文件libs.so gcc -g -shared -Wl,-soname,libs.so -o libs.so libs.o -lc
上述語句中 libs.o是輸入文件
-shared:
-Wl: 注意第二個(gè)字母是小寫的L,不是I
:
soname的關(guān)鍵功能是它提供了兼容性的標(biāo)準(zhǔn):
當(dāng)要升級(jí)系統(tǒng)中的一個(gè)庫時(shí),并且新庫的soname和老庫的soname一樣,用舊庫鏈接生成的程序使用新庫依然能正常運(yùn)行。這個(gè)特性使得在Linux下,升級(jí)使得共享庫的程序和定位錯(cuò)誤變得十分容易。
在Linux中,應(yīng)用程序通過使用soname,來指定所希望庫的版本,庫作者可以通過保留或改變soname來聲明,哪些版本是兼容的,這使得程序員擺脫了共享庫版本沖突問題的困擾。
-lc:
-l 是直接加上某庫的名稱,如-lc是libc庫 -L 是庫的路徑,搜索的時(shí)候優(yōu)先在-L目錄下搜索
一個(gè)頭文件:s.h
#ifndef _MY_SO_HEADER_ #define _MY_SO_HEADER_ void out_msg(const char *m); #endif
再來一個(gè)C文件來引用這個(gè)庫中的函數(shù):ts.c
#include #include "s.h" int main(int argc, char** argv) { printf("TS Main\n"); out_msg("TS "); sleep(5); //這句話可以注釋掉,在第4節(jié)的時(shí)候打開就可以。 printf("TS Quit\n"); }
編譯鏈接這個(gè)文件:得到輸出文件ts gcc -g ts.c -o ts -L. -ls
執(zhí)行./ts,嗯:成功了。。。還差點(diǎn) 得到了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,為了方便,寫個(gè)腳本:e(文件名就叫e,懶得弄長了)
export LD_LIBRARY_PATH=${pwd}:${LD_LIBRARY_PATH} ./ts
執(zhí)行:./e & 屏幕上就開始不停有信息輸出了,當(dāng)然TS Quit你是看不到的,前面是個(gè)死循環(huán),后面會(huì)用到這句
———————-
& 放在啟動(dòng)參數(shù)后面表示設(shè)置此進(jìn)程為后臺(tái)進(jìn)程。默認(rèn)情況下,進(jìn)程是前臺(tái)進(jìn)程,這時(shí)就把Shell給占據(jù)了,我們無法進(jìn)行其他操作,對(duì)于那些沒有交互的進(jìn)程,很多時(shí)候,我們希望將其在后臺(tái)啟動(dòng),可以在啟動(dòng)參數(shù)的時(shí)候加一個(gè)’&’實(shí)現(xiàn)這個(gè)目的。
———————-
3.地址空間,以及線程安全: 如果這樣: ./e &開始執(zhí)行后,稍微等待一下然后再 ./e&, 這個(gè)時(shí)候屏幕信息會(huì)怎么樣呢?全局變量count會(huì)怎么變化? 會(huì)是兩個(gè)進(jìn)程交叉輸出信息,并且各自的count互不干擾,雖然他們引用了同一個(gè)so文件。 也就是說只有代碼是否線程安全一說,沒有代碼是否是進(jìn)程安全這一說法。
下面的還沒細(xì)看,汗
4.庫的初始化,解析: windows下的動(dòng)態(tài)庫加載,卸載都會(huì)有初始化函數(shù)以及卸載函數(shù)來完成庫的初始化以及資源回收,linux當(dāng)然也可以實(shí)現(xiàn)。 ELF文件本身執(zhí)行時(shí)就會(huì)執(zhí)行一個(gè)init()函數(shù)以及fini()函數(shù)來完成這個(gè),我們只要把自己的函數(shù)能讓系統(tǒng)在這個(gè)時(shí)候執(zhí)行 就可以了。 修改我們前面的s.c文件:
#include void my_init(void) __attribute__((constructor)); //告訴gcc把這個(gè)函數(shù)扔到init section void my_fini(void) __attribute__((destructor)); //告訴gcc把這個(gè)函數(shù)扔到fini section void out_msg(const char *m) { printf(" Ok!\n"); } int i; //仍然是個(gè)計(jì)數(shù)器 void my_init(void) { printf("Init ... ... %d\n", ++i); } void my_fini(void) { printf("Fini ... ... %d\n", ++i); }
重新制作 libs.so,ts本是不用重新編譯了,代碼維護(hù)升級(jí)方便很多。 然后執(zhí)行: ./e & 可以看到屏幕輸出:(不完整信息,只是順序一樣) Init Main OK Quit Fini 可以看到我們自己定義的初始化函數(shù)以及解析函數(shù)都被執(zhí)行了,而且是在最前面以及最后面。 如果s.c中的sleep(5)沒有注釋掉,那么有機(jī)會(huì): ./e& ./e&連續(xù)執(zhí)行兩次,那么初始化函數(shù)和解析函數(shù)也會(huì)執(zhí)行兩次,雖然系統(tǒng)只加載了一次libs.so。 如果sleep時(shí)候kill 掉后臺(tái)進(jìn)程,那么解析函數(shù)不會(huì)被執(zhí)行。
5.使用我們自己庫里的函數(shù)替換系統(tǒng)函數(shù): 創(chuàng)建一個(gè)新的文件b.c:我們要替換系統(tǒng)函數(shù)malloc以及free(可以自己寫個(gè)內(nèi)存泄露檢測(cè)工具了)
#include void* malloc(int size) { printf("My malloc\n"); return NULL; } void free(void* ad) { printf("My free\n"); }
老規(guī)矩,編譯鏈接成一個(gè)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
void out_msg() { int *p; p = (int*)malloc(100); free(p); printf("Stop Ok!\n"); }
修改腳本文件e:
export LD_PRELOAD=${pwd}libb.so:${LD_PRELOAD} export LD_LIBRARY_PATH=${pwd}:${LD_LIBRARY_PATH} ./ts
關(guān)鍵就在LD_PRELOAD上了,這個(gè)路徑指定的so將在所有的so之前加載,并且符號(hào)會(huì)覆蓋后面加載的so文件中的符號(hào)。如果可執(zhí)行文件的權(quán)限不合適(SID),這個(gè)變量會(huì)被忽略。 執(zhí)行:./e & 嗯,可以看到我們的malloc,free工作了。
到此,相信大家對(duì)“Linux系統(tǒng)so文件內(nèi)容有哪些”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。