簡體   English   中英

限制Linux靜態庫中的符號

[英]Restricting symbols in a Linux static library

我正在尋找限制導出到Linux靜態庫(存檔)的C符號數量的方法。 我想將這些僅限於那些屬於該庫官方API的符號。 我已經使用'static'將大多數函數聲明為static,但是這會將它們限制為文件范圍。 我正在尋找一種限制圖書館范圍的方法。

我可以使用Ulrich Drepper的“ 如何編寫共享庫”中的技術為共享庫執行此操作,但我無法將這些技術應用於靜態存檔。 在他早期的圖書館設計良好實踐論文中,他寫道:

唯一的可能性是使用'ld -r'將需要某些內部資源的所有目標文件合並為一個,然后限制由此組合目標文件導出的符號。 GNU鏈接器可以選擇執行此操作。

誰能幫助我發現這些選項可能是什么? 我在'strip -w -K prefix_ *'上取得了一些成功,但這感覺很野蠻。 理想情況下,我想要一個適用於GCC 3和4的解決方案。

謝謝!

對於使用GCC 3.x或4.x編譯的代碼,靜態庫無法執行您想要的操作。

如果您可以使用共享對象(庫),GNU鏈接器將通過稱為版本腳本的功能來執行您所需的操作。 這通常用於提供特定於版本的入口點,但是退化情況只是區分公共和私有符號而沒有任何版本控制。 使用ld的--version-script =命令行選項指定版本腳本。

版本腳本的內容使得入口指向foo和bar為public並隱藏所有其他接口:

{ global: foo; bar; local: *; };

請參閱ld doc: http//sourceware.org/binutils/docs/ld/VERSION.html#VERSION

我是共享庫的主要倡導者,這種限制全局變量可見性的能力是他們的偉大優點之一。

提供共享對象的更多優點但是為Solaris編寫的文檔(由Greg Nakhimovsky撰寫的快樂記憶)位於http://developers.sun.com/solaris/articles/linker_mapfiles.html

我希望這有幫助。

我不相信GNU ld有任何這樣的選擇; Ulrich必須具有objcopy ,它有許多這樣的選項: - --localize-hidden , - --localize-symbol=symbolname , - --localize-symbols=filename

--localize-hidden特別允許人們對暴露的符號進行非常精細的控制。 考慮:

int foo() { return 42; }
int __attribute__((visibility("hidden"))) bar() { return 24; }

gcc -c foo.c
nm foo.o
000000000000000b T bar
0000000000000000 T foo

objcopy --localize-hidden foo.o bar.o
nm bar.o
000000000000000b t bar
0000000000000000 T foo

因此bar()不再從對象中導出(即使它仍然存在並可用於調試)。 您也可以使用objcopy --strip-unneeded刪除bar()

這個答案的優點將取決於您使用靜態庫的原因。 如果允許鏈接器稍后刪除未使用的對象,那么我幾乎無法添加。 如果它是為了組織的目的 - 最小化必須傳遞給鏈接應用程序的對象的數量 - 這種對Employed Russian的答案的擴展可能是有用的。

在編譯時,可以使用以下命令設置編譯單元中所有符號的可見性:

-fvisibility=hidden
-fvisibility=default

這意味着可以編譯具有默認可見性的單個文件“interface.c”和具有隱藏可見性的大量實現文件,而無需注釋源。 然后,可重定位鏈接將生成單個目標文件,其中非api函數被“隱藏”:

ld -r interface.o implementation0.o implementation1.o -o relocatable.o

現在可以對組合的目標文件進行objcopy:

objcopy --localize-hidden relocatable.o mylibrary.o

因此,我們有一個目標文件“library”或“module”,它只公開預期的API。


上述策略與鏈接時間優化適度地相互作用。 使用-flto編譯並通過編譯器將-r傳遞給鏈接器來執行可重定位鏈接:

gcc -fuse-linker-plugin -flto -nostdlib -Wl,-r {objects} -o relocatable.o

使用objcopy像以前一樣本地化隱藏的符號,然后最后一次調用鏈接器來剝離本地符號以及它可以在post-lto對象中找到的任何其他死代碼。 遺憾的是,relocatable.o不太可能保留任何與lto相關的信息:

gcc -nostdlib -Wl,-r,--discard-all relocatable.o mylibrary.o

lto的當前實現在可重定位鏈接階段期間似乎是活動的。 使用lto,隱藏的=>本地符號被最終的可重定位鏈接剝離。 沒有lto,hidden => local符號在最終的可重定位鏈接中幸存下來。

lto的未來實現似乎可能通過可重定位鏈接階段保留所需的元數據,但是目前可重定位鏈接的結果似乎是一個普通的舊目標文件。

這是對EmployedRussian和JonChesterfield的答案的改進,如果您同時生成動態和靜態庫,這可能會有所幫助。

從標准機制開始,用於在DSO中隱藏符號(lib的動態版本)。 使用-fvisibility=hidden編譯所有文件。 在定義API的頭文件中,更改要公開的類和函數的聲明:

   #define DLL_PUBLIC __attribute__ ((visibility ("default")))
   extern DLL_PUBLIC int my_api_func(int);

詳情請見此處 這適用於C和C ++。 這對於DSO來說已足夠,但您需要為靜態庫添加以下構建步驟:

ld -r obj1.o obj2.o ... objn.o -o static1.o
objcopy --localize-hidden static1.o static2.o
ar -rcs mylib.a static2.o

ar步驟是可選的 - 您只需鏈接static2.o

我這樣做的方法是使用INTERNAL標記不要導出的所有內容,包括保護所有.h文件,使用-DINTERNAL =編譯dev版本,並使用包含所有其他庫.c文件的單個.c文件編譯發布版本with -DINTERNAL = static。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM