armlink 散列文件使用说明, FirstEntry.s堆栈,堆初始化基地址得到

转载于此地址:http://www.guiplus.com/html/60/t-260.html

 

 

一、基本概念
    一般而言,一个程序包括只读的代码段和可读写的数据段。只读的代码段和常量被称作RO段(ReadOnly);可读写的全局变量和静态变量被称作RW段(ReadWrite);RW段中要被初始化为零的变量被称为ZI段(ZeroInit)。对于嵌入式系统而言,程序映象都是存储在Flash存储器等一些非易失性器件中的,而在运行时,程序中的RW段必须重新装载到可读写的RAM中。这就涉及到程序的加载时域和运行时域。简单来说,程序的加载时域就是指程序烧入Flash中的状态,运行时域是指程序执行时的状态 。加载 时域和运行时域内容之间的影射关系可以通过 创建Scatterfile文本文件,通知连接器armlink把程序的某一部分连接在存储器的某个地址空间。需要指出的是,Scatterfile中的定义要按照系统重定向后的存储器分布情况进行。
    什么是arm的映像文件,arm映像文件其实就是可执行文件,包括bin或hex两种格式,可以直接烧到rom里执行。映像文件一般由域组成,域最多由三个输出段组成(RO,RW,ZI)组成,输出段又由输入段组成。在scatterfile中可以为每一个代码或数据区在装载和执行时指定不同的存储区域地址,所谓域,指的就是整个bin映像文件所处在的区域,Scatlertoading的存储区块可以分成二种类型:
装载域:当系统启动或加载时应用程序的存放区。
执行域:系统启动后,应用程序进行执行和数据访问的存储器区域,系统在实时运行时可以有一个或多个执行块。
映像中所有的代码和数据都有一个装载地址和运行地址(二者可能相同也可能不同,视具体情况而定)。在系统启动时,PrepareImageRegions()初始化代码会执行必要的复制及清零操作,使应用程序的相应代码和数据段从装载状态转入执行状态。     
    我们输入的代码,一般有代码部分和数据部分,这就是所谓的输入段,经过编译后就变成了bin文件中ro段和rw段,还有所谓的zi段,这就是输出段。对于加载域中的输出段,一般来说ro段后面紧跟着rw段,rw段后面紧跟着zi段。在运行域中这些输出段并不连续,但rw和zi一定是连着的。zi段和rw段中的数据其实可以是rw属性。
二:Scatterfile 结构:
Scatterfile 分成多个装载域,对于.net micro frameword分成三个装载域: LR_FLASH, LR_DAT, LR_CONFIG
每个装载域可以由多个执行域组成.
每个执行域可以由多个 分散加载描述文件 组成.所以分散加载描述文件是Scatterfile 最基本元素
下图列出他们在Microsoft .NET Micro Framework 4.0语法


分散加载描述文件说明

分散加载描述文件的属性:
1) RO-CODE
2) RO-DATA
3) RO,同时选择 RO-CODE 和 RO-DATA
4) RW-DATA
5) RW-CODE
6) RW,同时选择 RW-CODE 和 RW-DATA
7) ZI
8) ENTRY,即,包含 ENTRY 点的节。
可以识别以下同义词:
CODE 表示 RO-CODE
CONST 表示 RO-DATA
TEXT 表示 RO
DATA 表示 RW
BSS 表示 ZI。
可以识别以下伪属性:
FIRST
LAST
第一个和最后一个节
如果节位置顺序很重要(例如,如果特定输入节必须是
区中的第一个输入节,而包含校验和的输入节必须是最
后一个输入节),则可以使用 FIRST 和 LAST 标记执行区中
的第一个节和最后一个节。在一个执行区域,FIRST和LAST只能出现一次.

分散加载描述文件匹配属性:

1) * 与任何模块或库相匹配
2) *.obj 与任何对象模块相匹配
3) math.obj 与 math.obj 模块相匹配
4) *armlib* 与 ARM 提供的所有 C 库相匹配
5) *math.lib 与以 math.lib 结尾的任何库路径相匹配。



执行区域参数说明:

由4部分组成:分别介绍如下


