在Linux中動态庫的确給程式帶來了良好的擴充性,并減少了記憶體的使用量,但這是有代價的。例如:
1
2
3
4
5
6
<code>#include <stdio.h></code>
<code>int</code> <code>main(</code><code>int</code> <code>argc, </code><code>char</code> <code>*argv[])</code>
<code>{</code>
<code> </code><code>printf</code><code>(“hello\n”);</code>
<code> </code><code>return</code> <code>0;</code>
<code>}</code>
我們知道printf是在glibc中定義的,如果不适用動态庫,而是将glibc靜态連結到程序中的話,那麼printf函數的位址在編譯時就是已知的了,使用很簡單的依據位址轉移,就可以進行函數調用。
可是如果采用動态庫的話,在程式編譯階段,編譯器就無法得知printf的函數位址,因為動态庫加載的記憶體位址時随機的。那麼對于動态庫的情況,針對printf是如何尋址的呢?
在程式運作時,當調用printf的時候,程式會将處理權交給linker,由其負責在執行檔案以及其連接配接的動态庫中查找printf的函數位址。由于linker不知道printf具體是在哪個動态庫,是以它将在整個執行檔案和動态庫的範圍内查找。更糟糕的是在C++程式中,符号的命名是類名+函數名,這導緻在做字元串比較時,往往直到字元串的結尾才能獲得結果。
這也就導緻了在程序啟動過程中,符号查找占據了一大部分時間。在Linux的KDE程序啟動中,符号查找甚至占據了程序啟動80%的時間。
是以就針對上述的情況,有以下優化解決方案:
1、減少導出符号的數量
在動态庫編譯和生成時,預設所有的函數和全局變量都是導出的。而實際上有很多函數隻是動态庫内部使用,通過去掉那些動态庫中不必要的導出符号,進而減少動态庫在做連結時所查找的符号數量,可以加快動态庫連結的速度。
可以使用ld的ld --retain-symbols-file --version-script兩個選項實作。寫一個導出符号檔案,如 symbol 指定你隻導出的函數,如 func1。使用 ld 的--retain-symbols-file 參數可以在 static section 裡取消 func1 以外的所有函數。這時你用 readelf 看編譯好後的 .so 檔案 static section 裡沒有了,使用 nm 看 .so檔案它無法查出導出函數。但這并不完全。因為在 dynamic section 裡還是會看到所有符号被導出。如果想在 dynsym section 裡也不讓他導出的話,需要再編寫一個 script 檔案,指定 global 與 local 在 global 中指定你要導出的函數,簡單的格式如下:
VERSION{
VER_1.0{
global: 導出函數名;
local: *;
};
}
再在 ld 時用 --version-script 選項來 load 你的檔案。都完事後再使用 readelf 觀察static 與 dynamic section 發現隻導出了你指定的函數名即符号。
例:
ld -shared --retain-symbols-file 符号檔案 --version-script 腳本檔案 -o 動态庫檔案。so filename
2、減少符号的長度
3、使用prelink
在這裡另外在提一個問題,很有趣的東西。
gcc -fvisibility=hidden 隻在連結時傳入的.c檔案起作用,對.o檔案不其作用;
比如test.c test1.c,使用以下指令:
gcc -shared -fvisibility=hidden -otest.so test.c test1.c
和指令
gcc -c test.c test1.c
gcc -shared -fvisibility=hidden -otest.so test.o test1.o
生成的test.so中的對應可見性是不一樣的,使用“readelf -s test.so”檢視發現:
第一個達到預期目的,即将兩個.c檔案中的functions設為HIDDEN,
而第2個則不行,-fvisibility=hidden不起作用;
再用gcc -shared -fvisibility=hidden -o test.so test.o test1.c
生成的so,則可發現test1.c中的函數為HIDDEN,但test.o中的函數仍為DEFAULT;
本文轉自 驿落黃昏 51CTO部落格,原文連結:http://blog.51cto.com/yiluohuanghun/1198295,如需轉載請自行聯系原作者