痞子衡嵌入式:MCUXpresso IDE下工程連結檔案配置管理與自動生成機制

痞子衡發表於2021-09-08

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是MCUXpresso IDE下工程連結檔案配置管理與自動生成機制

  痞子衡在 2018 年初寫過一個專題 《嵌入式開發檔案系列》,用 8 篇文章系統地介紹了 ARM Cortex-M 核心微控制器開發過程中所要了解的主要檔案型別:原始檔、連結檔案、工程檔案、可重定向檔案、對映檔案、可執行檔案、反彙編檔案、映象檔案。

  上述 8 種檔案中,大家對原始檔、工程檔案以及映象檔案這三種應該是最熟悉的,而其餘檔案型別,很多人應該都沒有深入研究過,但痞子衡一直認為只有深入瞭解了連結檔案才算是真正步入嵌入式開發老手行列。

  我們知道不同 IDE 下連結檔案語法是不一樣的,而恩智浦 MCUXpresso IDE 底層編譯器是 Arm GCC,因此其連結檔案就是標準 GCC 下 .ld 檔案。如果你對 .ld 檔案語法非常精通,當然可以自己從頭開始寫連結檔案,如果不太熟的話,也不要緊張,MCUXpresso IDE 早就為你掃清了障礙,在這個 IDE 下能夠支援圖形介面裡做連結配置,然後自動生成相應連結檔案的。今天痞子衡就和大家聊聊這個特性:

一、準備開發環境

  首先需要準備好環境,包含必要的軟體,痞子衡的環境如下:

  • 整合開發環境: MCUXpresso IDE_11.4.0_6224,點此下載
  • 軟體開發包: SDK_2.10.0_EVK-MIMXRT1170(Toolchain需包含MCUXpresso IDE),點此下載

二、MCUXpresso IDE下連結檔案配置

  現在進入正題,我們先按照 《MCUXpresso IDE下SDK工程匯入與workspace管理機制》 一文步驟從 SDK 包裡匯入生成一個工程(就選最簡單的 hello_world 吧)。工程匯入成功後,會在 \MCUXpressoIDE_11.4.0_6224\workspace\evkmimxrt1170_hello_world_demo_cm7 下看到 .project 工程檔案,在 MCUXpresso IDE 下開啟這個工程。

2.1 Memory 空間定義

  在工程名上右擊選擇 Properties 進入選項配置介面,其中 MCU settings 一欄裡定義的就是 MCU 實際儲存空間,這是連結檔案的空間分配基礎,我們後面會將程式裡全部的段都連結在這些區域裡。

  儲存空間屬性(Type)分為兩類:一類是 Flash(存放 RO 段),一類是 RAM(存放 RW 段)。每個屬性的空間都可以被定義很多個,但其中僅 Alias 名為 Flash 和 RAM 的空間才是預設被選中用於連結程式段的(可通過上下移動按鈕將指定空間調整到前排 Flash 和 RAM 的位置)。

2.2 預設程式段分配

  還是在上一節開啟的 Properties 選項配置介面,其中 Settings / Managed Linker Script 頁面就是連結檔案裡具體程式段連結設定,這個頁面的最上面 Manage linker script 要保持勾選,勾選上則代表使用 IDE 的連結檔案自動生成功能。

  在一個具體應用程式專案工程裡,如果原始檔僅包含標準 C 和彙編程式碼,那麼程式段會被預設歸納為三大類:RO 段(函式程式碼,常量,全域性變數初值等),RW 段(全域性變數,重定向到 RAM 中函式程式碼等),Heap/Stack。IDE 裡分別提供了這三類程式段的空間指定:

1. Link application to RAM 勾選框:
    - 不勾選,則 RO 段放在 2.1 節圖中 Alias 名為 Flash 的空間裡
    - 勾選上,則 RO 段放在 2.1 節圖中 Alias 名為 RAM 的空間裡
2. Heap and Stack placement 配置框:
    - 可以按需調整 Heap/Stack 裡的 Region,Location,Size,其中 Region 可以是 2.1 節圖中屬性為 RAM 的任意空間
    - Heap/Stack 預設大小均為 4KB,放在 2.1 節圖中 Alias 名為 RAM 的空間裡
3. Global data placement 下拉框:
    - 可以按需連結 RW 段到 2.1 節圖中屬性為 RAM 的任意空間
    - RW 段預設放在 2.1 節圖中 Alias 名為 RAM 的空間裡

2.3 自定義程式段分配

  除了上一節連結器預設的程式段名外,我們也可以自定義一些使用者段名,方便一些特殊程式碼處理。這裡需要使用 __attribute__((section("UserSectionName"))) 連結器語法來修飾指定函式/變數,這樣該函式/變數就會被放在 UserSectionName 段裡,然後我們在上一節圖中連結設定框的最後 Extra linker script input sections 框裡單獨為自定義 UserSectionName 段指定連結空間。

  比如工程 clock_config.c 檔案裡如下函式 UpdateSemcClock(),這個函式在預設的 RO .text 段裡,RO 段都是連結在 Flash 裡的,但是我們希望將這個函式重定向到 ITCM 裡執行,所以我們可以使用 __attribute__((section("CodeQuickAccess"))) 連結器語法來修飾這個函式,然後在 Extra linker script input sections 框裡將 CodeQuickAccess 段放到 SRAM_ITC_cm7 空間裡即可。

