KeilMDK输出map⽂件分析
转⾃:
⼀、⽂件分析流程
1、第⼀部分:Section Cross References
主要是各个源⽂件⽣成的模块之间相互引⽤的关系。
stm32f10x.o(STACK) refers (Special) to stkheap2.o(.text) for __use_two_region_memory
⽐如上⾯这句话,stm32f10x.o是stm32f10x.s⽣成的⽬标⽂件模块,(STACK)是⽂件内定义的⼀个段,链接器把它视为⼀个Section,输⼊节。
它引⽤了模块stkheap2.o输⼊节(.text)⾥⾯的⼀个全局符号__use_two_region_memory(可能是⼀个函数或变量)。这个(Special)不知道是什么含义。
剩下的基本都是这⽤的意思。
stm32f10x_vector.o(.text) refers to __main.o(main) for __main
__main.o(main) refers to kernel.o(.text) for __rt_entry
kernel.o(.text) refers to usertask.o(.text) for main
上⾯这⼏个对于程序意义⽐较重⼤⽤户在启动代码中调⽤了__main.o模块中的__main函数,__main⼜调⽤了kernel.o中的__rt_entry函数,最后kernel.o⼜调⽤了⽤户定义的main主函数。
2、第⼆部分:Removing Unused input sections from the image.
就是将库中没有⽤到的函数从可执⾏映像中删除掉,减⼩程序的体积。
Removing os_mbox.o(.text), (1094 bytes).
Removing os_mutex.o(.text), (1744 bytes).
Removing os_sem.o(.text), (1016 bytes).
3、第三部分:Image Symbol Table
Local Symbols
符号表⾥的局部符号。
../../angel/boardlib.s 0x00000000 Number 0 boardinit1.o ABSOLUTE
./../angel/handlers.s 0x00000000 Number 0 __scatter_copy.o ABSOLUTE
../../angel/kernel.s 0x00000000 Number 0 kernel.o ABSOLUTE
../../angel/rt.s 0x00000000 Number 0 rt_raise.o ABSOLUTE
../../angel/scatter.s 0x00000000 Number 0 __scatter.o ABSOLUTE
../../angel/startup.s 0x00000000 Number 0 __main.o ABSOLUTE
../../angel/sys.s 0x00000000 Number 0 sys_exit.o ABSOLUTE
../../angel/sysapp.c 0x00000000 Number 0 sys_wrch.o ABSOLUTE
../../armsys.c 0x00000000 Number 0 _get_argv.o ABSOLUTE
../../division_7m.s 0x00000000 Number 0 rtudiv10.o ABSOLUTE
../../fpinit.s 0x00000000 Number 0 fpinit.o ABSOLUTE
.
./../heapalloc.c 0x00000000 Number 0 hrguard.o ABSOLUTE
../../printf.c 0x00000000 Number 0 _printf_outstr_char.o ABSOLUTE
../../signal.c 0x00000000 Number 0 defsig_exit.o ABSOLUTE
../../stdlib.c 0x00000000 Number 0 exit.o ABSOLUTE
../../stkheap.s 0x00000000 Number 0 heapext.o ABSOLUTE
以上是⼀些系统内部的局部符号,还有⽤户的⼀些局部符号
4、第四部分:Global Symbols
全局符号
_terminate_user_alloc - Undefined Weak Reference
_terminateio - Undefined Weak Reference
__Vectors 0x08000000 Data 4 stm32f10x_vector.o(RESET)
__main 0x08000131 Thumb Code 8 __main.o(main)
__scatterload 0x08000139 Thumb Code 0 __scatter.o(scatter)
__scatterload_rt2 0x08000139 Thumb Code 44 __scatter.o(scatter)
这些是⼀些系统的全局符号
Font8x16 0x08001a82 Data 2048 tft018.o(.constdata)
Font8x8 0x08002282 Data 2056 tft018.o(.constdata)
codeGB_16 0x08002a8a Data 770 tft018.o(.constdata)
Region$$Table$$Base 0x08002dc0 Number 0 anon$$obj.o(Region$$Table)
Region$$Table$$Limit 0x08002de0 Number 0 anon$$obj.o(Region$$Table)
后⾯这两个符号我认为很重要,在运⾏库代码将可执⾏映像从加载视图转变为可执⾏视图的过程中起到了关键作⽤。Number是指它并不占据程序空间,⽽只是⼀个具有⼀定数值的符号,类似于程序中⽤define和EQU定义的。所以这⾥,我先放下map⽂件的分析,先通过仿真调试,看这两个数值在程序
中怎么⽤。
果然,在刚开始执⾏程序时,R10和R11的值就已经被赋值成了这两个值。
很快就将0x08002dc0到0x08002dcf处的16个字节,4个双字加载到了R0-R3,我们可以分析⼀下⾥⾯的内容,R0就是程序加载视图的RW区的起始地址(0x08002de0),R1就是要输出的执⾏视图的RW区的地址(0x20000000),R2就是要复制的RW数据的个数,R3是复制函数 ( __scatterload_copy)的地址,类似于⼀个回调函数。接下来就要⽤了:0x0800011E 4718 BX r3这条指令去执⾏复制⼯作。
接下来⼜将0x08002dd0到0x08002ddf处的16个字节,4个双字加载到了R0-R3,我们可以分析⼀下⾥⾯的内容,R0就是程序加载视图的RW区的起始地址(0x08002de0+0x20=0x08002e00),R1就是要输
出的执⾏视图的RW区的地址(0x20000020),R2就是要复制的RW数据的个数,R3是ZI区域建⽴函数( __scatterload_zeroinit )的地址。
执⾏完成后,程序就会进⼊BL.W __rt_entry处进⾏库的初始化⼯作。
经过这么⼀分析,现在我对于程序的加载映像和执⾏映像有了较深的理解:程序的RO_Code加上RO_Data总共是0x2dc0这么⼤,地址范围0x0800,0000到0x8000,2dbf。然后在0x0800,2dc0-2dcf共16个字节放了RW加载映像地址(0x0800,2de0)、执⾏映像地址
(0x2000,0000)、RW长度(0x20)和将该段数据从加载映像复制到执⾏映像的函数地址。在0x0800,2dd0-2ddf共16个字节放了ZI加载映像地址(0x0800,2e00)、执⾏映像地址(0x2000,0020)、ZI长度(0x480)和建⽴ZI、HEAP和STACK执⾏映像的函数地址。
在上⾯的第⼆个阶段,将ZI清零阶段,程序的ZI长度实际上只有0x20,⽽库代码留出了0x60的长度。因此数据区的顶端为
0x2000,00a0-1。接下来从0x2000,00a0开始为堆的起始地址,堆长度加上程序栈长度为0x2000,04a0,这就是堆栈顶端,也是
__initial_SP的初始值。
程序进⼊_rt_entry后,还要对heapstack进⾏处理,但我没有看到有什么⽤的变化。从中对库留出的ZI数据区进⾏了⼀些处理,我暂时也看不明⽩。好了,调试就到这⾥,回到map⽂件分析的正途。
5、第五部分:
text函数什么意思Memory Map of the image
//映像的内存分布
Image Entry point : 0x080000ed
//程序的⼊⼝点:这⾥应该是RESET_Handler的地址
Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00002e00, Max: 0x00020000, ABSOLUTE)
//程序的加载映像地址和长度,2e00=2dc0(代码和常数)+0x20(Region Table是RW的加载和执⾏地址、ZI与HEAPSTACK的执⾏地址)+0x20(已经初始化的数据)。
Execution Region ER_IROM1 (Base: 0x08000000, Size: 0x00002de0, Max: 0x00020000, ABSOLUTE) //这段RO区域的加载映像和执⾏映像⼀致。
Base Addr Size Type Attr Idx E Section Name Object
0x08000000 0x000000ec Data RO 3 RESET stm32f10x.o
0x080000ec 0x00000008 Code RO 191 * main __main.o(c_w.l)
Execution Region RW_IRAM1 (Base: 0x20000000, Size: 0x000004a0, Max: 0x00005000, ABSOLUTE) //RW数据区 ZI数据区 Heap和Stack数据区。
Base Addr Size Type Attr Idx E Section Name Object
0x20000000 0x00000001 Data RW 100 .data tft018.o
0x20000040 0x00000060 Zero RW 212 .bss libspace.o(c_w.l)
0x200000a0 0x00000000 Zero RW 2 HEAP stm32f10x.o
0x200000a0 0x00000400 Zero RW 1 STACK stm32f10x.o
6、第六部分:Image component sizes
这是指出各个模块的输⼊节的⼤⼩
Code (inc. data) RO Data RW Data ZI Data Debug Object Name
972 58 0 10 32 2416 can.o
824 168 0 15 0 1791 candemo.o
928 88 0 0 0 4529 stm32_init.o
52 18 236 0 1024 2700 stm32f10x.o
1836 32 4874 1 0 8076 tft018.o
最后给出总长度:这个11744应该=0x2dc0,1184应该0x4a0。11776应该是=0x2e00。
Total RO Size (Code + RO Data) 11744 ( 11.47kB)
Total RW Size (RW Data + ZI Data) 1184 ( 1.16kB)
Total ROM Size (Code + RO Data + RW Data) 11776 ( 11.50kB)
⼆、总结
感觉经过这么分析⼀遍,对于嵌⼊式系统程序的静态结构和动态执⾏流程的了解⼜深⼊了⼀些,当然也还是有些问题并没有了解透彻:留待以后慢慢解决吧
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论