痞子衡嵌入式:在IAR開發環境下為工程開啟CRC完整性校驗功能的方法

痞子衡發表於2020-11-26

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是在IAR開發環境下為工程開啟CRC完整性校驗功能的方法

  CRC校驗在嵌入式領域裡的應用非常廣,比如在通訊領域,CRC檢驗值可以作為資料包的一部分,用於檢查一包資料傳輸過程中是否發生了位元錯誤,如果CRC校驗失敗,那麼接收方可以通知傳送方要求該包資料重新傳輸,這樣能大大增加資料傳輸的可靠性。同時CRC在應用程式完整性驗證方面也有廣泛應用,相比和檢驗,CRC校驗糾錯能力更強;相比簽名校驗,CRC校驗在速度方面又佔優勢,因此它是一個各方面比較均衡的完整性驗證手段。

  IAR是個非常老牌的嵌入式開發整合環境,它的功能非常強大,有很多寶藏功能值得我們去發掘。痞子衡自畢業之後就一直在使用IAR,算是一路看著它從古典畫風的v6.50.x升級到現在潮流的v8.50.x,對於經典的CRC校驗功能的支援,IAR當然不會放過,今天痞子衡就來介紹IAR下如何使用其自帶的CRC校驗功能。

一、ielftool命令列工具

  IAR安裝目錄下有非常多的命令列小工具,這些小工具其實就是IAR的核心,整合開發環境介面只是提供人機互動,其背後的很多功能都是通過呼叫這些命令列小工具來實現的。其中用於實現CRC校驗的功能就包含在ielftool.exe工具裡:

  ielftool.exe工具跟CRC相關的一共兩個引數選項,一是--fill用於填充,二是--checksum用於設定演算法,具體引數使用細節詳見 \IAR Systems\Embedded Workbench 8.50.6\arm\doc\EWARM_DevelopmentGuide.ENU手冊裡的Checksum calculation for verifying image integrity小節。

  此處痞子衡僅舉一個簡單例子,如下命令表示在源可執行檔案sourceFile.out中計算範圍__checksum_begin - __checksum_end之間的CRC結果,最終校驗值__checksum長度為4位元組、固定CRC32演算法、計算單元為1位元組、指定CRC初始值為0xffffffff,其餘設定預設,並將結果放在目標可執行檔案destinationFile.out中。

ielftool --fill="0xFF;__checksum_begin–__checksum_end"
         --checksum="__checksum:4,crc32:p,0xffffffff;__checksum_begin-__checksum_end"
         sourceFile.out
         destinationFile.out

  從上面的命令你應該能知道,sourceFile.out並不是任意可執行檔案都行的,其必須包含必要的__checksum_begin、__checksum_end、__checksum的定義。假設我們程式碼中並沒有實際使用CRC,那麼我們需要在生成sourceFile.out檔案的IAR工程選項裡做如下設定:

注意:__checksum_begin、__checksum_end符號、__checksum變數、.checksum段四個名字,使用者都可以自定義的,這裡命名成這樣主要是為了和IAR預設定義相統一。

  讓我們隨便找一個嵌入式IAR工程按上面設定生成源hello_world.out檔案,並使用ielftool工具執行一次命令看看,可以看到產生了__checksum值,新生成的hello_world_1.out檔案裡包含了正確的CRC校驗結果。

二、為工程新增CRC校驗

  IAR介面裡有兩種使用ielftool來生成CRC校驗值的方法,痞子衡一一介紹:

2.1 利用Checksum功能

  第一種是直接在IDE介面裡配置,我們隨便開啟一個嵌入式工程,比如 \SDK_2.8.2_FRDM-K64F\boards\frdmk64f\demo_apps\hello_world\iar\,在工程選項Linker/Checksum下面,勾選Fill unused code memory和Generate checksum便使能了CRC校驗,藍色框裡的兩個地址用於設定CRC計算範圍,綠框裡的引數用於設定CRC演算法細節,具體每個配置什麼意義可以檢視 \IAR Systems\Embedded Workbench 8.50.6\arm\doc\EWARM_DevelopmentGuide.ENU手冊裡的Checksum一節,痞子衡在這裡不予展開。

  下圖示例配置中有兩點要說明:一、演算法選擇了CRC32,其多項式係數其實固定為0x04C11BD7;如果想自定義CRC32多項式係數值,可選CRC polynomial;二、因為地址設定的是 0x0 - 0x400,一共1025個位元組(包含0x400),所以checksum unit size此處僅能選8-bit,因為IDE強制要求地址對齊。

  設定好之後重新編譯工程,此時會報錯“ielftool error: The string '__checksum' was not found in the string table ”,因為在程式程式碼裡,我們完全沒有任何CRC相關的引用,IAR會忽略介面裡使能的CRC功能,所以我們還需要將__checksum強行加入如下選項裡(注意__checksum是IAR裡預設定義的CRC檢驗值符號名)。

  這時候再編譯工程就可以在生成的.out和.map檔案裡看到CRC資訊了,__checksum被連結器隨機放在了0x2844的位置,__checksum_begin和__checksum_end是IAR預設記錄CRC計算範圍的符號變數名。

  如果你想自己決定__checksum的連結位置,你可以在工程連結檔案裡新增放置 section .checksum,這個段便對應著__checksum。比如我們試著將這個段放在0x1000的位置:

  再一次編譯工程,檢視map檔案,這次__checksum被放在了我們指定的0x1000的位置。

2.2 利用Post-build功能

  第二種方式是利用IDE裡的Post-build功能,在第一節的基礎上,在工程選項Linker/Extra Options裡把ielftool命令加進去,這樣在編譯工程的時候,IAR會自動跑這個命令:

$TOOLKIT_DIR$\bin\ielftool --fill="0xFF;__checksum_begin-__checksum_end" --checksum="__checksum:4,crc32:p,0xffffffff;__checksum_begin-__checksum_end" --verbose "$TARGET_PATH$" "$TARGET_PATH$"

  上述命令與第一節中命令基本一致,只是用"$TARGET_PATH$" "$TARGET_PATH$"替代了sourceFile.out destinationFile.out,並且加了--verbose顯示執行操作資訊:

三、在工程中驗證CRC校驗

  IAR生成的CRC校驗值在應用程式裡的使用就比較簡單了,見如下程式碼,其中calc_crc()函式需與我們之前在IAR配置的CRC演算法引數相一致,此外程式碼中的資料型別也是與具體CRC配置有關的。

  另外還有兩個注意點:一、CRC計算範圍不應包含__checksum存放位置;二、CRC計算範圍如果沒有按照演算法對齊要求,那麼實際計算時要相應補上0(使用IDE配置生成是強制對齊的,但是使用命令列沒有強制對齊)。

extern uint32_t const __checksum;
extern int32_t __checksum_begin;
extern int32_t __checksum_end;

void TestChecksum()
{
    uint32_t calc = 0;

    // 根據CRC計算範圍重算新CRC校驗值
    calc = calc_crc(0xFFFFFFFF,
                    (uint8_t *) &__checksum_begin,
                    ((uint8_t *) &__checksum_end - ((uint8_t *) &__checksum_begin) + 1));

    // 比對新CRC校驗值與IAR生成的CRC校驗值
    if (calc != __checksum)
    {
        printf("Incorrect checksum!\n");
    }
}

  至此,在IAR開發環境下為工程開啟CRC完整性校驗功能的方法痞子衡便介紹完畢了,掌聲在哪裡~~~

歡迎訂閱

文章會同時釋出到我的 部落格園主頁CSDN主頁知乎主頁微信公眾號 平臺上。

微信搜尋"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。

相關文章