KEIL MDK输出map文件分析01

发布者:ShiningSmile最新更新时间:2015-08-24 来源: eefocus关键字:KEIL  MDK  map文件 手机看文章 扫描二维码
随时随地手机看文章
前言

前面写了一篇文章对__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.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文件的分析,先通过仿真调试,看这两个数值在程序中怎么用。[page]

 

点击看大图

果然,在刚开始执行程序时,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、第五部分:


Memory Map of the image


 

//映像的内存分布


 

  Image Entry point : 0x080000ed


 

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

[page]
 

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


 

    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应该=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)


 

 


 

二、总结


 

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

关键字:KEIL  MDK  map文件 引用地址:KEIL MDK输出map文件分析01

上一篇:KEIL下分散加载文件的使用
下一篇:stm32 堆栈分配

推荐阅读最新更新时间:2024-03-16 14:29

STM32F0开发笔记8: 在keil中使用不初始化变量
我们进行程序设计的时候,都会知道,系统上电或复位时,会执行变量初始化操作,但是有些情况下,我们并不希望变量初始化,例如,在系统异常复位发生后,我们希望系统能够迅速恢复复位前的现场状况,这样就希望变量能够保留原先的值,而不被初始化。实际上,大家都知道,变量是存储在RAM中的,只要不掉电,变量的数值是不会改变的,只要我们不让系统进行初始化操作就可以了。 不同的编译环境,有不同的设置方法,本文介绍在Keil中设置不初始化变量的方法。在这里需要说明的是,网上介绍了许多的设置方法,但并不是所有的方法都起作用,本文将介绍一种最为直接的方法。 1、打开Options for Target对话框Linker标签,勾选掉Use Mem
[单片机]
STM32开发笔记40: Keil链接时”No section matches selector“解决方法
单片机型号:STM32F070F6P6 首先指明,此问题是STM32CubeMX升级时造成的,我现在STM32CubeMX的版本是4.27.0,原先的版本生成的程序在Keil中打开是不报错的。 这个问题是链接错误,仔细查看工程目录就可以看见4.27.0版本生成的程序,在工程目录中缺少启动的汇编文件startup_stm32f070x6.s,只需将此文件加载到工程中,再重新生成,此问题就可以解决。
[单片机]
KeilMDK-ARM)系列教程(八)_在线调试(Ⅰ)
Ⅰ、写在前面 Keil在线调试的内容有很多,本文带来在线调试常用的内容:Debug Toolbar调试工具栏(复位、全速运行、停止运行、单步调试、逐行调试、跳出调试、运行到光标行、跳转到暂停行、调试窗口)快捷按钮的详细内容。 Keil工具栏总共有三种:文件工具栏(File Toolbar)、编译工具栏(Build Toolbar)、调试工具栏(Debug Toolbar)。编译工具栏只在编辑模式有效,调试工具栏只在调试模式下有效。文件工具栏在两种模式下都有效。 文件工具栏可以参看文章:Keil(MDK-ARM)系列教程(二)_工具栏详细说明 本文内容已经整理成PDF文件,提供给大家下载: http://pan.ba
[单片机]
<font color='red'>Keil</font>(<font color='red'>MDK</font>-ARM)系列教程(八)_在线调试(Ⅰ)
单片机脚本语言移植lua到stm32MDK
Lua简单介绍 Lua 是一个小巧的脚本语言。作者是巴西人。该语言的设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。 Lua脚本能够非常easy的被C/C++ 代码调用,也能够反过来调用C/C++的函数,这使得Lua在应用程序中能够被广泛应用。不只作为扩展脚本,也能够作为普通的配置文件,取代XML,Ini等文件格式,而且更easy理解和维护。 Lua的目标是成为一个非常easy嵌入其他语言中使用的语言。大多数程序猿也觉得它的确做到了这一点。 非常多应用程序使用LUA作为自己的嵌入式脚本语言,以此来实现可配置性、可扩展性。这当中包含魔兽世界、博德之门、愤慨的小鸟、VOCALOID3 等。 单片机使用
[单片机]
KEIL FOR ARM 下LPC22xx的外部RAM用法
工作笔记: 调试外部RAM,我是在CS0上外扩了一个64K的RAM,也就是地址从0X80000000开始。开始不知道REALVIEW的设置,所以总是不能读写RAM,没有输出信号,在KEIL下要做如下设置。 一、在 Options for Target 'Targe 1' 下,选择Asm菜单,在 Conditional Assembly Control Symbols 下的输入框中填上EXTERNAL_MODE,然后按OK结束, 二、Startup.s这个文件也要做一定的改动。 EMC_SETUP EQU 1 ;使能外部RAM控制。 BCFG0_SETUP EQU
[单片机]
keil中 code、data、idata的区别
存储器类型   本C51编译器支持8051及其派生类型的结构能够访问8051的所有存储器空间具有下表列出的存储器类型的变量都可以被分配到某个特定的存储器空间。 存储器类型        描述 code        程序空间64 Kbytes ;通过MOVC @A+DPTR 访问 data        直接访问的内部数据存储器;访问速度最快128 bytes idata       间接访问的内部数据存储器 ;可以访问所有的内部存储器空间 256 bytes bdata       可位寻址的内部数据存储器;可以字节方式也可以位方式访问16bytes xdata       外部数据存储器64 Kbytes ;通过MOVX @D
[单片机]
面向51单片机的Keil uVision4的四种基本数据类型
在标准C语言中,存在着如下六种基本数据类型: 1、char:字符型; 2、short = short int:短整型 3、int:整型 4、long = long int:长整型 5、float:单精度浮点型 6、double:双精度浮点型 而面向51单片机的Keil uVision4对此进行了简化, 因此,可以理解为只存在如下四种基本数据类型: 1、char:字符型 2、int = short = short int:整型 3、long = long int:长整型 4、float = double:单精度浮点型 其中,基本整
[单片机]
Keil uVision4简单使用教程
首先,我们用 Keil 先打开一个现成的工程,来认识一下 Keil 软件,如图1-7所示。 图1-7 工程文件 从图1-7我们可以很轻松的分辨出菜单栏、工具栏、工程管理区、程序代码区和信息输出窗口。这个是 Keil4 的英文版,网上有一些汉化版本的,但不建议使用。即使你的英语不好,使用英文版本的软件也一点问题没有,刚开始大家先跟着我去使用,一共没几个单词,不需要你去翻译,用几次你就记住怎么用了。因为以后做实际开发的时候,大多数软件都是英文版的,如果现在学习的时候一直用中文软件,将来一旦换了其它的英文软件就会慌了,所以从现在开始,我们就慢慢的来熟悉英文软件,将来再用到其他英文软件的时候,就可以做到触类旁通、驾轻就熟了。 Keil
[单片机]
<font color='red'>Keil</font> uVision4简单使用教程
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved