系統(tǒng)地介紹了 ARM Cortex-M 內(nèi)核微控制器開發(fā)過(guò)程中所要了解的主要文件類型:源文件、鏈接文件、工程文件、可重定向文件、映射文件、可執(zhí)行文件、反匯編文件、鏡像文件。
上述 8 種文件中,大家對(duì)源文件、工程文件以及鏡像文件這三種應(yīng)該是最熟悉的,而其余文件類型,很多人應(yīng)該都沒(méi)有深入研究過(guò),但痞子衡一直認(rèn)為只有深入了解了鏈接文件才算是真正步入嵌入式開發(fā)老手行列。
我們知道不同 IDE 下鏈接文件語(yǔ)法是不一樣的,而恩智浦 MCUXpresso IDE 底層編譯器是 Arm GCC,因此其鏈接文件就是標(biāo)準(zhǔn) GCC 下 .ld 文件。如果你對(duì) .ld 文件語(yǔ)法非常精通,當(dāng)然可以自己從頭開始寫鏈接文件,如果不太熟的話,也不要緊張,MCUXpresso IDE 早就為你掃清了障礙,在這個(gè) IDE 下能夠支持圖形界面里做鏈接配置,然后自動(dòng)生成相應(yīng)鏈接文件的。今天痞子衡就和大家聊聊這個(gè)特性:
一、準(zhǔn)備開發(fā)環(huán)境
首先需要準(zhǔn)備好環(huán)境,包含必要的軟件,痞子衡的環(huán)境如下:
集成開發(fā)環(huán)境:MCUXpresso IDE_11.4.0_6224,點(diǎn)此下載
軟件開發(fā)包:SDK_2.10.0_EVK-MIMXRT1170(Toolchain需包含MCUXpresso IDE),點(diǎn)此下載
二、MCUXpresso IDE下鏈接文件配置
現(xiàn)在進(jìn)入正題,我們先從 SDK 包里導(dǎo)入生成一個(gè)工程(就選最簡(jiǎn)單的 hello_world 吧)。工程導(dǎo)入成功后,會(huì)在 \\MCUXpressoIDE_11.4.0_6224\\workspace\\evkmimxrt1170_hello_world_demo_cm7 下看到 .project 工程文件,在 MCUXpresso IDE 下打開這個(gè)工程。
2.1 Memory 空間定義
在工程名上右擊選擇 Properties 進(jìn)入選項(xiàng)配置界面,其中 MCU settings 一欄里定義的就是 MCU 實(shí)際存儲(chǔ)空間,這是鏈接文件的空間分配基礎(chǔ),我們后面會(huì)將程序里全部的段都鏈接在這些區(qū)域里。
存儲(chǔ)空間屬性(Type)分為兩類:一類是 Flash(存放 RO 段),一類是 RAM(存放 RW 段)。每個(gè)屬性的空間都可以被定義很多個(gè),但其中僅 Alias 名為 Flash 和 RAM 的空間才是默認(rèn)被選中用于鏈接程序段的(可通過(guò)上下移動(dòng)按鈕將指定空間調(diào)整到前排 Flash 和 RAM 的位置)。
2.2 默認(rèn)程序段分配
還是在上一節(jié)打開的 Properties 選項(xiàng)配置界面,其中 Settings / Managed Linker Script 頁(yè)面就是鏈接文件里具體程序段鏈接設(shè)置,這個(gè)頁(yè)面的最上面 Manage linker script 要保持勾選,勾選上則代表使用 IDE 的鏈接文件自動(dòng)生成功能。
在一個(gè)具體應(yīng)用程序項(xiàng)目工程里,如果源文件僅包含標(biāo)準(zhǔn) C 和匯編代碼,那么程序段會(huì)被默認(rèn)歸納為三大類:RO 段(函數(shù)代碼,常量,全局變量初值等),RW 段(全局變量,重定向到 RAM 中函數(shù)代碼等),Heap/Stack。IDE 里分別提供了這三類程序段的空間指定:
1. Link application to RAM 勾選框:
- 不勾選,則 RO 段放在 2.1 節(jié)圖中 Alias 名為 Flash 的空間里
- 勾選上,則 RO 段放在 2.1 節(jié)圖中 Alias 名為 RAM 的空間里
2. Heap and Stack placement 配置框:
- 可以按需調(diào)整 Heap/Stack 里的 Region,Location,Size,其中 Region 可以是 2.1 節(jié)圖中屬性為 RAM 的任意空間
- Heap/Stack 默認(rèn)大小均為 4KB,放在 2.1 節(jié)圖中 Alias 名為 RAM 的空間里
3. Global data placement 下拉框:
- 可以按需鏈接 RW 段到 2.1 節(jié)圖中屬性為 RAM 的任意空間
- RW 段默認(rèn)放在 2.1 節(jié)圖中 Alias 名為 RAM 的空間里
2.3 自定義程序段分配
除了上一節(jié)鏈接器默認(rèn)的程序段名外,我們也可以自定義一些用戶段名,方便一些特殊代碼處理。這里需要使用 ** attribute ((section("UserSectionName")))** 鏈接器語(yǔ)法來(lái)修飾指定函數(shù)/變量,這樣該函數(shù)/變量就會(huì)被放在 UserSectionName 段里,然后我們?cè)谏弦还?jié)圖中鏈接設(shè)置框的最后 Extra linker script input sections 框里單獨(dú)為自定義 UserSectionName 段指定鏈接空間。
比如工程 clock_config.c 文件里如下函數(shù) UpdateSemcClock(),這個(gè)函數(shù)在默認(rèn)的 RO .text 段里,RO 段都是鏈接在 Flash 里的,但是我們希望將這個(gè)函數(shù)重定向到 ITCM 里執(zhí)行,所以我們可以使用 attribute ((section("CodeQuickAccess"))) 鏈接器語(yǔ)法來(lái)修飾這個(gè)函數(shù),然后在 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 自動(dòng)生成的鏈接文件
鏈接設(shè)置完成后,會(huì)在工程目錄 \\MCUXpressoIDE_11.4.0_6224\\workspace\\evkmimxrt1170_hello_world_demo_cm7\\Debug 下自動(dòng)生成最終鏈接文件(假定用得 debug build),文件一共有三個(gè),其中 evkmimxrt1170_hello_world_demo_cm7_Debug.ld 是主鏈接文件,感興趣的可以打開這個(gè)鏈接文件學(xué)習(xí)一下(如果看不懂語(yǔ)法可以結(jié)合這篇文章 https://www.embedded.com/building-bare-metal-arm-systems-with-gnu-part-3/ )。
2.5 查看Map文件確認(rèn)
按照 2.1 節(jié)和 2.2 節(jié) 圖中的鏈接設(shè)置,我們編譯鏈接 evkmimxrt1170_hello_world_demo_cm7 工程可以得到如下鏈接結(jié)果,從空間占用上來(lái)看是符合預(yù)期的。
現(xiàn)在我們可以打開生成的 evkmimxrt1170_hello_world_demo_cm7.map 文件具體分析一下最終鏈接情況,痞子衡摘錄了最核心部分如下:
Memory Configuration
Name Origin Length Attributes
/------------------------------------------------------------/
// RO .text 段在 BOARD_FLASH:0x30000000 - 0x30006eaf,共 28336 個(gè)字節(jié)
// RO CodeQuickAccess 段在 BOARD_FLASH:0x30006eb0 - 0x30006ee7,共 56 個(gè)字節(jié)
// RO .data_init 段在 BOARD_FLASH:0x30006ee8 - 0x30006eeb,共 4 個(gè)字節(jié)
.boot_hdr 0x30000000 0x2000
.text 0x30002000 0x4eb0
// RW CodeQuickAccess 段在 SRAM_ITC_cm7:0x00000000 - 0x00000037,共 56 個(gè)字節(jié)
.data_RAM4 0x00000000 0x38 load address 0x30006eb0
CodeQuickAccess
0x00000000 0x38 ./board/clock_config.o
0x00000000 UpdateSemcClock
// RW .data 段在 BOARD_SDRAM:0x80000000 - 0x80000003,共 4 個(gè)字節(jié)
.data 0x80000000 0x4 load address 0x30006ee8
.data.SystemCoreClock
0x80000000 0x4 ./device/system_MIMXRT1176_cm7.o
// RW .bss 段在 BOARD_SDRAM:0x80000004 - 0x80000107,共 260 個(gè)字節(jié)
.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)
簡(jiǎn)單總結(jié)下,RO 段一般從 Flash 的最前面開始鏈接的,.text 段在最前面,然后是 ramfunc 函數(shù)實(shí)體,最后是 .data_init 段(全局變量初值)。RW 段也是從 RAM 的最前面開始鏈接,.data 段在前,.bss 在后,然后是 Heap 和 Stack(Heap/Stack的具體位置是可以設(shè)置的,有 Start、End、Post Data 三種選擇)。
三、MCUXpresso IDE下鏈接小實(shí)驗(yàn)
根據(jù)上面的知識(shí),我們現(xiàn)在來(lái)做些鏈接設(shè)置小實(shí)驗(yàn),在做實(shí)驗(yàn)前,我們調(diào)整下 Memory 定義,把 SDRAM 相關(guān)空間移到后面去,默認(rèn) RAM 用 SRAM_DTC_cm7 空間,這樣看起來(lái)習(xí)慣一點(diǎn)。
3.1 默認(rèn) XiP 鏈接
調(diào)整過(guò) Memory 空間順序后的鏈接結(jié)果如下:
3.2 Non-XiP 鏈接
現(xiàn)在我們嘗試使能 Link application to RAM 選項(xiàng),其余不變,此時(shí)可以看到 28396 Bytes 的 RO 段也到了 SRAM_DTC_cm7 空間里,BOARD_FLASH 空間完全沒(méi)有任何占用:
3.3 XiP 鏈接,調(diào)整 Stack 大小并放置到 OCRAM1
我們嘗試調(diào)整 Stack 大小到 1KB 并放置到 SRAM_OC1,其余不變,此時(shí)可以看到 SRAM_DTC_cm7 空間消耗相比 3.1 節(jié)里少了 4KB,但 SRAM_OC1 空間消耗多了 1KB:
3.4 XiP 鏈接,調(diào)整 RW 段到 OCRAM2
我們嘗試調(diào)整 RW 段到 SRAM_OC2,其余不變,此時(shí)可以看到 SRAM_DTC_cm7 空間消耗相比 3.1 節(jié)里少了 264 Bytes,但 SRAM_OC2 空間消耗多了 264 Bytes:
至此,MCUXpresso IDE下工程鏈接文件配置管理與自動(dòng)生成機(jī)制便介紹完畢了。
審核編輯:劉清
-
ARM
+關(guān)注
關(guān)注
134文章
9084瀏覽量
367381 -
FlaSh
+關(guān)注
關(guān)注
10文章
1633瀏覽量
147939 -
GCC
+關(guān)注
關(guān)注
0文章
107瀏覽量
24835 -
編譯器
+關(guān)注
關(guān)注
1文章
1623瀏覽量
49108
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論