如何隱藏SDK中符號

一、 問題引入

在當下的開發中,應用的功能做的越來越複雜,工程也越來越大,所以為了儘可能縮短開發周期,不可避免的會用到許多第三方庫,隨之而來的也會遇到好多問題。比如,程序調用函數funafuna函數從在於兩個庫liba.a,libb.a中,並且程序執行需要連接這兩個庫,那麼程序執行時是調用liba.afuna還是調用的libb.a中的funa呢?

其實這個取決於鏈接時的順序,比如先鏈接的liba.a,這個時候通過liba.a的導出符號表就可以找到funaliba.a中定義,並加入符號表中;鏈接libb.a的時候發現符號表已經存在funa,就不會再次更新符號表,所以調用的始終是liba.a中的funa函數。

這裡的調用嚴重的依賴於鏈接庫載入的順序,很大程度上會導致混論。作為SDK的提供者,我們尤其要避免這點。

正常我們使用的庫中包含了好多符號信息,如圖1所示:

這些符號信息有以下幾個弊端:

1、增大了庫的體積;

2、隱蔽性較差;

3、容易帶來衝突。

在開發過程中第三點帶來的問題尤其嚴重,特別是當我們提供的SDK用到第三方庫的時候(因為使用我們SDK的客戶也有可能用到跟我們一樣的第三方庫)。

二、 解決辦法

1、對第三方庫處理

下面繼續以x264(下文以libx264.a帶過)為例說明如何編譯第三方的庫。

沒有隱藏符號的第三方庫如「圖1」所示,函數前面會帶有external的標示。在最終對外發布的SDK中_x264_predict_16x16_dc_c還是打著external的標籤,及對外可見。如圖2所示:

隱藏符號後,在libx264.a中,原先打上external標籤的函數,會以private external標識。如圖3所示:

那麼如何才能得到我們想要的、打上private external標籤的庫呢,有兩種方法可以做到。

1)對每個函數加屬性

__attribute__((visibility(「hidden」))) void funa_hidden()

{

printf(「hidden symbol
」);

}

void funa_visible()

{

printf(「exported symbol」);

}

這樣做的好處是可以根據需要對每個函數做定製處理。但若我們用到的三方庫代碼量大,這種方法就是費時費力了。

2)編譯庫時統一處理

利用gcc的擴展屬性,編譯庫時加上-fvisibility=hidden。

a) 靜態庫

gcc –static –o libtest.a –fvisibility=hidden –c test.c

b) 動態庫

gcc –dynamic –o libtest.so –fvisility=hidden –c test.c

其中dynamicclang的寫法,大部分gcc寫法為shared

上邊兩種方法只處理了c/c++,因為語法問題,彙編需要做特殊里,但也是在函數頭加屬性,但它的屬性寫法為.private_extern

.macro function name, export=0, align=2

.macro endfunc

ELF .size
ame, . -
ame

FUNC .endfunc

.purgem endfunc

.endm

.text

.align align

.if export

.global EXTERN_ASM
ame

.private_extern EXTERN_ASM
ame

ELF .type EXTERN_ASM
ame, %function

FUNC .func EXTERN_ASM
ame

EXTERN_ASM
ame:

.else

ELF .type
ame, %function

FUNC .func
ame


ame:

.endif

.endm

因為需要處理的彙編文件較少,所以對彙編採用了直接編輯源文件的方法。其實個人覺得也應該能在編譯時做統一處理,有興趣的可以自己找一下方法。

2、對xcode工程的處理

xcode工程處理相對直觀、簡單了許多。只需在工程的設置里做如下處理。

1) 打開工程設置,跳轉到build setting頁面;

2) 搜索hidden;

3) 將Symbols Hidden by Default設置Yes;

其實通過觀察編譯的過程可以發現,通過上述設置,蘋果最終將其轉化為步驟1的命令進行編譯。編譯的結果也是在庫里加了private external而已。

3、符號剝離

最後一步,也是最關鍵的一步,就是真正將步驟1或步驟2中打上private external標籤的函數做最終的處理,把它們從要發布的庫里剝離。

1) 首先設置prelink

targetbuild setting里搜索prelink,將Perform Single-Object Prelink置為Yes,然後把該工程需要的庫都直接拖到Prelink libraries中。如圖5所示:

2) 設置post process

Deployment Postprocessing置為Yes。如圖6所示:

3) 設置剝離方式

Strip Style設置為Non-Global Symbols。如圖7所示:

到目前為止,所有的設置都已經完成,接下來編譯。有興趣的同學可以觀察一下編譯的過程,會發現通過設置prelinkxcode會將庫里所有的目標文件根據你支持的architecture分類打包,如libxxx-armv7-master.o/libxxx-arm64-master.o,最後一步執行Strip命令將所有需要隱藏的符號剝離。

容聯技術乾貨推薦>>>

技術乾貨 | PushKit和CallKit實現——基於實時語音通話

技術乾貨 | HTML5之簡單的音視頻應用開發探尋

技術乾貨 | H.264 SVC技術介紹及應用分析

技術乾貨丨ELK日誌系統部署與優化

推薦閱讀:

張明雲的Live——安卓 SDK 開發實戰經驗分享
與 Xcode 相比,用 Adobe AIR/Flex做 iOS 開發有哪些優勢和局限?
無人機 SDK 平台開放後,有哪些 App 場景?
矽谷和國內的 iOS 開發到底有何不同?
手游第三方服務商興衰史:建立核心競爭壁壘方能始終

TAG:SDK | 軟體開發 | 人工智慧 |