編譯.so動態庫隱藏函式名
阿新 • • 發佈:2019-02-11
在我們提供給別人使用的動態連結庫so檔案時,其內部實現函式的名稱,特別是一些關鍵名稱我們是不希望別人見到然後反向的,這時候一般有兩種處理方式:一是把程式中關鍵詞修改了再編譯,比較蠢笨;二是通過編譯的方式將字符隱藏,gcc編譯器提供了這個選項,即在編譯選項中加入-fvisibility=hidden選項。
比如ndk裡這樣操作:LOCAL_CPPFLAGS +=-fvisibility=hidden。執行編譯後,使用nm -D xxx.so命令或者readelf --symbols xxx.so即可檢視so檔案中符號列表,此時所有符號已經隱藏了,好像似乎目的達到了,但是引用此so檔案時發現根本執行不起來,那麼問題出哪兒了?
其實,根據動態連結庫呼叫原理可知,程式在顯示或隱示呼叫so檔案時,跟靜態庫一樣是需要使用確定名稱的函數的,而執行-fvisibility=hidden編譯後,所有函式名稱都被隱藏了,這時候程式當然執行不起來了。
那麼正確的思路應該是暴露出要被呼叫的函式名稱,而隱藏不被外部使用的其他符號即可,具體操作為:
在需要暴露(匯出)的函式前增加屬性__attribute__ ((visibility("default"))),例如,
- __attribute__ ((visibility("default")))
- void hello(void)
- {
- }
這樣就把函式hello匯出來了,而其他沒有新增該屬性的,就被-fvisibility=hidden給隱藏了,到此我們的目標就實現了。
當然,為了方便使用,可以把該選項用巨集定義,寫函式的時候就可以使用,比如:
- #ifdef WIN32
- # ifdef EXPORT
- ...
- # else
- ....
- # endif
- # define DLL_LOCAL
- #else
- # ifdef __GNU__
- # if (GCC_SUPPORTS_VISABLE == 1) /*defined by configure*/
- # ifdef EXPORT
- # define DLL_API __attribute__ ((visibility("default")))
- # else
- # define DLL_API __attribute__ ((visibility("default")))
- # endif
- # define DLL_LOCAL __attribute__ ((visibility("hidden")))
- # else
- # define DLL_API
- # define DLL_LOCAL
- # endif
- # endif
- #endif