STM32 MDK编译后生成的 .map文件深入分析
.map文件是STM32開發中非常重要的一個文件,在該文件中可以詳細的查看單個文件、函數及用戶定義的全局變量等的占用RAM和ROM(一般為片內FLASH)的空間大小,通過了解這些信息可以很方便的進行代碼的優化。
在MDK5中,生成的.map文件包含的內容可以在Options for Target--->Listing中如下界面中進行配置,默認是全選的,用戶也可以根據自己的需求進行選擇,如只生成Total info信息。在配置好map生成選項后編譯整個工程,雙擊Project框中的項目名稱即可打開.map文件。若使用的是STM32CubeMX生成的工程,則可能雙擊無法打開.map文件,具體解決方法參考這篇文章:
在STM32CubeMX生成的MDK5工程上添加RT-Thread Nano后雙擊工程名無法打開.map文件的解決方法
默認生成的.map文件由以下幾部分構成:
1)Section Cross References
該部分描述了不同函數之間(可能在同或不同文件中)的調用關系。
在.map中生成該部分信息需要勾選下圖中的標簽4:
.map文件中生成的信息如下所示(部分截圖):
第一行startup_stm32f103xb.o(RESET) refers to startup_stm32f103xb.o(STACK) for __initial_sp說明:startup_stm32f103xb.o文件中的“RESET”段為它使用的__initial_sp引用了startup_stm32f103xb.o文件中的“STACK”段。
有時候在編譯工程時會報錯,提示"Undefined symbol xxx(referred from yyy.o)",這表明在鏈接的過程中,yyy.o文件中引用的xxx符號并沒有被定義,此時我們需要打開yyy.c或yyy.s文件查看xxx是否被定義,沒定義需加上定義。
.o文件是.c文件或.s文件編譯后生成的目標文件,各個文件及文件內的段是相互獨立的,鏈接器根據它們之間的相互引用將各文件鏈接起來。
2)Removing Unused input sections from the image.
該部分描述了被MDK編譯器優化掉的在鏈接過程中鏈接器發現的并未在工程中被引用的段或函數。這里需要注意的是,這部分并非在.o文件中被刪除的,而是在鏈接器將這些.o文件鏈接生成.axf文件的過程中忽略掉這些無用部分,只將有用到的部分添加進.axf文件,如此可以有效的減少代碼占用空間大小。
在.map中生成該部分信息需要勾選下圖中的標簽7:
.map文件中生成的信息如下所示(部分截圖):
在MDK中可以通過勾選Options for Target--->C/C++--->One ELF Section per Function選項進行多余函數優化,若不勾選該選項也會進行部分函數優化,但不夠徹底
下面通過實例說明勾選和不勾選One ELF Section per Function對生成的工程的影響:
- 當勾選Options for Target--->C/C++中的One ELF Section per Function后在.map文件中生成的Removing Unused input sections from the image部分總結果如下:
共優化了529個函數,減少占用空間30270Bytes
- 當取消勾選Options for Target--->C/C++中的One ELF Section per Function后在.map文件中生成的Removing Unused input sections from the image部分總結果如下:
共優化了121個函數,減少占用空間3806Bytes
通過以上對比可發現,勾選Options for Target--->C/C++--->One ELF Section per Function相比于不勾選要減少代碼空間為26464Byte(30270 - 3806 )。這部分優化的空間最終會體現在Program Size中的Code大小上(60560 - 35716 = 24844Bytes),因此該選項對工程代碼的優化有很大的作用,建議要勾選上這個選項。
3)Image Symbol Table
該部分描述了Local Symbols和Global Symbols,即局部標號和全局標號。
在.map中生成該部分信息需要勾選下圖中的標簽3:
.map文件中生成的信息如下所示(部分截圖):
Local Symbols主要指的是通過static聲明的全局變量地址和大小,.c文件中函數的地址和用static聲明的函數代碼的大小,匯編文件中的作用域限定在本文件中的標號地址。如被限定在某個.c文件中使用的函數一般用static進行修飾防止和其它文件中的同名函數沖突,如在某個函數內部通過static聲明的變量雖然具有全局的生命周期但其只能在該函數中被訪問。
Global Symbols主要是指不是用static聲明的全局變量的地址和大小,.c文件中和函數的地址及其代碼大小,匯編文件中作用域為全工程的標號地址。
4)Memory Map of the image
該部分描述了映像文件的內存映射。
在.map中生成該部分信息需要勾選下圖中的標簽1:
.map文件中生成的信息如下所示(部分截圖):
映像文件分為加載域(Load Region)和執行域(Execution Region):
加載域反映了程序中各個段存放在ROM(FLASH)存儲器中時的位置關系,Load Region LR_IROM1 (Base: 0x08000000, Size: 0x0000ffb4, Max: 0x00010000, ABSOLUTE, COMPRESSED[0x0000f744])中的Base表示程序從0x08000000處開始保存,Size表示程序實際占用ROM(一般為內部FLASH)空間為0x0000ffb4 Bytes,Max表示芯片最大的ROM空間為0x00010000。
執行域是芯片上電后開始執行代碼的時候的運行狀態,Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x0000ef94, Max: 0x00010000, ABSOLUTE)中的Base表示執行域從0x08000000處開始,Size表示執行域空間大小為0x0000ef94 Bytes,Max表示芯片最大的ROM空間為0x00010000。
映像中的入口點Image Entry point是程序開始執行的地方,為_main函數起始的地方,而不是Reset_Handler。
RAM上的普通變量只需4字節對齊,但是棧空間的邊界需要8字節對齊。
?
5)Image component sizes
該部分描述了映像文件的組件大小,組件指的是單個的源文件,因為一個項目工程是由很多個.c文件組成的。這里會列舉單個.c文件所占用的空間大小(RAM和ROM),具體為Code、inc.data(內聯函數)、RO-Data、RW-Data、ZI-Data,并根據這些信息統計出程序占據的總RAM和ROM空間的大小。
在.map中生成該部分信息需要勾選下圖中的標簽5:
.map文件中生成的信息如下所示(部分截圖):
從如上匯總信息可以看出,整個程序下載到STM32的ROM(FLASH)中時占用的空間大小為從0x08000000開始的38440字節?(Code + RO Data + RW Data) 。當程序運行時,占用的RAM空間大小為從0x20000000開始的11152字節(RW Data + ZI Data)。
?
.map文件中名詞的解釋:
- section:映像文件的代碼和數據塊
- RO:Read-Only,包括RO-Data(只讀數據)和RO-Code(代碼)
- RW:Read-Write,指的是RW-Data,即讀寫數據段,存放初始化為非0值的全局變量
- ZI:Zero-Initialized,指的是ZI-Data,0數據段,存放初始化為0的全局變量或未初始化的全局變量(程序運行時會對未初始化的全局變量自動清0)
- .text:與RO-Code意義相同
- .constdata:與RO-Data意義相同
- .bss:與ZI-Data意義相同
- .data:與RW-Data意義相同
htm文件:
基本統計了所有被調用函數的棧stack的使用情況(不考慮中斷嵌套,因為中斷嵌套是不可預測的),會給出函數調用時最大的棧深度,如此可以方便評估究竟需要開辟多大的棧空間。
?
參考資料:
安富萊:MDK生成的map和htm文件分析
《ARM Cortex-M3與ARM Cortex-M4權威指南》(第3版)
總結
以上是生活随笔為你收集整理的STM32 MDK编译后生成的 .map文件深入分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中文语料库
- 下一篇: [pytorch、学习] - 4.6 G