1)Name="ER_%TARGETLOCATION%"  是命名执行区。
2)Base="%Code_BaseAddress%"  是基地址,如果是 绝对地址。区执行地址是由基址指示符指定的。
  如果是+offset 描述一个基址,该基址超出前一个执行区末尾 offset 个字节。offset 的值必须能被
  4 整除。如果前面没有执行区(即,这是加载区中的第一个执行区),则+offset 表示基址从该
  执行区所在的加载区的基址后面 offset 个字节开始。
3)属性:
(1)   ABSOLUTE 绝对地址。 区执行地址是由基址指示符指定的。
(2)   ALIGN alignment  将执行区的对齐约束从 4 增加到 alignment。 alignment 必须为 2 的正数幂。
        如果执行区具有 base_address,则必须为 alignment 对齐。如果执行区具有 +offset,则链接器
        将计算得到的区基 址与 alignment 边界对齐。
(3)   EMPTY 在执行区中保留一个给定长度的空白内存块, 通常供堆或堆栈使用。不能将任何节
        放置在具有 EMPTY 属性的区中。
(4)   FILL 创建一个链接器生成的区,其中包含一个值。如果指定 FILL,则必须为其赋值,
(5)   FIXED 固定地址。 链接器尝试通过插入填充使执行地 址等于加载地址。 这会使区成为根区。  
        如果这无法完成,则链接器会生成错误。
(6)   NOCOMPRESS 缺省情况下,将启用 RW 数据压缩。使用 NOCOMPRESS 关键字可以指定不
        能在最终映像中压缩执行区中的 RW 数据。
(7)   OVERLAY 用于具有重叠的地址范围的节。 将为具有OVERLAY 属性且基址偏移为 +0 的连续执行区指
        定相同的基址。 有关详细信息,请参阅《链接器用户指南》中第5-22 页的使用重叠区放置节。
(8)   PADVALUE 定义任何填充的值。 如果指定 PADVALUE,则必 须为其赋值,PADVALUE 必须为一个字大小。
        将忽略加载区中的PADVALUE 属性。
(9)   PI 此区仅包含与位置无关的节。
(10 ) UNINIT 用于创建包含未初始化的数据或内存映射的I/O 的执行区。
(11)  ZEROPAD 零初始化的节作为零填充块写入 ELF 文件,因此,运行时无需使用零进行填充。
        只有根执行区能够使用ZEROPAD 属性进行零初始化。 如果将 ZEROPAD 属性用于非根执行区,
        则会生成警告并忽略该属性。在某些情况下 (例如仿真),长时间的零循环是比较合适的。
4)最大值
   对于标记为 EMPTY 或 FILL 的执行区,max_size 值会解释为区的长
度。 在其他情况下,max_size 值会解释为执行区的最大 大小。

加载区描述

由4部分组成:分别介绍如下


1)Name="LR_%TARGETLOCATION%" 是命名加载区。
2)Base="%Code_BaseAddress%" 基地址:Code_BaseAddress指定要在其中链接加载区中对象的地址。
  Code_BaseAddress必须是字对齐的。
      如果是,"+offset "描述一个基址,该基址超出前一个加载区末尾 offset 个字节。offset 的值必须能被 4 整除。
      如果这是第一个加载区,则 +offset表示基址从零后面的 offset 个字节开始。
3)属性列表:
      (1) ABSOLUTE 绝对地址。 区的加载地址由基址指示符指定。
      (2) ALIGN alignment. 将加载区的对齐约束从 4 增加到 alignment。alignment 必须为 2 的正数幂。
           如果加载区具有base_address,则必须为 alignment 对齐。 如果加载区具有 +offset,则链接器
           将计算得到的区基址与 alignment 边界对齐。
      (3) NOCOMPRESS 缺省情况下,将启用 RW 数据压缩。使用NOCOMPRESS 关键字可以指定不
            能在最终映像中压缩加载区的内容。
      (4) OVERLAY 使用 OVERLAY 关键字可以使多个加载区位于同一个地址上。 ARM 工具没有提
           供重叠机制。 若要在同一地址使用多个加载区,必须提供自己的重叠区管理器。
      (5) PI 此区与位置无关。
      (6) RELOC 此区可重定位。
4)max_size 指定加载区的最大大小。 这是在进行任何解压缩或零初始化之前
            的加载区大小。 如果指定可选的 max_size 值,并且为区分配的字节
            数多于 max_size,则 armlink 会生成错误。
