精华内容
下载资源
问答
  • MDK .map文件

    千次阅读 2017-07-12 15:27:21
    连接器(Linker)产生的map文件包含大量的关于“链接,定位”过程的信息。该map文件由一些单元组成。各个单元的详解如下。 1、Page Header 页头。map文件一般是文本格式的,一个map文件中会分成好多的页。每一页的...

    一、简介

    连接器(Linker)产生的map文件包含大量的关于“链接,定位”过程的信息。该map文件由一些单元组成。各个单元的详解如下。

    1Page Header

    页头。map文件一般是文本格式的,一个map文件中会分成好多的页。每一页的头部都包含链接器的版本号,链接日期,时间,以及页码。

    2Command Line

    这部分是:完整的用于调用linker的命令。这一这里显示的是命令行调用linker时的输入参数,格式等。

    3CPU Details

    关于所选择的CPUCPU模式,存储模式的信息。如果用到了浮点运算的话,这里也显示支持浮点库的信息。

    4DPP Registers

    DPP寄存器的值。NCONSTNDATA的位置。

    5Input Modules

    输入模块,包含在链接过程中要使用的所有的模块名,库函数名,以及链接最终要产生的模块的名称。

    6Interrupt Procedures

    中断程序,包含所有的中断服务程序。map文件中列出了中断处理函数名(function name),中断向量编号(interrupt vector number),中断向量名(interrupt vector name)。

    7Memory Map

    存储器映射表 列出了程序中所有的代码段的开始和结束地址starting and ending address,类型( type重定位类型(relocation type对齐方式(alignment, tgroup, 分组(group组合方式(combination type段类型(class单元名称(name of each section)等信息。

    8Group List

    组列表列出了包含在每个组(Group)中的单元(Section)。

    9Public Symbols

    公共符号列别列出了所有的公共符号的值(value),名称(name),表示形式(representation),任务组(tgroup),类(class),段名(section name)。

    10Symbol Table

    符号表包含了链接器输入模块中包含的符号的信息,包括符号的值(value),类型(type),表示形式(representation),长度(length),任务组(tgroup),名称等。

    11Cross Reference

    交叉引用 包含交叉引用的段名称和它的表示形式(representation (LABEL, VAR, CONST)),以及所属的任务组。还包括该段是在那个模块中定义的以及哪个模块访问了它。

    12Warnings and Errors

    Problems encountered while linking a program generate errors and warnings that are output to the screen and to the map file.

     

     

     

    二、文件分析流程

    1Section 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(可能是一个函数或变量)。

    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主函数。

    2Removing Unused input section from the image

    就是讲库中没有用到的函数从可执行映像中删除掉,减小程序体积。

    Removing os_mbox.o(.text), (1094 bytes).

    Removing os_mutex.o(.text), (1744 bytes).

    Removing os_sem.o(.text), (1016 bytes).

    3Image Symbol Table

    Local Symbols(局部符号)

       Symbol Name     Value       Ov Type   Size  Object(Section)

    ../../angel/boardlib.s0x00000000   Number0boardinit1.o ABSOLUTE

    ../../angel/handlers.s0x00000000   Number0__scatter_copy.o ABSOLUTE

    ../../angel/kernel.s0x00000000   Number kernel.o ABSOLUTE

    ../../angel/rt.s0x00000000   Number 0rt_raise.o ABSOLUTE

    ../../angel/scatter.s0x00000000   Number __scatter.o ABSOLUTE

    ../../angel/startup.s0x00000000   Number0 __main.o ABSOLUTE   

    ../../angel/sys.s0x00000000   Number0 sys_exit.o ABSOLUTE

    ../../angel/sysapp.c0x00000000   Number0 sys_wrch.o ABSOLUTE

    ../../armsys.c0x00000000   Number _get_argv.o ABSOLUTE

    ../../division_7m.s0x00000000   Number0rtudiv10.o ABSOLUTE

    ../../fpinit.s0x00000000   Number0fpinit.o ABSOLUTE

    ../../heapalloc.c0x00000000   Number0hrguard.o ABSOLUTE

    ../../printf.c0x00000000   Number_printf_outstr_char.o ABSOLUTE

    ../../signal.c0x00000000   Numberdefsig_exit.o ABSOLUTE

    ../../stdlib.c0x00000000   Numbe exit.o ABSOLUTE

    ../../stkheap.s0x00000000   Number       0heapext.o ABSOLUTE

    以上是一些系统内部的局部符号,还有用户的一些局部符号

    Global Symbols(全局符号)

       Symbol NameValueOv TypeSizeObject(Section)

        _terminate_user_alloc- UndefinedWeakReference

        _terminateio- UndefinedWeakReference

        __Vectors0x08000000Data4stm32f10x_vector.o(RESET)

        __main0x08000131 Thumb Code8__main.o(!!!main)

        __scatterload0x08000139Thumb Code0__scatter.o(!!!scatter)

       __scatterload_rt20x08000139Thumb Code44__scatter.o(!!!scatter)

    这些是一些系统的全局符号

     Font8x160x08001a82Data2048tft018.o(.constdata)

     Font8x80x08002282Data2056tft018.o(.constdata)

     codeGB_160x08002a8aData770tft018.o(.constdata)

    Region$$Table$$Base0x08002dc0Numberanon$$obj.o(Region$$Table)

    Region$$Table$$Limit0x08002de0Number0anon$$obj.o(Region$$Table)

    后面这两个符号我认为很重要。在运行库代码将可执行映像从加载视图转变为可执行视图的过程中起到了关键作用Number是指它并不占据程序空间,而只是一个具有一定数值的符号,类似于程序中用defineEQU定义的。所以这里,先通过仿真调试,看这两个数值在程序中怎么用。

     

    果然,在刚开始执行程序时,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,00000x0800,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文件分析的正途。

     

    4Memory 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 AddrSizeTypeAttr    IdxE Section NameObject

    0x080000000x000000ECDataRO       3RESETstm32f10x.o

    0x080000EC0x00000008CodeRO    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   AttrIdxE Section NameObject

    0x20000000   0x00000001   Data   RW100.datatft018.o

    0x20000040   0x00000060   Zero   RW212      .bsslibspace.o(c_w.l)

    0x200000a0   0x00000000   Zero   RW2         HEAPstm32f10x.o

    0x200000a0   0x00000400   Zero   RW1        STACKstm32f10x.o

    5Image component sizes

    这是指出各个模块的输入段的大小

    Code (inc. data)RO Data    RW Data    ZI Data      DebugObject Name

    97258010322416 can.o

    8241680            1501791candemo.o

    928880004529stm32_init.o

    5218236010242700stm32f10x.o

    18363248741 08076tft018.o

    最后给出总长度:这个11744应该=0x2dc01184应该0x4a011776应该是=0x2e00

    TotalROSize (Code + RO Data)11744 (11.47kB)

    TotalRWSize (RW Data + ZI Data) 1184 (1.16kB)

    TotalROMSize (Code + RO Data + RW Data)11776 (11.50kB)

     

    三、分散加载描述文件(Scatter Loading Description Files

    1 启动文件

    通常我们将处理器复位开始执行第一条指令到进入C语言的main( )函数之前执行的那段汇编代码称为启动代码。

    Ø 异常向量表定义:

    每当一个中断发生以后,ARM处理器便强制把PC指针置为向量表中对应中断类型的地址值。因为每个中断只占据向量表中1个字的存储空间,只能放置一条ARM指令,使程序跳转到存储器的其他地方,再执行中断处理。

    ARM芯片上电或复位后,系统进入管理模式、ARM状态、PC(R15寄存器)指向0x00000000地址处。中断向量表为每一个中断设置1个字的存储空间,存放一条跳转指令,通过这条指令使PC指针指向相应的中断服务程序入口,继而执行相应的中断处理程序。

    Ø 地址重映射及中断向量表的转移:

    ARM7处理器在复位后从地址0读取第一条指令并执行,因此系统上电后地址0必须是非易失的ROM/FLASH,这样才能保证处理器有正确可用的指令。为了加快对中断的处理以及实现在不同操作系统模式下对中断的处理,这就需要重新映射中断向量表、BootblockSRAM空间的一小部分。ARM具有非常灵活的存储器地址分配特性。ARM处理器的地址重映射机制有两种情况:

    ① 专门的寄存器完成重映射(Remap),只需对相应的Remap寄存器相应位设置即可。  

    ②  没有专门的Remap控制寄存器需要重新改写用于控制存储器起始地址的块(Bank)寄存器来实现Remap

    Ø 堆栈初始化:

    启动代码中各模式堆栈空间的设置是为中断处理和程序跳转时服务的。当系统响应中断或程序跳转时,需要将当前处理器的状态和部分重要参数保存在一段存储空间中,所以对每个模式都要进行堆栈初始化工作,给每个模式的SP定义一个堆栈基地址和堆栈的容量。堆栈的初始化有两种方法:第一种方法是结合ADS开发套件中的分散加载文件来定义堆栈。第二种方法是最简单也是最常用的一种就是直接进入对应的处理器模式,为SP寄存器指定相应的值。下面给出了用第二种方法初始化管理模式和中断模式堆栈的程序:  

    MSR CPSR_c, #0xD3         /切换到管理模式,并初始化管理模式的堆栈

    LDR SP, Stack_Svc 

    MSR CPSR_c, #0xD2       /切换到IRQ模式,并初始化IRQ模式的堆栈

    LDR SP,Stack_Irq 

    Ø 设置系统时钟频率以及切换工作模式:

    时钟是芯片各部分正常工作的基础,应该在进入main()函数前设置。

    Ø 存储器系统配置:

    主要是对系统存储器控制器(MMU)的初始化。由于存储器控制器并不是ARM架构的一部分,不同芯片商的实现不同。由于运算能力和寻址能力的强大,基于ARM内核烦人微处理器系统初始化都需要外扩展各种类型的出出气。初始化一般包括:

    一般包括存储器类型、时序可总线宽度的配置、存储器地址的配置。

    Ø 初始化应用程序的执行环境:

    一个ARM映像文件由RORWZI三个段组成。RO为代码段,RW是已初始化的全局变量,ZI是未初始化的全局变量。映像文件一开始总是存储在ROM/Flash里面的,其RO部分即可以在ROM/Flash里面执行,也可以转移到速度跟快的RAM中执行;而RWZI这两部分是必须转移到可写的RAM里去的。所谓应用程序执行环境的初始化,就是完成必要的从ROMRAM的数据传输和内容清0

    RWROM搬到RAM

    ZI所在的RAM区域全部清0,因为ZI并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来讲相应的RAM区清0

    Ø 进入main( )

    至此,系统各部分的初始化基本完成,可以直接从启动代码转入到应用程序的main()函数入口。从启动代码转入到应用程序的实例代码如下:  

    IMPORT main 

    LDR R0,=main 

    BX R0

    __main()是编译系统提供的一个函数,负责完成库函数的初始化和初始化应用程序执行环境,最后自动跳转到main()函数,有点像WIN32main函数。

     

     

    2ARM映像文件

    Section.text .data .bss .symtab

    Ø ELF格式文件

    ARM各种源文件(汇编、C/C++程序)经过ARM编译器编译后生成ELF格式的目标文件。这些目标文件和相应的C/C++运行时经过ARM链接器处理后,生成ELF格式的映像文件(image。这种ELF格式的映像文件可以被写入嵌入式设备的ROM中。

    ELF文件类型:

    可执行文件;

    可重定位文件(目标文件);

    共享object(共享库)。

    Ø ELF文件物理结构

    ARMIDE中:

    只读的代码段称为Code,即通常的.text

    只读的常量数据段,被称作RO Data,即通常的.const data

    以上两个统称为RO段(Read Only),存放在ROMFlash等非易失性器件中。

    可读可写初始化全局变量静态变量段,被称作RW段(Read  Write,即通常的.data段。

    可读可写未初始化全局变量静态变量段,被称作ZI,即通常的.bss。这个段的变量要初始化为0,故称作是ZI段。在运行时,RWZI段必须重新装载到可读可写的RAM中。

    RO

    Code

    .text

    只读的代码段

    RO-Data

    .const data

    只读的常量数据段

    RW

    RW-Data

    .data

    可读可写的初始化的全局变量和静态变量段

    ZI

    ZI-Data

    .bss

    可读可写的未初始化的全局变量和静态变量段

    Ø ARM映像文件是一个层次性结构的文件,其中包含域(region输出段(output section输入段(input section。各部分关系如下:

    一个映像文件至少由一个域组成;

    每个人域包含一个或多个输出段;

    每个输出段包含一个或多个输入段(RORWZI

    各输入段包含了目标文件中的代码和数据。

    输出段的属性与其包含的输入段的属性相同。各输出段的排列顺序由其属性决定。RO属性输出段排在最前,其次是RW属性输出段,最后是ZI属性输出段。一个域通常映射到一个物理存储器上,如ROMRAM等。

     

    3ARM映像文件的地址映射

    ARM映像文件各部分在存储系统中的地址有两种:

    一种是映像文件开始运行之前的地址(运行前输出段在ROM/RAM中的分布状态),称为加载地址加载域、装载域

    一种是映像文件运行时的地址(运行时输出段在ROM/RAM中的分布状态),称为运行地址运行域

    之所以存在2种地址,大多数情况下。映像文件在执行前把它装在到ROM中,而当前运行时域里的有些输出段必须复制到RAM中,程序才能正常运行。所以,在装载和运行时,有些段处在不同的位置(地址空间)。

     

    可以看出,映像文件中ZI段在装载域中是不存在的,在运行域里才建立的;映像文件运行时,第一件工作就是把RW输出段复制到RAM里的正确位置第二件工作是建立ZI输出段并初始化为0这就是应用程序执行环境的初始化这样,在运行时,代码和数据分布到了不同地址空间,形成三个运行域:RO运行域、RW运行域和ZI运行域。

     

    4ARM映像文件的入口点

    ARM映像文件的入口点位于ELF文件头部(描述文件的总体格式),ARM映像文件的入口点有2种类型:初始入口点initialentry  point)和普通入口点entry  point)。

    每个映像文件只有一个唯一的初始入口点,就是当程序运行时,要执行的第一条指令的地址。如果映像文件是被操作系统加载的,操作系统正式通过跳转到该初始入口点处执行来加载该映像文件。

    Ø 初始入口点条件

    通常ARM映像文件的初始入口点是在链接是生成的,所以在连接之前必须定义初始入口点。初始入口点必须满足2个条件:

    初始入口点必须位于映像文件的运行域内

    包含初始入口点的运行域不能被覆盖,即在加载地址和运行地址相同的区域内

    注意:所谓链接就是资源定位,目标文件和可执行文件的区别就在于是否有定址,即初始入口点。

    Ø 如何指定初始入口点

    在链接之前可以使用链接选项-entry address来指定映像文件的初始入口点。地址0x0处为ROM的嵌入式应用系统,可以使用-entry 0x0指定初始入口点

    当用户没有指定链接选项-entry address时,链接器根据下面的原则确定映像文件的初始入口点:

    如果输入目标文件中只有一个普通入口点,则该普通入口点被链接器当成映像文件的初始入口点。

    如果输入目标文件中普通入口点多于一个,或没有。则链接器生成的映像文件中不含初始入口点,并产生以下警告信息L6305WImage dose not have an entry point.(Not specified or not set duo to multiple choices)

    Ø 普通入口点

    普通入口点在汇编程序中用ENTRY伪操作定义。它通常用于标识该段代码是通过异常中断处理程序进入的一个映像文件中可以定义多个普通入口点。

     

    5 分散加载文件(scatter  file

    xxx.scf,链接时使用。它可以把用户的应用程序分割成多个RO运行域和RW运行域,并给他们指定不同的地址。在嵌入式系统中,Flash16RAM32RAM都可能存在于系统,所以不同功能的代码定位于特定的位置上会大大提高系统的运行效率。

     

    LOAD_ROM(加载域名称) 0x0000(加载域起始地址) 0x8000(加载域最大字节数)  

     { 

          EXEC_ROM(第一运行域名称) 0x0000(第一运行域起始地址) 0x8000(第一运行域最大字节数

          

              *(+RO (代码与只读数据) )       

          RAM(第二运行域名称) 0x10000(第二运行域起始地址) 0x6000(第二运行域最大字节数

          

              *(+RW(读写变量), +ZI(未初始化变量与初始化为0的变量)) 

          

    }

    Ø BNF符号与语法

    Ø 加载域(Load Region)描述

           称:为Linker确定不同加载区域   

        址:相对或绝对地址   

           性:可选   

    最大字节数:可选 

    运行域列:确定执行时各运行域的类型与位置 

    load_region_description ::= 

    load_region_name (base_address |("+" offset)) [attribute_list] [max_size] 

    "{" 

          execution_region_description+ 

    "}"

    load_region_name

    加载域名称

    最大有效字符数31。(并不像运行域段名用于

    Load$$region_name,而是仅仅用于表示加载区域)。 

    base_address

    加载域基地址

    按字对齐

    offset

    偏移量

    相对前一个加载区域的偏移量(4的整数倍

    attribute_list

    属性列表

    PI, RELOC, OVERLAY, ABSOLUTE

    max_size

    最大空间(字节单位)

    若加载区域的实际空间大于该指定值,则ARMLink报错

     

    Ø 执行域(Execution Region)描述

           称:为Linker确定不同运行域   

        址:相对或绝对地址   

           性:确定运行域的属性  

    最大字节数:可选 

         段:确定放在该运行域的模块

     execution_region_description ::=   

    exec_region_name (base_address | "+" offset) [attribute_list] [max_size]   

    "{" 

          input_section_description+ 

    "}" 

    exec_region_name

    执行域名称

    最大有效字符数31

    base_address

    执行域基地址

    按字对齐

    offset

    偏移量

    相对于前一个运行域结束地址的偏移量,4的整数倍;如果之前没有运行域(本运行域为该加载区域的第一个运行域),则该偏移量是相对于该加载域的基址偏移量。

    attribute_list

    属性列表

    PI, OVERLAY, ABSOLUTE, FIXED, UNINIT

    max_size

    最大空间(字节单位)

    若加载区域的实际空间大于该指定值,则ARMLink报错

    input_section_description

    输入段内容

     

    属性

    说明

    PI

    位置无关

    OVERLAY

    覆盖

    ABSOLUTE

    绝对地址(默认值)

    FIXED

    固定地址。表示装载地址与执行地址都是该固定地址。

    UNINIT

    未初始化数据。

    RELOC

    可重定位。无法明确指定执行域的属性,而只能通过继承前一个运行或父区域获得。

    注意:

    对于PIOVERLAYABSOLUTEFIXED,我们只能选择一个,缺省属性为ABSOLUTE

    一个运行域要么直接继承其前面的执行域的属性或者具有属性为ABSOLUTE PIOVERLAYRELOC属性的执行域允许其地址空间重叠,对于ABSOLUTEFIXED 属性运行域地址空间重叠ARMlink会报错。

     

    Ø 输入段(Input  section)描述

    模块选择形式:匹配方式可为:目标文件名,库成员名,库文件名,通配符。 

    输入段属性  RO(TEXT),RW(DATA),ZI(BSS),属性前必需加“+”。 

    输入段形式  :匹配方式可为:通配符”*”,”?”,输入段名称。

     input_section_description ::=  

     module_select_pattern ["(" 

      ("+" input_section_attr | input_section_pattern) 

      ([","] "+" input_section_attr | "," input_section_pattern))* 

    ")"]

    module_select_pattern

    模块选择形式。匹配方式可为:目标文件名,库成员名,库文件名,通配符”*”,”? (”*”匹配任意多个字符,”?”匹配任意一个字符,名称不区分字母大小写)。

    input_section_attr

    输入段属性

    (RO(TEXT),RW(DATA),ZI(BSS),FIRST,LAST)属性前必需加”+”。

    input_section_pattern

    输入段选择形式。匹配方式可为:通配符”*”,”?”,输入段名。


    1*libtx.a (+RO)  

    libtx.athreadX库文件。  

    2tx_ill.o (INIT) 

    tx_ill.othreadX中断向量目标文件。  

     3os_main_init.o (INIT ,+FIRST) 

    FIRST表示放于本运行域的开始处。   

     4*libtx.a (+RO) 

    RO 表示*libtx.a的只读部分。    

    5os_main_init.o (INIT ,+FIRST)   

    INIT os_main_init.o的一个段

    6os_stackheap.o (heap) 

           heap os_stackheap.o的一个段。    

    7os_stackheap.o (stack) 

     stackos_stackheap.o的一个段。


     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    附录:

    1ARM编译中的RORWZI DATA

    ARM程序(指在ARM系统中正在执行的程序,而非保存在ROM中的bin文件)的组成一个ARM程序包含3部分:RO段,RW段和ZI

    Code

    代码占用空间

    Flash中被占用空间是:

    Code+RO-Data+RW-Data

    RO-data

    Read-Only 只读常量

    RW-data

    Read-Write 可读写变量

    ZI-data

    Zero-Initialize 没初始化的可写可写变量

    RAM使用空间是:RW-Data+ZI-Data

    2ARM映像文件

    所谓ARM映像文件就是指烧录到ROM中的bin文件,也成为Image文件。以下用Image文件来称呼它。

    Image文件包含了RORW数据。之所以Image文件不包含ZI数据,是因为ZI数据都是0,没必要包含只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。

    3ARM的执行过程

    从以上两点可以知道,烧录到ROM中的Image文件与实际运行时的ARM程序之间并不是完全一样的。因此就有必要了解ARM程序是如何从ROM中的Image到达实际运行状态的。
    实际上,RO中的指令至少应该有这样的功能:

    Ø RWROM中搬到RAM因为RW是变量,变量不能存在ROM中。

    Ø ZI所在的RAM区域全部清零 因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来将相应得RAM区域清零。ZI中也是变量,同理变量不能存在ROM

    在程序运行的最初阶段,RO中的指令完成了这两项工作后C程序才能正常访问变量。否则只能运行不含变量的代码。

    注意:如果一个变量被初始化为0,则该变量的处理方法与未初始化华变量一样放在ZI区域。即:ARM C程序中,所有的未初始化变量都会被自动初始化为0

     

    4总结
    ① C中的指令以及常量被编译后是RO类型数据。
    ② C中的未被初始化或初始化为0的变量编译后是ZI类型数据。
    ③ C中的已被初始化成非0值的变量编译后市RW类型数据。
        ROM主要指:NAND FlashNor Flash
        RAM主要指:PSRAMSDRAMSRAMDDRAM
        简单的说就是在烧写完的时候是:FLASH中:Code+RO Data+RW Data,运行的时候:RAM: RW Data + ZI Data,当然还要有堆栈的空间。

    展开全文
  • KEIL MDK输出map文件分析   主要是各个源文件生成的模块之间相互引用的关系。   stm32f10x.o(STACK) refers (Special) to stkheap2.o(.text) for __use_two_region_memory   比如上面这句话...

    KEIL MDK输出map文件分析
     

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


     

    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)

    展开全文
  • MDK输出map文件分析

    2016-01-22 13:38:47
    MDK输出map文件分析   零、前言   前面写了一篇文章对__main函数的执行过程做了一个粗略的跟踪描叙,对一个烧录了程序的STM32开发板从启动复位到进入用户main函数的过程有了一个大概的了解,但是有很多...
    
    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.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)


     


     

    二、总结


     

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

     

    展开全文
  • KEIL MDK输出map文件分析

    千次阅读 2015-11-12 12:23:23
    标题:KEIL MDK输出map文件分析01   零、前言   前面写了一篇文章对__main函数的执行过程做了一个粗略的跟踪描叙,对一个烧录了程序的STM32开发板从启动复位到进入用户main函数的过程有了一个大概...

    标题: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)


     


     

    二、总结


     

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

    展开全文
  • MDK5之.map文件解析

    2021-06-18 09:47:19
    MDK5之.map文件解析前言一、.map文件总览二、详细介绍1、Section Cross References:模块、段(入口)交叉引用2、Removing Unused input sections from the image:移除未使用的模块3、Image Symbol Table:映射符号表...
  • Keil MDK输出map文件分析

    千次阅读 2018-05-08 16:30:07
    转自:http://kmoving.blog.163.com/blog/static/20504919720129241952437/一、文件分析流程1、第一部分:Section Cross References主要是各个源文件生成的模块之间相互引用的关系。stm32f10x.o(STACK) refers ...
  • 前言:   在写程序时经常会进行一些配置,比如开启关闭某些功能、修改一些常量等,会反复去修改配置文件。...  MDK在编译时 是怎们知道这是一个配置文件的呢?就需要用到文件的格式,开头和结尾。// <&
  • 基于MDK的分散加载文件

    千次阅读 2015-11-18 17:18:17
    分散加载文件
  • MDK---Keil生成.bin文件和hex文件

    万次阅读 2018-10-29 13:10:10
    一、Keil生成bin文件 1、右键工程名,选择:Option For Target"xxx" 或者直接点击魔术棒 2、选择User: 3、选择After Build/Rebuild下的 Run#1如上图所示 4、添加路径:"D:\keil for arm\ARM\...
  • MDK中配置生成bin文件的流程 一、 打开 Options for Target... 二、 选择User,将After Build/Rebuild 下的 这个 Run #1 打勾 三、 这个是最重要的部分,在Run #1 这行的空白部分写上路径。该处需要填写三...
  • 我们使用MDK5建立工程模板的时候,一般是通过参考已有的工程,从其他工程中复制我们所需要的文件或文件夹,其中就需要复制一个CMSIS文件夹,但是对于该文件夹是从哪里来的,有什么作用毫不清楚,对于初学者而言也许...
  • MDK文件类型
  • MDK的编译过程及文件类型全解

    千次阅读 2017-04-17 21:52:03
      本章参考资料:MDK的帮助手册《ARM ... Development Tools》,点击MDK界面的...关于ELF文件格式,参考配套资料里的《ELF文件格式》文件。 在本章中讲解了非常多的文件类型,学习时请跟着教程的节奏,打开实
  • MDK 的编译过程及文件类型全解

    千次阅读 2018-07-31 15:07:31
    出处:MDK 的编译过程及文件类型全解   MDK 的编译过程及文件类型全解 ------(在arm9的开发中,这些东西都是我们自己搞定的,但是在windows上,IDE帮我们做好了,了解这些对深入开发是很有帮助的,在有arm9开发...
  • stm32 开发环境MDK+库文件配置

    千次阅读 2016-08-30 21:10:59
    stm32 是一款arm cortex-m3 架构的芯片 结合库函数使用 可以更方便的实现各种功能 尤其是结合各种总线开发应用时 因为库函数已经封装很...stm32 的开发工具有很多MDK ADS AVR 等 我用的是MDk 其实就是可以编译arm的keil
  • 本文转载自:第48章 MDK的编译过程及文件类型全解—零死角玩转STM32-F429系列 1. MDK 相关文件 1.1 uvprojx 文件 uvprojx 文件就是我们平时双击打开的工程文件,它记录了整个工程的结构,如芯片类型、工程包含...
  • C语言编译步骤 1.预处理 gcc -E 2.编译 gcc -S 3.汇编 gcc -C 4.连接 gcc -l 复制代码 预处理 一般就是处理宏以及...将所有目标文件按照连接脚本的要求进行链接 在这个时候,什么代码段,数据段之类的就可以进...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,966
精华内容 2,386
关键字:

mdk对比文件