作為一個嵌入式軟件攻城獅,提起庫首先會想到靜態庫和動態庫。靜態庫一般以.a為后綴,動態庫以.so為后綴(Win系統.DLL)。
而作為一個單片機軟件攻城獅,也會經常用到各種靜態庫,常見的C庫有stdio,stdlib,string,time等,第三方庫也有CMSIS_DSP_Library,mbedtls,60730等等。為什么要使用這些庫呢?個人認為可能有以下幾個原因:
系統解耦,可以減少軟件模塊之間的耦合,使軟件結構更清晰。
加速編譯,有些庫源碼有非常多的源文件,如果使用源碼編譯會大大增加編譯時間。
保護知識產權,限定產品的使用范圍。比如NXP提供的電機算法庫rtcesl當然希望它運行在自己品牌的MCU。
MCU從產品實用角度上看,也是有動態庫的需求,比如下面幾種場景:
有些產品形態要求MCU的固件分為安全域和非安全域,安全域的邏輯一旦經過認證就無法進行升級,而非安全域的邏輯可以通過bootloader進行遠程或本地的升級。比如新規電表,計量部分屬于安全域不可更新,而其他固件則可以進行更新
有些軟件/算法公司并不提供實際的硬件產品,和終端客戶的合作模式如果按件收費,除非每個產品必須聯網認證,就像我們所用的Windows系統激活,否則很難把控。比較好的做法是,將算法編譯成二進制燒入芯片中,向終端客戶提供芯片。
有些產品經常需要更新固件,受限于通訊速率,Flash大小的問題,希望可更新的固件越小越好。比如內置藍牙的MCU,其協議棧往往在100KB左右,如果通過源碼或者靜態庫的方式編譯,則升級的時候就必須將協議棧也一并升級,即使協議棧本身沒有任何修改,由于升級的固件比較大,所需要的更新時間也會非常長。如果通過動態庫的方式提供協議棧,就沒有這個問題。同時,如果客戶要求產品的固件能回退,則Flash必須能放兩份固件,如果應用代碼超過20K,則最終固件很容易超過128K(APP+BLE),如果使用靜態庫,則選型時必須使用超過256K的產品(APP+BLE)x2,而動態庫則可以使用256K以內的產品(APPx2+BLE)。用過Nordic藍牙MCU的應該都懂。
今天我們就專門研究下如何在MCU上實現動態庫的制作和加載。
制作動態庫
首先我們先回憶下如何制作靜態庫,第三方的或者自己寫的靜態庫,一般由三部分組成:
在MCU中制作的動態庫則需要如下幾部分內容:
至于具體如何實現,現在以之前介紹的開源PLC為例:
規劃內存,將MCU內部的Flash/RAM分出一部分留給庫,具體做法需要修改鏈接文件中的相關地址
定義函數指針列表結構體,用于提供給用戶程序調用:
初始化結構體,并實現函數原型:
修改鏈接文件,將函數指針列表放到固定地址
編譯并下載到MCU中
加載動態庫
生成動態庫后,用戶只需要知道函數指針列表的地址和結構體列表即可。使用過程如下:
在用戶工程中定義相同的結構體,并從固定地址中加載到
通過函數指針執行相應代碼即可
擴展知識
針對動態庫的應用場景2,簡單的賣芯片也只是防君子不防小人,因為終端客戶可以通過JTAG/SWD把動態庫讀出來,有些芯片雖然支持禁用JTAG/SWD使能ISP的方式下載,但用戶還是可以通過指針+地址的方式將庫從芯片中讀取出來,之后找芯片原廠克隆,針對這種攻擊,普通的MCU往往是無力應付的,大部分的軟件/算法公司是通過綁定加密芯片的方式來進行保護,但是除非加密芯片中有算法邏輯,否則這種保護也是徒勞的,因為不管是動態庫,還是靜態庫,攻擊者都可以通過反匯編看到關鍵的跳轉點,從而bypass驗證過程。
難道真的就沒有更好的防守么?目前知道有兩種方案:
NXP Kinetis系列產品在Flash中添加了FAC(Flash Access Control)功能,可以保證在可配置區域內只能被執行,而無法通過指針方式,DMA,JTAG/SWD,Ezport等接口獲取
ARM Cortex-M33內核以及支持了TrustZone,可以將動態庫放置在Secure區域,并設置NSC訪問接口,具體做法和FAC類似
審核編輯:郭婷
-
mcu
+關注
關注
146文章
16667瀏覽量
347805 -
嵌入式
+關注
關注
5046文章
18821瀏覽量
298586
發布評論請先 登錄
相關推薦
評論