Linux下控制動態庫匯出

2021-09-21 20:15:07 字數 2111 閱讀 4602

在linux中動態庫的確給程式帶來了良好的擴充性,並減少了記憶體的使用量,但這是有代價的。例如:

12

3

4

5

6

#include

intmain(intargc,char*ar**)

我們知道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;

}再在 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;

Linux下gcc編譯控制動態庫匯出函式小結

根據說明文件 how to write shared libraries 介紹,有四種方法 1.在方法宣告定義時,加修飾 attribute visibility hidden 2.gcc 在鏈結時設定 fvisibility hidden,則不加 visibility宣告的都預設為hidden g...

Linux下gcc編譯控制動態庫匯出函式小結

根據說明文件 how to write shared libraries 介紹,有四種方法 1.在方法宣告定義時,加修飾 attribute visibility hidden 就是說將不公開的函式都加上這個屬性,沒加的就是可見的 2.gcc 在鏈結時設定 fvisibility hidden,則不...

Linux下gcc編譯控制動態庫匯出函式小結

根據說明文件 how to write shared libraries 介紹,有四種方法 1.在方法宣告定義時,加修飾 attribute visibility hidden 就是說將不公開的函式都加上這個屬性,沒加的就是可見的 2.gcc 在鏈結時設定 fvisibility hidden,則不...