大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家分享的是在 IAR 開(kāi)發(fā)環(huán)境下為工程開(kāi)啟 CRC 完整性校驗(yàn)功能的方法。
CRC 校驗(yàn)在嵌入式領(lǐng)域里的應(yīng)用非常廣,比如在通信領(lǐng)域,CRC 檢驗(yàn)值可以作為數(shù)據(jù)包的一部分,用于檢查一包數(shù)據(jù)傳輸過(guò)程中是否發(fā)生了比特錯(cuò)誤,如果 CRC 校驗(yàn)失敗,那么接收方可以通知發(fā)送方要求該包數(shù)據(jù)重新傳輸,這樣能大大增加數(shù)據(jù)傳輸?shù)目煽啃?。同時(shí) CRC 在應(yīng)用程序完整性驗(yàn)證方面也有廣泛應(yīng)用,相比和檢驗(yàn),CRC 校驗(yàn)糾錯(cuò)能力更強(qiáng);相比簽名校驗(yàn),CRC 校驗(yàn)在速度方面又占優(yōu)勢(shì),因此它是一個(gè)各方面比較均衡的完整性驗(yàn)證手段。
IAR 是個(gè)非常老牌的嵌入式開(kāi)發(fā)集成環(huán)境,它的功能非常強(qiáng)大,有很多寶藏功能值得我們?nèi)グl(fā)掘。痞子衡自畢業(yè)之后就一直在使用 IAR,算是一路看著它從古典畫(huà)風(fēng)的 v6.50.x 升級(jí)到現(xiàn)在潮流的 v8.50.x,對(duì)于經(jīng)典的 CRC 校驗(yàn)功能的支持,IAR 當(dāng)然不會(huì)放過(guò),今天痞子衡就來(lái)介紹 IAR 下如何使用其自帶的 CRC 校驗(yàn)功能。
?
一、ielftool 命令行工具
IAR 安裝目錄下有非常多的命令行小工具,這些小工具其實(shí)就是 IAR 的核心,集成開(kāi)發(fā)環(huán)境界面只是提供人機(jī)交互,其背后的很多功能都是通過(guò)調(diào)用這些命令行小工具來(lái)實(shí)現(xiàn)的。其中用于實(shí)現(xiàn) CRC 校驗(yàn)的功能就包含在 ielftool.exe 工具里:
ielftool.exe 工具跟 CRC 相關(guān)的一共兩個(gè)參數(shù)選項(xiàng),一是 --fill 用于填充,二是 --checksum 用于設(shè)置算法,具體參數(shù)使用細(xì)節(jié)詳見(jiàn) IAR SystemsEmbedded Workbench 8.50.6armdocEWARM_DevelopmentGuide.ENU 手冊(cè)里的 Checksum calculation for verifying image integrity 小節(jié)。
此處痞子衡僅舉一個(gè)簡(jiǎn)單例子,如下命令表示在源可執(zhí)行文件 sourceFile.out 中計(jì)算范圍 __checksum_begin - __checksum_end 之間的 CRC 結(jié)果,最終校驗(yàn)值 __checksum 長(zhǎng)度為 4 字節(jié)、固定 CRC32 算法、計(jì)算單元為 1 字節(jié)、指定 CRC 初始值為 0xffffffff,其余設(shè)置默認(rèn),并將結(jié)果放在目標(biāo)可執(zhí)行文件 destinationFile.out 中。
ielftool --fill="0xFF;__checksum_begin–__checksum_end"
--checksum="__checksum:4,crc32:p,0xffffffff;__checksum_begin-__checksum_end"
sourceFile.out
destinationFile.out
從上面的命令你應(yīng)該能知道,sourceFile.out 并不是任意可執(zhí)行文件都行的,其必須包含必要的 __checksum_begin、__checksum_end、__checksum 的定義。假設(shè)我們代碼中并沒(méi)有實(shí)際使用 CRC,那么我們需要在生成 sourceFile.out 文件的 IAR 工程選項(xiàng)里做如下設(shè)置:
注意:__checksum_begin、__checksum_end 符號(hào)、__checksum 變量、.checksum 段四個(gè)名字,用戶都可以自定義的,這里命名成這樣主要是為了和 IAR 默認(rèn)定義相統(tǒng)一。
讓我們隨便找一個(gè)嵌入式 IAR 工程按上面設(shè)置生成源 hello_world.out 文件,并使用 ielftool 工具執(zhí)行一次命令看看,可以看到產(chǎn)生了 __checksum 值,新生成的 hello_world_1.out 文件里包含了正確的 CRC 校驗(yàn)結(jié)果。
?
二、為工程添加 CRC 校驗(yàn)
IAR 界面里有兩種使用 ielftool 來(lái)生成 CRC 校驗(yàn)值的方法,痞子衡一一介紹:
?
2.1 利用 Checksum 功能
第一種是直接在 IDE 界面里配置,我們隨便打開(kāi)一個(gè)嵌入式工程,比如 SDK_2.8.2_FRDM-K64Fboardsfrdmk64fdemo_appshello_worldiar,在工程選項(xiàng) Linker/Checksum 下面,勾選 Fill unused code memory 和 Generate checksum 便使能了 CRC 校驗(yàn),藍(lán)色框里的兩個(gè)地址用于設(shè)置 CRC 計(jì)算范圍,綠框里的參數(shù)用于設(shè)置 CRC 算法細(xì)節(jié),具體每個(gè)配置什么意義可以查看 IAR SystemsEmbedded Workbench 8.50.6armdocEWARM_DevelopmentGuide.ENU 手冊(cè)里的 Checksum 一節(jié),痞子衡在這里不予展開(kāi)。
下圖示例配置中有兩點(diǎn)要說(shuō)明:一、算法選擇了 CRC32,其多項(xiàng)式系數(shù)其實(shí)固定為 0x04C11BD7;如果想自定義 CRC32 多項(xiàng)式系數(shù)值,可選 CRC polynomial;二、因?yàn)榈刂吩O(shè)置的是 0x0 - 0x400,一共 1025 個(gè)字節(jié)(包含 0x400),所以 checksum unit size 此處僅能選 8-bit,因?yàn)?IDE 強(qiáng)制要求地址對(duì)齊。
設(shè)置好之后重新編譯工程,此時(shí)會(huì)報(bào)錯(cuò)“ielftool error: The string '__checksum' was not found in the string table ”,因?yàn)樵诔绦虼a里,我們完全沒(méi)有任何 CRC 相關(guān)的引用,IAR 會(huì)忽略界面里使能的 CRC 功能,所以我們還需要將 __checksum 強(qiáng)行加入如下選項(xiàng)里(注意 __checksum 是 IAR 里默認(rèn)定義的 CRC 檢驗(yàn)值符號(hào)名)。
這時(shí)候再編譯工程就可以在生成的 .out 和 .map 文件里看到 CRC 信息了,__checksum 被鏈接器隨機(jī)放在了 0x2844 的位置,__checksum_begin 和 __checksum_end 是 IAR 默認(rèn)記錄 CRC 計(jì)算范圍的符號(hào)變量名。
如果你想自己決定 __checksum 的鏈接位置,你可以在工程鏈接文件里添加放置 section .checksum,這個(gè)段便對(duì)應(yīng)著 __checksum。比如我們?cè)囍鴮⑦@個(gè)段放在 0x1000 的位置:
再一次編譯工程,查看 map 文件,這次 __checksum 被放在了我們指定的 0x1000 的位置。
?
2.2 利用 Post-build 功能
第二種方式是利用 IDE 里的 Post-build 功能,在第一節(jié)的基礎(chǔ)上,在工程選項(xiàng) Linker/Extra Options 里把 ielftool 命令加進(jìn)去,這樣在編譯工程的時(shí)候,IAR 會(huì)自動(dòng)跑這個(gè)命令:
$TOOLKIT_DIR$binielftool --fill="0xFF;__checksum_begin-__checksum_end" --checksum="__checksum:4,crc32:p,0xffffffff;__checksum_begin-__checksum_end" --verbose "$TARGET_PATH$" "$TARGET_PATH$"
上述命令與第一節(jié)中命令基本一致,只是用"" ""替代了 sourceFile.out destinationFile.out,并且加了 --verbose 顯示執(zhí)行操作信息:
?
三、在工程中驗(yàn)證 CRC 校驗(yàn)
IAR 生成的 CRC 校驗(yàn)值在應(yīng)用程序里的使用就比較簡(jiǎn)單了,見(jiàn)如下代碼,其中 calc_crc()函數(shù)需與我們之前在 IAR 配置的 CRC 算法參數(shù)相一致,此外代碼中的數(shù)據(jù)類型也是與具體 CRC 配置有關(guān)的。
另外還有兩個(gè)注意點(diǎn):一、CRC 計(jì)算范圍不應(yīng)包含 __checksum 存放位置;二、CRC 計(jì)算范圍如果沒(méi)有按照算法對(duì)齊要求,那么實(shí)際計(jì)算時(shí)要相應(yīng)補(bǔ)上 0(使用 IDE 配置生成是強(qiáng)制對(duì)齊的,但是使用命令行沒(méi)有強(qiáng)制對(duì)齊)。
extern?uint32_t?const?__checksum;
extern?int32_t?__checksum_begin;
extern?int32_t?__checksum_end;
void?TestChecksum()
{
????uint32_t?calc?=?0;
????//?根據(jù) CRC 計(jì)算范圍重算新 CRC 校驗(yàn)值
????calc?=?calc_crc(0xFFFFFFFF,
????????????????????(uint8_t?*)?&__checksum_begin,
????????????????????((uint8_t?*)?&__checksum_end?-?((uint8_t?*)?&__checksum_begin)?+?1));
????//?比對(duì)新 CRC 校驗(yàn)值與 IAR 生成的 CRC 校驗(yàn)值
????if?(calc?!=?__checksum)
????{
????????printf("Incorrect?checksum!n");
????}
}
至此,在 IAR 開(kāi)發(fā)環(huán)境下為工程開(kāi)啟 CRC 完整性校驗(yàn)功能的方法痞子衡便介紹完畢了,掌聲在哪里~~~