KEIL MDK输出map文件分析

原作者:nthq2004

 

标题:KEIL MDK输出map文件分析01


 

零、前言


 

前面写了一篇文章对__main函数的执行过程做了一个粗略的跟踪描叙,对一个烧录了程序的STM32开发板从启动复位到进入用户main函数的过程有了一个大概的了解,但是有很多问题感觉还是模模糊糊,因此,今天又把KEIL MDK编译、链接后生成的map文件简单分析一下,加深对链接器、嵌入式系统可执行映像特点的了解。、


 

一、文件分析流程


 

1、第一部分:Section Cross References


 

主要是各个源文件生成的模块之间相互引用的关系。


 

stm32f10x.o(STACK) refers (Special) to stkheap2.o(.text) for __use_two_region_memory


 

比如上面这句话,stm32f10x.ostm32f10x.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文件的分析,先通过仿真调试,看这两个数值在程序中怎么用。


 


 

点击看大图


 


 


 

果然,在刚开始执行程序时,R10R11的值就已经被赋值成了这两个值。



 

点击看大图



 


 

很快就将0x08002dc00x08002dcf处的16个字节,4个双字加载到了R0-R3,我们可以分析一下里面的内容,R0就是程序加载视图的RW区的起始地址(0x08002de0),R1就是要输出的执行视图的RW区的地址(0x20000000),R2就是要复制的RW数据的个数,R3是复制函数__scatterload_copy)的地址,类似于一个回调函数。接下来就要用了:0x0800011E 4718  BX  r3这条指令去执行复制工作。


 

点击看大图


 

接下来又将0x08002dd00x08002ddf处的16个字节,4个双字加载到了R0-R3,我们可以分析一下里面的内容,R0就是程序加载视图的RW区的起始地址(0x08002de0+0x20=0x08002e00),R1就是要输出的执行视图的RW区的地址(0x20000020),R2就是要复制的RW数据的个数,R3ZI区域建立函数(__scatterload_zeroinit )的地址。


 


 

执行完成后,程序就会进入BL.W  __rt_entry处进行库的初始化工作。

经过这么一分析,现在我对于程序的加载映像和执行映像有了较深的理解:程序的RO_Code加上RO_Data总共是0x2dc0这么大,地址范围0x0800,00000x8000,2dbf。然后在0x0800,2dc0-2dcf16个字节放了RW加载映像地址(0x0800,2de0)、执行映像地址(0x2000,0000)RW长度(0x20)和将该段数据从加载映像复制到执行映像的函数地址。0x0800,2dd0-2ddf16个字节放了ZI加载映像地址(0x0800,2e00)、执行映像地址(0x2000,0020)ZI长度(0x480)和建立ZIHEAPSTACK执行映像的函数地址。


 

在上面的第二个阶段,将ZI清零阶段,程序的ZI长度实际上只有0x20,而库代码留出了0x60的长度。因此数据区的顶端为0x2000,00a0-1。接下来从0x2000,00a0开始为堆的起始地址,堆长度加上程序栈长度为0x2000,04a0,这就是堆栈顶端,也是__initial_SP的初始值。


 

程序进入_rt_entry后,还要对heapstack进行处理,但我没有看到有什么用的变化。从中对库留出的ZI数据区进行了一些处理,我暂时也看不明白。好了,调试就到这里,回到map文件分析的正途。


 

5、第五部分:


 

Memory Map of the image


 

//映像的内存分布


 

  Image Entry point : 0x080000ed


 

//程序的入口点:这里应该是RESET_Handler的地址


 

Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00002e00, Max: 0x00020000, ABSOLUTE)


 

//程序的加载映像地址和长度,2e00=2dc0(代码和常数)+0x20Region TableRW的加载和执行地址、ZIHEAPSTACK的执行地址)+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数据区 HeapStack数据区


 


 

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object


 

    0x20000000   0x00000001   Data   RW   100    .data              tft018.o


 

    x20000040   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应该=0x2dc01184应该0x4a011776应该是=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)


 


 

二、总结


 

感觉经过这么分析一遍,对于嵌入式系统程序的静态结构和动态执行流程的了解又深入了一些,当然也还是有些问题并没有了解透彻:留待以后慢慢解决吧。

 

  • 1
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
### 回答1: Keil MDK是一款嵌入式开发工具,它提供了丰富的功能和易用的界面,可以帮助开发人员进行嵌入式软件的开发和调试。其中的编辑器配色文件是指可以修改编辑器的颜色方案,以满足开发人员个性化的需求。 要修改Keil MDK编辑器的配色方案,首先需要打开Keil MDK软件,然后点击菜单栏中的"Options"选项,再选择"Fonts and Colors"。接着,在弹出的窗口中,可以看到各种不同语言的配色选项。 点击对应的语言选项,比如C、C++、ASM等,就可以设置该语言的配色方案。在配色方案窗口中,可以设置编辑器的前景色和背景色,以及关键字、注释、字符串等的颜色。通过选择不同的颜色,并进行预览,可以实时查看效果。还可以根据自己的喜好,调整配色方案的亮度、对比度等参数。 在选择配色方案后,点击"Apply"按钮,就可以将修改的配色方案应用到Keil MDK的编辑器中了。如果想要保存修改的配色方案,可以点击"Save"按钮,然后给配色方案命名,并保存到指定的位置。 通过修改Keil MDK编辑器的配色方案,可以使开发人员在编写代码时更加舒适和高效。不同的颜色搭配和亮度对比可以帮助开发人员更好地区分不同的代码元素,提高代码的可读性和可维护性。因此,根据个人喜好和需求,合理设置Keil MDK编辑器的配色方案是很重要的。 ### 回答2: Keil MDK(Microcontroller Development Kit)编辑器是一种常用的嵌入式开发工具,用于编写和调试嵌入式系统的程序代码。配色文件可以用来改变编辑器界面的颜色和外观,以提高开发者的舒适度和工作效率。 在Keil MDK编辑器中,我们可以根据自己的喜好和需求进行配色定制。一般而言,配色文件是以XML格式保存的,可以包含各种编辑器界面的颜色和样式设置。 要更改Keil MDK编辑器的配色,可以按照以下步骤进行: 1. 打开Keil MDK编辑器,并在菜单栏中选择“Options”(选项)。 2. 在弹出的对话框中,选择“Editor”(编辑器)选项。 3. 在编辑器选项中,可以找到“Colors”(颜色)选项。在这里,可以看到各种编辑器元素(如关键字、注释、字符串等)的配色设置。 4. 可以通过单击下拉菜单来选择不同的配色方案。通常,Keil MDK提供了一些预定义的配色方案,如“Classic”(经典)、“Dark”(暗黑)等。 5. 如果需要进行自定义配色,可以单击“Edit...”按钮来编辑配色方案。在弹出的对话框中,可以更改具体的颜色值和样式设置。 6. 编辑完成后,点击“OK”按钮保存并应用新的配色方案。 需要注意的是,更改配色文件可能需要重启Keil MDK编辑器才能生效。此外,Keil MDK还提供了其他一些编辑器设置,如字体、缩进、代码折叠等,可以根据个人习惯进行调整。 通过改变Keil MDK编辑器的配色文件,可以让开发者在编写和调试嵌入式程序时有一个更舒适和高效的工作环境。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值