三:分散加载描述文件例子说明
  1)把FirstEntry.obj的RO连接到该装载区域的最开始
     < BR>     
                解析:
      Name="FirstEntry.obj"表示只对FirstEntry.obj目标文件
                        Options="(+RO, +FIRST)" 表示:因为属性的RO指定的是RO_CODE和RO_DATA,
                        FIRST指定的是连接到该装载区域的最开始

  2) 把所有SectionForBootstrapOperations指定的RO_CODE和RO_DATA连接到该区域  
    
    解析: 
    因为Name="*" ,表示的是所有的意思.
    因为属性: Options="(SectionForBootstrapOperations)"  表示节SectionForBootstrapOperations的意思.
    对于这种情况,如要把某函数定位在这里,则在定义函数如下
    void __section(SectionForBootstrapOperations) PrepareImageRegions()
    {
    }

  3) 把所有代码连接该区域
          < BR>     
                解析: 
    因为Name="*" ,表示的是所有的意思.
    因为属性: Options="(+RO-CODE)" 表示程序所有代码

  4)把所有常量的全局变量连接到区域(即由const 定义的全局变量.这些变量是不可修改的)
    
    解析: 
      因为Name="*" ,表示的是所有的意思.
      因为属性: Options="(+RO-DATA)" :RO-DATA表示程序所有全局常量
  5)把所有全局变量和静态变量连接到区域(即由非const 定义的全局变量.和static定义的全局/局部变量)                    
    解析: 
      因为Name="*" ,表示的是所有的意思.
      因为属性: ="( +RW-DATA, +ZI)"  :+RW-DATA表示非const 定义的全局变量;
            +ZI表示static定义的全局/局部变量

  6)把某目标连接到该区域的最后面.
    
     解析: 
      因为Name="tinyclr_dat.obj",表示把目标文件tinyclr_dat.obj.
      因为属性: Options="(+RO, +LAST)" RO表示RO_CODE和RO_DATA, LAST表示该区域的最后

四、Scatterfile 例子

该Scatterfile 有开头的宏定义和三个装载域组成(四种颜色表示).

黑色是宏定义:是真个系统rom和ram的分配配置定义。

绿色:是LR_RAM或LR_FLASH装载区域。由编译命令控制

兰色:是LR_DAT装载区域;由编译命令控制该装载区域是否存在。 该转载区域是托管代码

红色:是LR_CONFIG装载区域;由编译命令控制该装载区域是否存在。该转载区域是配置信息保存区域。(联想uboot保存参数sector)




   

   
   
   

   
   
   
   
   
   



   

           
        
          
        
        
                
        
        

        
            
                        
            
            
        

   


   

   
   


   
   



        
        
        
        

   


   

   
        
   


   

    < /FONT>< /FONT>

        < /FONT>< /FONT>

           
           < /FONT>< /FONT>

           
           
           
               
                             
            


        

        
        

        
            
            
            
            
            < /FONT>< /FONT>

           < /FONT>< /FONT>

            < /FONT>< /FONT>

            

               

            

            
        


        
            
        


        
            
        


        

        
            
        

        
        
           
        


        

        
         
        



        

        
            
        

        
        
            
        

  
        
           
                      
             
             
             
             
             
         
        

      
   





   

   

        

            

               
               
                < /FONT>

            


        


   





    < /FONT>

        < /FONT>

            < /FONT>

                < /FONT>

            


        


   








该例子说明:

1) 环境变量TARGETLOCATION说明:

如果执行 msbuild/t:build/p:memory=flash;flavor=release或debug .则 TARGETLOCATION=flash. 则LR_%TARGETLOCATION%就是LE_flash,整个编译结果输出是flash
如果执行msbuild/t:build/p:memory=ram;flavor=release或debug.则 TARGETLOCATION=ram. 则LR_%TARGETLOCATION%就是LE_ram,整个编译结果输出是RAM
2) 环境变量 Data_BaseAddress 说明
    控制LR_DAT区域的条件判断。如果编译命令是如msbuild/t:build/p:memory=flash;flavor=release或debug则该装载区域存在。
    控制LR_DAT区域的条件判断。如果编译命令是如msbuild/t:build/p:memory=ram;flavor=release或debug则该装载区域存在。
3) 环境变量Config_BaseAddress说明
     控制LR_CONFIG区域的条件判断。如果编译命令是如msbuild/t:build/p:memory=flash;flavor=release或debug则该装载区域存在。
    控制LR_CONFIG区域的条件判断。如果编译命令是如msbuild/t:build/p:memory=ram;flavor=release或debug则该装载区域存在。
4)  编译运行目标是RAM的特别说明:
    如果是msbuild/t:build/p:memory=ram;flavor=release或debug  编译输出目标是RAM。这是LR_DAT和LR_CONFIG是不存在的。而LR_DAT是托管代码区域。这样托管代码在哪里呢。注意在LR_RAM有下面定义(如果不是Flash)。则把托管代码连接到RAM中。
            
               
            


五、装载区域和执行区域访问参数。
          经过armlink连接后,每个装载区域和执行区域都存在基地址和长度。
方法一:armlink提供了下面的一些宏访问装载区域和执行区域:

对于执行区域:
Image$$region_name$$Base             得到该执行区域在ram中的基地址。红色部分就是执行区域名称
Image$$region_name$$Length          得到该执行区域的ro_code和ro_data的长度。红色部分就是执行区域名称
Image$$region_name$$ZI$$Length  得到该执行区域的rw_data的长度。红色部分就是执行区域名称
特别注意:整个可以执行区域长度为  Image$$region_name$$Length    + Image$$region_name$$ZI$$Length  
对于装载区域:
Load$$region_name$$Base     得到该装载区域在flash中的基地址。红色部分就是装载区域名称
Load$$region_name$$Length  得到该装载区域长度。红色部分就是装载区域名称
例如:定义了三个可以执行区域。这些区域分配给LCD作为显示缓存用。
   
      
   
   

              
      

              


要取得每段的基本地址值:通过下面宏实现
extern UINT32 Image$$ER_LCD_BUFFER_BASE$$Base;
extern UINT32 Image$$ER_TV_BUFFER_BASE$$Base;

#define GRAPHIC_OSD0_BASE (UINT32)(&(Image$$ER_LCD_BUFFER_BASE$$Base ))    //GRAPHIC_OSD0_BASE =0x6400000
#define GRAPHIC_OSD1_BASE (UINT32)(&(Image$$ER_TV_BUFFER_BASE$$Base ))      //GRAPHIC_OSD0_BASE =0x6800000

方法二:通过汇编定义变量到具体某区域实现,再通过该变量得到其基地址。

  
              SectionForLcdBuffer)" />
   
      
   
              SectionForTvBuffer)" />
   

      
红色部分就是该区域的section 名称。汇编有个特性可以指定变量或代码在具体section。
在某个汇编文件里定义如下
AREA SectionForLcdBuffer,    DATA
LcdBufferBase    DCD 0
AREA SectionForTvBuffer,    DATA
TvBufferBase    DCD 0
EXPORT LcdBufferBase
EXPORT TvBufferBase
在某个.c文件声明如下
extern int LcdBufferBase;
extern int TvBufferBase;
使用如下
UINT32 *srclcd=(UINT32 *)&LcdBufferBase;    // srclcd=0x6400000
UINT32 *srctv=(UINT32 *)&TvBufferBase;        // srctv=0x6800000
注意:对于Microsoft .NET Micro Framework 4.0的heap custom_heap stack。就是通过这种方法的得到他的地址
FirstEntry.s文件部份内容如下
定义如下:
AREA SectionForStackBottom,       DATA
StackBottom       DCD 0
    AREA SectionForStackTop,          DATA
StackTop          DCD 0
    AREA SectionForHeapBegin,         DATA
HeapBegin         DCD 0
    AREA SectionForHeapEnd,           DATA
HeapEnd           DCD 0
    AREA SectionForCustomHeapBegin,   DATA
CustomHeapBegin   DCD 0
    AREA SectionForCustomHeapEnd,     DATA
CustomHeapEnd     DCD 0
使用如下:
PreStackInit_Exit_Pointer
    ldr     r0, =StackTop               ; new SYS stack pointer for a full decrementing stack  得到StackTop变量所在地址值。
理解了Scatterfile ,就可以理解整个程序的组织价构。也就能理解系统运行环境。

梁仲宏 2009-9-18整理

你可能感兴趣的:(.NET,Micro,Framework,alignment,buffer,flash,image,microsoft,存储)