1. 程式人生 > >動態連結庫so檔案中的函式名隱藏

動態連結庫so檔案中的函式名隱藏

     在我們提供給別人使用的動態連結庫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
這樣可以在函式前新增相應的屬性,DLL_API或DLL_LOCAL