#define AT_QUICKACCESS_SECTION_CODE(func) __attribute__((section("CodeQuickAccess"), __noinline__)) func
#define AT_QUICKACCESS_SECTION_DATA(func) __attribute__((section("DataQuickAccess"))) func

AT_QUICKACCESS_SECTION_CODE(void UpdateSemcClock(void));
void UpdateSemcClock(void)
{
    SEMC->IPCMD = 0xA55A000D;
    while ((SEMC->INTR & 0x3) == 0);
    SEMC->INTR                                = 0x3;
    SEMC->DCCR                                = 0x0B;
    CCM->CLOCK_ROOT[kCLOCK_Root_Semc].CONTROL = 0x602;
}

2.4 自動生成的連結檔案

  連結設定完成後,會在工程目錄 \MCUXpressoIDE_11.4.0_6224\workspace\evkmimxrt1170_hello_world_demo_cm7\Debug 下自動生成最終連結檔案(假定用得 debug build),檔案一共有三個,其中 evkmimxrt1170_hello_world_demo_cm7_Debug.ld 是主連結檔案,感興趣的可以開啟這個連結檔案學習一下(如果看不懂語法可以結合這篇文章 https://www.embedded.com/building-bare-metal-arm-systems-with-gnu-part-3/ )。

2.5 檢視Map檔案確認

  按照 2.1 節和 2.2 節 圖中的連結設定,我們編譯連結 evkmimxrt1170_hello_world_demo_cm7 工程可以得到如下連結結果,從空間佔用上來看是符合預期的。

  現在我們可以開啟生成的 evkmimxrt1170_hello_world_demo_cm7.map 檔案具體分析一下最終連結情況,痞子衡摘錄了最核心部分如下:

Memory Configuration
Name             Origin        Length             Attributes
/------------------------------------------------------------/
// RO .text 段在           BOARD_FLASH:0x30000000 - 0x30006eaf,共 28336 個位元組
// RO CodeQuickAccess 段在 BOARD_FLASH:0x30006eb0 - 0x30006ee7,共 56 個位元組
// RO .data_init 段在      BOARD_FLASH:0x30006ee8 - 0x30006eeb,共 4 個位元組
.boot_hdr       0x30000000     0x2000
.text           0x30002000     0x4eb0

// RW CodeQuickAccess 段在 SRAM_ITC_cm7:0x00000000 - 0x00000037,共 56 個位元組
.data_RAM4      0x00000000       0x38 load address 0x30006eb0
 CodeQuickAccess
                0x00000000       0x38 ./board/clock_config.o
                0x00000000                UpdateSemcClock

// RW .data 段在           BOARD_SDRAM:0x80000000 - 0x80000003,共 4 個位元組
.data           0x80000000        0x4 load address 0x30006ee8
 .data.SystemCoreClock
                0x80000000        0x4 ./device/system_MIMXRT1176_cm7.o

// RW .bss 段在            BOARD_SDRAM:0x80000004 - 0x80000107,共 260 個位元組
.bss            0x80000004      0x104

// Heap 在                 BOARD_SDRAM:0x80000108 - 0x80001107,共 4KB
.heap           0x80000108     0x1000

// Stack 在                BOARD_SDRAM:0x82fff000 - 0x82ffffff,共 4KB
.stack          0x82fff000        0x0
                0x82fff000                _vStackBase = .
                0x82fff000                . = ALIGN (0x4)
                0x83000000                _vStackTop = (. + _StackSize)

  簡單總結下,RO 段一般從 Flash 的最前面開始連結的,.text 段在最前面,然後是 ramfunc 函式實體,最後是 .data_init 段(全域性變數初值)。RW 段也是從 RAM 的最前面開始連結,.data 段在前,.bss 在後,然後是 Heap 和 Stack(Heap/Stack的具體位置是可以設定的,有 Start、End、Post Data 三種選擇)。

三、MCUXpresso IDE下連結小實驗

  根據上面的知識,我們現在來做些連結設定小實驗,在做實驗前,我們調整下 Memory 定義,把 SDRAM 相關空間移到後面去,預設 RAM 用 SRAM_DTC_cm7 空間,這樣看起來習慣一點。

3.1 預設 XiP 連結

  調整過 Memory 空間順序後的連結結果如下:

3.2 Non-XiP 連結

  現在我們嘗試使能 Link application to RAM 選項,其餘不變,此時可以看到 28396 Bytes 的 RO 段也到了 SRAM_DTC_cm7 空間裡,BOARD_FLASH 空間完全沒有任何佔用:

3.3 XiP 連結,調整 Stack 大小並放置到 OCRAM1

  我們嘗試調整 Stack 大小到 1KB 並放置到 SRAM_OC1,其餘不變,此時可以看到 SRAM_DTC_cm7 空間消耗相比 3.1 節裡少了 4KB,但 SRAM_OC1 空間消耗多了 1KB:

3.4 XiP 連結,調整 RW 段到 OCRAM2

  我們嘗試調整 RW 段到 SRAM_OC2,其餘不變,此時可以看到 SRAM_DTC_cm7 空間消耗相比 3.1 節裡少了 264 Bytes,但 SRAM_OC2 空間消耗多了 264 Bytes:

  至此,MCUXpresso IDE下工程連結檔案配置管理與自動生成機制痞子衡便介紹完畢了,掌聲在哪裡~~~

歡迎訂閱

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

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

相關文章