大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家講的是嵌入式開發里的map文件。
第四節課里,痞子衡給大家介紹了第一種output文件-relocatable文件,本文繼續給大家講project生成的第二種output文件-map文件,map文件記錄了很多重要的信息,這對於后續調試有很大幫助。
文件關系:鏈接文件(.icf) + 工程文件(.ewp) + 可重定向文件(.o/.a) -> 映射文件(.map)
痞子衡在第四節課可重定向文件(.o/.a)里分析object文件里的symbol list時講到由於object文件並沒有經過鏈接,所以所有symbol地址信息是無效的(待分配的),而map文件就是所有relocatable文件經過鏈接器統一鏈接后生成的記錄鏈接信息的文件,map文件里可以查到所有symbol在存儲器中具體分配地址。話不多說,讓我們直接開啟map文件分析之旅,以第三節課工程文件(.ewp)里demo工程為例。
一、解析map文件
在IAR軟件選項設置options->Linker->List里選中Generate linker map file,編譯鏈接demo工程可在D:\myProject\bsp\builds\demo\Release\List路徑下得到demo.map文件。讓我們從頭到尾逐一分析里面內容:
1.1 工程文件信息
map文件里第一部分信息記錄的是工程文件相關信息,包括工程使用的軟件版本,工程編譯時間,工程文件目錄,工程文件生成文件信息。
###############################################################################
#
# IAR ELF Linker V8.11.2.13589/W32 for ARM 12/Jan/2018 17:37:39
# Copyright 2007-2017 IAR Systems AB.
#
# Output file = D:\myProject\bsp\builds\demo\Release\Exe\demo.elf
# Map file = D:\myProject\bsp\builds\demo\Release\List\demo.map
# Command line =
# -f C:\Users\Baoge\AppData\Local\Temp\EW5D86.tmp
# (D:\myProject\bsp\builds\demo\Release\Obj\main.o
# D:\myProject\bsp\builds\demo\Release\Obj\reset.o
# D:\myProject\bsp\builds\demo\Release\Obj\startup.o
# D:\myProject\bsp\builds\demo\Release\Obj\startup_MKL25Z4.o
# D:\myProject\bsp\builds\demo\Release\Obj\system_MKL25Z4.o
# D:\myProject\bsp\builds\demo\Release\Obj\task.o -o
# D:\myProject\bsp\builds\demo\Release\Exe\demo.elf --map
# D:\myProject\bsp\builds\demo\Release\List\demo.map --config
# D:\myProject\bsp\builds\demo/../../linker/iar/KL25Z128xxx4_flash.icf
# --entry Reset_Handler --inline --vfe --text_out locale)
#
###############################################################################
1.2 系統庫使用信息
map文件里第二部分信息記錄的是工程系統庫使用情況,由於task.c里調用了malloc()、free()等HEAP相關操作的API,所以自然我們在編譯鏈接工程時會使用到HEAP相關系統庫,這里告訴我們用的是DLib里的DLMalloc,而DLMalloc有很多種不同的HEAP實現策略,我們可在options->General Options->Library Option 2->Heap selection指定具體策略,由於demo工程選的是Automatic,也就是讓IDE自動選擇,這里告訴我們最終用的策略是advanced heap。
*******************************************************************************
*** RUNTIME MODEL ATTRIBUTES
***
CppFlavor = *
__Heap_Handler = DLMalloc
__SystemLibrary = DLib
__dlib_version = 6
*******************************************************************************
*** HEAP SELECTION
***
The advanced heap was selected because the application calls memory
allocation functions outside of system library functions, and there
are calls to deallocation functions in the application.
1.3 各object中Section放置信息
從map文件第三部分開始,就進入非常有用的信息環節了。第一個重要信息就是section放置信息。我們在第四節課可重定向文件(.o/.a)里分析過單個relocatable文件task.o,task.o里各個基本section都有,但是都並沒有分配有效地址,而這里列出了所有relocatable文件統一存儲和地址分配信息,從這里我們可以看到,鏈接器在整合各section的時候,都是以object文件為單位的,這意味着同一個object文件里的同一個section里的對象(變量/函數)在存儲空間里的位置也是靠在一起的。
另外一個有意思的信息是在第二節課鏈接文件(.icf)里,我們一共有四句block放置語句,在這里section也被分成了四個block:A0,P1,P2,P3。IDE給每個block重命名了,這些重命名的信息將會在第六節課可執行文件(.out/.elf)里被提到。
*******************************************************************************
*** PLACEMENT SUMMARY
***
define block Vectors with alignment = 256 { ro section .intvec };
"A0": place at start of [0x00000000-0x0001ffff] { block Vectors };
define block CodeRelocate { section .textrw_init };
define block ApplicationFlash { ro, block CodeRelocate };
"P1": place in [from 0x00000000 to 0x0001ffff] { block ApplicationFlash };
define block CodeRelocateRam { section .textrw };
define block HEAP with size = 1K, alignment = 8 { };
define block ApplicationRam { rw, block CodeRelocateRam, block HEAP };
"P2": place in [from 0x10002000 to 0x1000ffff] { block ApplicationRam };
define block CSTACK with size = 8K, alignment = 8 { };
"P3": place in [from 0x10000000 to 0x10001fff] { block CSTACK };
initialize manually with packing = copy, complex ranges { section .data };
initialize manually with packing = copy, complex ranges { section .textrw };
Section Kind Address Size Object
------- ---- ------- ---- ------
"A0": 0x40
Vectors 0x00000000 0x40 <Block>
.intvec ro code 0x00000000 0x40 startup_MKL25Z4.o [1]
- 0x00000040 0x40
"P1": 0x1a3c
ApplicationFlash 0x00000040 0x1a3c <Block>
.noinit ro code 0x00000040 0x58 reset.o [1]
.rodata const 0x00000098 0x4 main.o [1]
Veneer ro code 0x0000009c 0x10 - Linker created -
.text ro code 0x000000ac 0x20 main.o [1]
.text ro code 0x000000cc 0x58 task.o [1]
.text ro code 0x00000124 0x16f8 dlmalloc.o [3]
.text ro code 0x0000181c 0x50 ABImemset.o [4]
.text ro code 0x0000186c 0x5c ABImemcpy.o [4]
.text ro code 0x000018c8 0x8 heaptramp0.o [3]
.text ro code 0x000018d0 0xa abort.o [3]
.text ro code 0x000018da 0x2 startup_MKL25Z4.o [1]
.text ro code 0x000018dc 0x2c xgetmemchunk.o [3]
.text ro code 0x00001908 0xc XXexit.o [4]
.text ro code 0x00001914 0x90 startup.o [1]
.text ro code 0x000019a4 0xc system_MKL25Z4.o [1]
.text ro code 0x000019b0 0x1a cmain.o [4]
.text ro code 0x000019ca 0x2 startup_MKL25Z4.o [1]
.text ro code 0x000019cc 0x28 data_init.o [4]
.text ro code 0x000019f4 0x8 exit.o [3]
.text ro code 0x000019fc 0xa cexit.o [4]
.text ro code 0x00001a06 0x2 startup_MKL25Z4.o [1]
CodeRelocate 0x00001a08 0x10 <Block>
Initializer bytes const 0x00001a08 0x10 <for CodeRelocateRam-1>
.data_init 0x00001a18 0x4 <Block>
Initializer bytes const 0x00001a18 0x4 <for .data-1>
.text ro code 0x00001a1c 0x2 startup_MKL25Z4.o [1]
.text ro code 0x00001a1e 0x2 startup_MKL25Z4.o [1]
.text ro code 0x00001a20 0xc cstartup_M.o [4]
.text ro code 0x00001a2c 0x40 zero_init3.o [4]
.iar.init_table const 0x00001a6c 0x10 - Linker created -
.rodata const 0x00001a7c 0x0 zero_init3.o [4]
- 0x00001a7c 0x1a3c
"P3": 0x2000
CSTACK 0x10000000 0x2000 <Block>
CSTACK uninit 0x10000000 0x2000 <Block tail>
- 0x10002000 0x2000
"P2": 0x620
ApplicationRam 0x10002000 0x620 <Block>
CodeRelocateRam 0x10002000 0x10 <Block>
CodeRelocateRam-1 0x10002000 0x10 <Init block>
.textrw inited 0x10002000 0x10 task.o [1]
.data 0x10002010 0x4 <Block>
.data-1 0x10002010 0x4 <Init block>
.data inited 0x10002010 0x4 task.o [1]
.bss 0x10002014 0x208 <Block>
.bss zero 0x10002014 0x4 task.o [1]
.bss zero 0x10002018 0x10 task.o [1]
.bss zero 0x10002028 0x18 dlmalloc.o [3]
.bss zero 0x10002040 0x1d8 dlmalloc.o [3]
.bss zero 0x10002218 0x4 xgetmemchunk.o [3]
.noinit uninit 0x1000221c 0x4 task.o [1]
HEAP 0x10002220 0x400 <Block>
HEAP uninit 0x10002220 0x400 <Block tail>
- 0x10002620 0x620
1.4 系統初始化表信息
map文件第四部分列出了經由系統初始化的表,這里只有bss段(即代碼中所有僅定義但沒有賦初值的全局變量),由於SRAM中數據存有一定不確定性,所以系統必須要在啟動時將bss段內所有數據全部清零,以保證程序能正常運行。
*******************************************************************************
*** INIT TABLE
***
Address Size
------- ----
Zero (__iar_zero_init3)
1 destination range, total size 0x208:
0x10002014 0x208
1.5 各object文件所占存儲資源信息
map文件第五部分會列出各object文件所占存儲資源具體信息,有了這部分信息,我們便知道工程具體是哪個object文件(功能模塊)占用資源最多,如果有代碼size方面優化的需求,可以選擇占用資源較多的object文件里的代碼進行針對性地優化。
*******************************************************************************
*** MODULE SUMMARY
***
Module ro code rw code ro data rw data
------ ------- ------- ------- -------
D:\myProject\bsp\builds\demo\Release\Obj: [1]
main.o 32 4
reset.o 88
startup.o 144
startup_MKL25Z4.o 74
system_MKL25Z4.o 12
task.o 88 16 20 28
-----------------------------------------------------
Total: 438 16 24 28
command line: [2]
-----------------------------------------------------
Total:
dl6M_tln.a: [3]
abort.o 10
dlmalloc.o 5 880 496
exit.o 8
heaptramp0.o 8
xgetmemchunk.o 44 4
-----------------------------------------------------
Total: 5 950 500
rt6M_tl.a: [4]
ABImemcpy.o 92
ABImemset.o 80
XXexit.o 12
cexit.o 10
cmain.o 26
cstartup_M.o 12
data_init.o 40
zero_init3.o 64
-----------------------------------------------------
Total: 336
Linker created 16 16 9 216
---------------------------------------------------------
Grand Total: 6 740 16 40 9 744
1.6 各object具體分配信息
map文件第六部分記錄的是各object文件里的具體對象(變量,函數等)在存儲空間里的具體分配,這里的信息對於調試來說非常重要。平時調試時我們除了單步執行、打斷點之外,還會配合看內存的實時情況,有時候因為編譯器優化的原因,從代碼角度看不出邏輯問題(比如我們給變量s_variable0賦值為1),但是內存里(0x10002014)卻並沒有被更新為1,這時候工程肯定是有問題的,定位到了具體問題,然后我們再考慮解決問題的方法。
*******************************************************************************
*** ENTRY LIST
***
Entry Address Size Type Object
----- ------- ---- ---- ------
.bss$$Base 0x10002014 -- Gb - Linker created -
.bss$$Limit 0x1000221c -- Gb - Linker created -
.data$$Base 0x10002010 -- Gb - Linker created -
.data$$Limit 0x10002014 -- Gb - Linker created -
.data_init$$Base 0x00001a18 -- Gb - Linker created -
.data_init$$Limit 0x00001a1c -- Gb - Linker created -
.iar.init_table$$Base 0x00001a6c -- Gb - Linker created -
.iar.init_table$$Limit 0x00001a7c -- Gb - Linker created -
?main 0x000019b1 Code Gb cmain.o [4]
ApplicationFlash$$Base 0x00000040 -- Gb - Linker created -
ApplicationFlash$$Limit
0x00001a7c -- Gb - Linker created -
ApplicationRam$$Base 0x10002000 -- Gb - Linker created -
ApplicationRam$$Limit 0x10002620 -- Gb - Linker created -
CSTACK$$Base 0x10000000 -- Gb - Linker created -
CSTACK$$Limit 0x10002000 -- Gb - Linker created -
CodeRelocate$$Base 0x00001a08 -- Gb - Linker created -
CodeRelocate$$Limit 0x00001a18 -- Gb - Linker created -
CodeRelocateRam$$Base 0x10002000 -- Gb - Linker created -
CodeRelocateRam$$Limit 0x10002010 -- Gb - Linker created -
HEAP$$Base 0x10002220 -- Gb - Linker created -
HEAP$$Limit 0x10002620 -- Gb - Linker created -
Region$$Table$$Base 0x00001a6c -- Gb - Linker created -
Region$$Table$$Limit 0x00001a7c -- Gb - Linker created -
Reset_Handler 0x00000041 Code Gb reset.o [1]
SystemInit 0x000019a5 0xc Code Gb system_MKL25Z4.o [1]
Vectors$$Base 0x00000000 -- Gb - Linker created -
Vectors$$Limit 0x00000040 -- Gb - Linker created -
__Vectors_End 0x00000040 Data Gb startup_MKL25Z4.o [1]
__aeabi_memcpy 0x0000186d Code Gb ABImemcpy.o [4]
__aeabi_memcpy4 0x00001895 Code Wk ABImemcpy.o [4]
__aeabi_memset 0x0000181d Code Gb ABImemset.o [4]
__cmain 0x000019b1 Code Gb cmain.o [4]
__data_GetMemChunk 0x000018dd 0x2c Code Gb xgetmemchunk.o [3]
__data_GetMemChunk::start
0x10002218 0x4 Data Lc xgetmemchunk.o [3]
__exit 0x00001909 Code Gb XXexit.o [4]
__iar_Memset4_word 0x0000183d Code Gb ABImemset.o [4]
__iar_Memset_word 0x00001829 Code Gb ABImemset.o [4]
__iar_data_init3 0x000019cd 0x28 Code Gb data_init.o [4]
__iar_dlfree 0x00001271 0x5a4 Code Gb dlmalloc.o [3]
__iar_dlmalloc 0x00000f77 0x2f6 Code Gb dlmalloc.o [3]
__iar_program_start 0x00001a21 Code Gb cstartup_M.o [4]
__iar_systems$$module {Abs}
0x00000001 Data Gb command line/config [2]
__iar_zero_init3 0x00001a2d 0x40 Code Gb zero_init3.o [4]
__vector_table 0x00000000 Data Gb startup_MKL25Z4.o [1]
_call_main 0x000019bd Code Gb cmain.o [4]
_exit 0x000019fd Code Gb cexit.o [4]
_gm_ 0x10002040 0x1d8 Data Lc dlmalloc.o [3]
_main 0x000019c7 Code Gb cmain.o [4]
abort 0x000018d1 0xa Code Gb abort.o [3]
add_segment 0x00000539 0x208 Code Lc dlmalloc.o [3]
exit 0x000019f5 0x8 Code Gb exit.o [3]
free 0x000018c9 0x8 Code Gb heaptramp0.o [3]
heap_task 0x000000db 0x3c Code Gb task.o [1]
init_data_bss 0x00001915 0x54 Code Gb startup.o [1]
init_interrupts 0x00001969 0x12 Code Gb startup.o [1]
init_mparams 0x00000145 0x2a Code Lc dlmalloc.o [3]
init_top 0x0000016f 0x38 Code Lc dlmalloc.o [3]
main 0x000000ad 0x20 Code Gb main.o [1]
mparams 0x10002028 0x18 Data Lc dlmalloc.o [3]
n_variable1 0x1000221c 0x4 Data Gb task.o [1]
normal_task 0x000000cd 0xe Code Gb task.o [1]
prepend_alloc 0x000001b5 0x384 Code Lc dlmalloc.o [3]
ram_task 0x10002001 0x10 Code Gb task.o [1]
s_array 0x10002018 0x10 Data Lc task.o [1]
s_constant 0x00000098 0x4 Data Gb main.o [1]
s_variable0 0x10002014 0x4 Data Lc task.o [1]
s_variable2 0x10002010 0x4 Data Lc task.o [1]
segment_holding 0x00000125 0x20 Code Lc dlmalloc.o [3]
sys_alloc 0x00000749 0x16c Code Lc dlmalloc.o [3]
sys_trim 0x000008b5 0x6a Code Lc dlmalloc.o [3]
tmalloc_large 0x00000931 0x3fe Code Lc dlmalloc.o [3]
tmalloc_small 0x00000d35 0x242 Code Lc dlmalloc.o [3]
[1] = D:\myProject\bsp\builds\demo\Release\Obj
[2] = command line
[3] = dl6M_tln.a
[4] = rt6M_tl.a
1.7 image占用存儲資源信息
map文件第七部分會給出整個工程占用存儲資源情況的總結,這里我們可以看到工程占用ROM資源6780bytes,RAM資源9760bytes,所以我們在選擇芯片時必須保證ROM(FLASH),RAM要大於工程所需。
6 740 bytes of readonly code memory
16 bytes of readwrite code memory
40 bytes of readonly data memory
9 744 bytes of readwrite data memory
二、代碼對象與section的關系
痞子衡在第二節課鏈接文件(.icf)里的講過section的概念,並且列出了IAR系統里默認的各section的含義。經過上面對map文件的分析,現在讓我們直接用demo工程里的main.c和task.c源文件來實例分析section:
Section | Description | Region | Object |
---|---|---|---|
.bss | 未賦初值的全局/靜態變量 | RAM(0x10002014 - 0x1000221b) | s_variable0 (0x10002014 - 0x10002017) |
s_array[16] (0x10002018 - 0x10002027) | |||
CSTACK | 棧:函數調用返回地址、函數傳遞實參、局部變量 | RAM(0x10000000 - 0x10001fff) | normal_task/ram_task/heap_task地址、l_variable、*heap |
.data | 賦初值的全局/靜態變量 | RAM(0x10002010 - 0x10002013) | s_variable2 |
.data_init | 賦初值的全局/靜態變量的初值 | ROM(0x00001a18 - 0x00001a1b) | 0x5a(s_variable2) |
HEAP | 堆:動態內存分配 | RAM(0x10002220 - 0x1000261f) | *heap = (uint8_t *)malloc(16 * sizeof(uint8_t)) |
.intvec | 中斷向量表 | ROM(0x00000000 - 0x0000003f) | startup_MKL25Z4.s里DCD指定的ISR表 |
.noinit | 指明不初始化的全局/靜態變量 | RAM(0x1000221c - 0x1000221f) | n_variable1 |
.rodata | 常量 | ROM(0x00000098 - 0x0000009b) | s_constant |
.text | ROM中執行的函數代碼 | ROM(0x000000ac - 0x00001a07) | main函數體 (0x000000ad - 0x000000cc) |
normal_task函數體 (0x000000cd - 0x000000da) | |||
heap_task函數體 (0x000000db - 0x00000116) | |||
.textrw | RAM中執行的函數代碼 | RAM(0x10002000 - 0x1000200f) | ram_task函數體 |
.textrw_init | RAM中執行的函數代碼的數據 | ROM(0x00001a08 - 0x00001a17) | ram_task函數體 |
至此,嵌入式開發里的map文件痞子衡便介紹完畢了,掌聲在哪里~~~
歡迎訂閱
文章會同時發布到我的 博客園主頁、CSDN主頁、微信公眾號 平台上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。