日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32 map文件解析

發布時間:2024/1/23 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32 map文件解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是map文件?
簡單的說:map文件是通過編譯器編譯之后,集程序、數據及IO空間的一種映射文件。

Keil生成map文件的設置如下圖所示:
生成文件保存路徑與Listings選擇路徑相同。

keil 主要包含配置
Memory Map:內存映射
Callgraph:圖像映射
Symbols:符號
Cross Reference:交叉引用
Size Info:大小信息
Totals Info:統計信息
Unused Section Info:未調用模塊信息
Veneers Info:裝飾信息

如何查看map文件
1.到對應文件生成文件目錄下查看(KEIL即為Listings目錄)
2.雙擊工程目標名則會打開對應工程的map文件(需要是編譯完成的情況下)

MAP文件基本概念
段(section):描述映像文件的代碼和數據塊
RO:Read-Only的縮寫,包括RO-data(只讀數據)和RO-code(代碼)
RW:Read-Write的縮寫,主要是RW-data,RW-data由程序初始化初始值
ZI:Zero-initialized的縮寫,主要是ZI-data,由編譯器初始化為0。
.text:與RO-code同義
.constdata:與RO-data同義
.bss:與ZI-data同義
.data:與RW-data同義

文件分析

map文件分為如下五大部分內容:
1.Section Cross References:模塊、段(入口)交叉引用

2.Removing Unused input sections from the image:移除未調用模塊

3.Image Symbol Table:映射符號表

4.Memory Map of the image:內存(映射)分布

5.Image component sizes:存儲組成大小

第一部分:Section Cross References(模塊、段的交叉引用關系)
主要是各個源文件生成的模塊之間相互引用的關系。“refer to”是引用的意思,比如:

首先main.c和led.c會被編譯成目標文件main.o和led.o。i.main是main.c中main函數的入口(也是main函數編譯出的段,函數編譯后以段的形式存在,函數之間的引用,也就是段與段之間的引用)。i.LED_Init是led.c中LED_Init函數的入口(也是LED_Init函數編譯出的段)。因此上面這段的意思就是main.c中的main函數引用了led.c中的LED_Init函數,該部分剩余的其他語句基本都類似。

第二部分:Removing Unused input sections from the image(移除未使用的段)
就是將庫中沒有用到的函數從可執行映像中刪除掉,減小程序的體積。
刪除(指不加入到*.axf 文件,不是指在*.o 文件刪除),這樣可以防止這些無用數據占用程序空間

最后一欄有個總的統計結果:

總共移除了666個未使用的段,共51615字節。

第三部分:Image Symbol Table(映射符號表,列出了各個段所存儲的對應地址)

分為Local Symbols局部 和 Global Symbols全局。

局部標號(用static聲明的全局變量地址和大小,C文件中函數的地址和用static聲明的函數代碼大小,匯編文件中的標號地址(作用域限本文件)
全局標號,全局變量的地址和大小,C文件中函數的地址及其代碼大小,匯編文件中的標號地址(作用域全工程)

Local Symbols記錄了用static聲明的全局變量地址和大小,C文件中函數的地址和用static聲明的函數代碼大小,匯編文件中的標號地址(作用域限本文件),下面是部分截圖:

1、Symbol Name:符號名稱

2、Value:存儲對應的地址;

大家會發現有0x0800xxxx、0x2000xxxx這樣的地址。
0x0800xxxx指存儲在FLASH里面的代碼、變量等。
0x2000xxxx指存儲在內存RAM中的變量Data等。

3、Ov Type:符號對應的類型

符號類型大概有幾種:Number、Section、Thumb Code、Data等;
細心的朋友會發現:全局、靜態變量等位于0x2000xxxx的內存RAM中。

4、Size:存儲大小

這個容易理解,我們懷疑內存溢出,可以查看代碼存儲大小來分析。

5、Object(Section):當前符號所在段名

這里一般指所在模塊(所在源文件)。

舉例:

LED_Init 符號存儲在 0x08001861 地址,它屬于 Thumb Code 類型,大小為 62 字節,它所在的節區為 led.o 文件的 i.LED_Init 節區。

以下這段位于Local Symbols中,可以判斷LCD_Gpio_Init是一段static的函數,函數占用flash 150字節,在lcd.o中定義了。

堆和棧也在Local Symbols中,可以看出HEAP和STACK大小分別是512字節和1024字節。

lcd_buf位于Local Symbols中,因此lcd_buf是一個static變量,大小為1152字節,符號類型是Data,在bss段可以判定沒有初始化,【bss(Block Started by Symbol segment):未初始化靜態變量, 未初始化數據】,定義在lcd.o文件

第四部分:Memory Map of the image(映像的內存分布)

映像文件可以分為加載域(Load Region)和運行域(Execution Region):加載域反映了ARM可執行映像文件的各個段存放在存儲器中的位置關系。下面是部分截圖,另外映像中的入口點就是程序開始執行的位置。

1、Exec Addr:運行域地址

2、Load Addr:加載域地址

3、Size:存儲大小

4、Type:類型

Data:數據類型

Code:代碼類型

Zero:未初始化變量類型

PAD:這個類型在map文件中放在這個位置,其實它不能算這里的類型。要翻譯的話,只能說的“補充類型”。

ARM處理器是32位的,如果定義一個8位或者16位變量就會剩余一部分,這里就是指的“補充”的那部分,會發現后面的其他幾個選項都沒有對應的值。

5、Attr 屬性 RO:存儲與ROM中的段;RW:存儲與RAM中的段
6、Section Name 段名
7、Object 目標

運行域反映了ARM可執行映像文件各個段真正執行時在存儲器中的位置關系:

Load Region LR_IROM1 (Base: 0x08000000, Size: 0x000122a8, Max: 0x00080000, ABSOLUTE, COMPRESSED[0x000121a0])

指加載域位于LR_IROM1開始地址0x08000000,大小有0x000122a8,這塊區域最大為0x00080000

Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x0001213c, Max: 0x00080000, ABSOLUTE) Execution Region RW_IRAM1 (Exec base: 0x20000000, Load base: 0x0801213c, Size: 0x00011de0, Max: 0x00018000, ABSOLUTE, COMPRESSED[0x00000064])

執行區域:對應我們目標配置中的區域

【補充:加載域和運行域】
加載域就是程序在Flash中的實際存儲,而運行域是芯片上電后的運行狀態,因為MCU沒上電時RAM中沒有數據,所以此時所有的東西(包括代碼、變量、初始值等)都是存放在flash中的,當上電后又要把變量等復制到RAM中才能正常運行。

通過上面的框圖可以看出,RW區也是要存儲到ROM/Flash里面的。在執行映像之前,必須將已初始化的RW數據從ROM中復制到RAM中的執行地址并創建ZI Section(初始值為0的變量區),這樣才算完成了MCU運行的準備。

第五部分:Image component sizes(映像組成大小)

Code (inc. Data) :顯示代碼占用了多少字節。 在此映像中,有19442字節的代碼, 其中包括1832字節的內聯數據 (inc. data),例如文字池和短字符串。

RO Data :顯示只讀數據占用了多少字節(比如const char buf[] = “123456”)。這是除 Code (inc. data) 列中包括的內聯數據之外的數據。

RW Data :顯示讀寫數據占用了多少字節。

ZI Data :顯示零初始化的數據占用了多少字節。

Debug :顯示調試數據占用了多少字節,例如,調試輸入節以及符號和字符串。

Object Totals :顯示鏈接到一起以生成映像的對象占用了多少字節。

(incl. Generated):鏈接器會生成的映像內容,例如,交互操作中間代碼。 如果 Object Totals 行包含此類型的數據,則會顯示在該行中。本例中共有 1016 字節的 RO 數據,其中32字節是鏈接器生成的 RO 數據。

(incl. Padding) :鏈接器根據需要插入填充,以強制字節對齊。

最后是整個映像文件的總結說明:

Grand Totals:顯示映像的真實大小。

ELF Image Totals:ELF(Executable and Linking Format)可執行鏈接格式映像文件大小。

ROM Totals:顯示包含映像所需的 ROM的最小大小。這不包括 ZI數據和存儲在ROM 中的調試信息。

補充:KEIL 計算程序占用大小
如圖是MDK編譯之后的信息:

Code:指代碼的大小;
Ro-data:指除了內聯數據(inline data)之外的常量數據;
RW-data:指可讀寫(RW)、已初始化的變量數據;
ZI-data:指未初始化(ZI)的變量數據;

提醒:
A.Code、Ro-data:位于FLASH中;
B.RW-data、ZI-data:位于RAM中;
C.RW-data已初始化的數據會存儲在Flash中,上電會從FLASH搬移至RAM。

占用的FLASH = Code + RO-data + RW-data
占用的SRAM = RW-data + ZI-data
為什么RW-data既在FLASH中又在SRAM?—因為RW-data已初始化的數據會存儲在Flash中,上電會從FLASH搬移至RAM。

關系如下:
RO Size = Code + RO Data
RW Size = RW Data + ZI Data
ROM Size = Code + RO Data + RW Data
(此數據在map文件末尾就可以查看)

補充:內存分布
text:程序 文字區段(text segment)也稱為程序段(code segment),存放可執行命令(instructions)。

該區段通常位于 heap 或 stack 之後,避免因 heap 或 stack 溢出或者覆蓋 CPU 指令。

data:初始化靜態變量 初始化數據區段(initialized data segment)存儲已經初始化的靜態變量,例如有經過初始化的 C 語言的全局變量(global variables)以及靜態變量(static variables),分為RW-data和RO-data。

bss(Block Started by Symbol segment):未初始化靜態變量 未初始化數據

stack:棧(stack segment)用于存儲函數的局部變量,以及各種函數調用時需要存儲的信息(比如函數返回的存儲器地址、函數狀態等),每一次的函數調用就會在棧上建立一個 stack frame(棧幀),存儲該次調用的所有數據于狀態,這樣以來同一個函數被調用多次時,就會有不同棧幀,不會相互干擾。

heap:堆是用于存放進程運行中被動態分配的內存段,它的大小并不固定,可動態擴張或縮減,例如 C 語言的 malloc 以及 C++ 的 new 所建立的變量都是儲存于此。

棧(Stack)一般的狀態會從高地址往低地址生長,而 heap 相反。


前面提到的運行域從Section Name也可以印證上面的內存分布圖。

參考鳴謝:
https://blog.csdn.net/qlexcel/article/details/78884379

https://neyzoter.cn/2019/04/25/Map-Of-Keil/#3%E5%86%85%E5%AD%98%E7%A7%BB%E9%99%A4%E6%8E%92%E6%9F%A5%E6%96%B9%E6%B3%95

https://www.cnblogs.com/chengeputongren/p/12177423.html

https://blog.csdn.net/IT_B_O_Y/article/details/93722989

https://zhuanlan.zhihu.com/p/108358035

https://www.cnblogs.com/ycpkbql/p/9160192.html

總結

以上是生活随笔為你收集整理的STM32 map文件解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。