Chinaunix首页 | 论坛 | 博客
  • 博客访问: 488119
  • 博文数量: 121
  • 博客积分: 4001
  • 博客等级: 上校
  • 技术积分: 1390
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-13 21:48
文章分类

全部博文(121)

文章存档

2011年(4)

2010年(11)

2009年(106)

我的朋友

分类: 嵌入式

2009-09-22 13:49:48

转载:http://kellycan.blogbus.com/logs/10962408.html

1.ARM映像文件

      ARM中的各种源文件(包括汇编文件,C语言程序及C++程序等)经过ARM编译器编译后生成ELF格式的目标文件。这些目标文件和相应的C/C++运行时用到的库经过ARM连接器处理后,生成ELF格式的映像文件(image),这种ELF格式的映像文件是一种可执行文件,可被写入嵌入式设备的ROM中。

      ARM映像文件的组成:ARM映像文件是一个层次性结构的文件,包括了域(region),输出段(output section)和输入段(input section)。

      一个映像文件由一个或者多个域组成;每个域最多由三个输出段组成组成;每个输出段又包含一个或者输入段;各输入端包含了目标文件中的代码和数据。

      所谓域,指的就是整个bin映像文件所处在的区域,它又分为加载域和运行域。加载域就是映像文件被静态存放的工作区域,一般来说flash里的整个bin文件所在的地址空间就是加载域,当然程序一般都不会放在flash里执行,一般都会搬到sdram里运行工作,它们在被搬到sdram里工作所处的地址空间就是运行域。

      我们输入的代码,一般有代码部分和数据部分,这就是所谓的输入段,每个输入段都有相应的属性,可以为只读(ro),可读写的(rw)以及初始化成0的(zi)。ARM连接器根据各输入段的属性将这些输入段分组,再组成对应属性的输出段。对于加载域中的输出段,一般来说ro段后面紧跟着rw段,rw段后面紧跟着zi段。在运行域中这些输出段并不连续,但rw和zi一定是连着的。zi段和rw段中的数据其实可以是rw属性。

      通常一个映像文件中包含若干个域,各个域又包含若干的输出段。ARM连接器就需要知道如下信息以决定生成相应的映像文件。

    *分组信息 :决定如何各将输入段组织成相应的输出段和域。
      *定位信息 :决定各个域在存储器空间中的起始地址。

      根据映像文件中地址映射的复杂程度有两种方法告诉ARM连接器这些相关的信息。

      (1)当映像文件中最多包含两个域,每个域最多有三个输出段时,可以使用连接器选项告诉连接器相关的地址映射关系。选项有-ropi,-rwpi,-ro_base,-rw_base,-split等。

      (2)当映像文件地址映射关系更复杂时,可以使用一个配置文件(分散加载文件)告诉连接器相关的地址映射关系。

2.简单的初始化用户程序的执行环境

      ARM映像文件一开始总是存储在ROM/Flash里面的,其RO部分既可以在ROM/Flash里面执行,也可以转移到速度更快的RAM中执行;而RW和ZI这两部分是必须转移到可写的RAM里去,其实RW包括ZI区域,ZI区域放的是未赋值的全局变量,RW 区域放的是已赋值(赋0除外)的全局变量。所谓应用程序执行环境的初始化,就是完成必要的从ROM到RAM的数据传输和内容清零。

      先介绍几个必要的符号,编译器使用下列符号来记录各段的起始和结束地址:
     |Image$$RO$$Base| :RO段起始地址
      |Image$$RO$$Limit| :RO段结束地址加1
     |Image$$RW$$Base| :RW段起始地址
      |Image$$RW$$Limit| :ZI段结束地址加1
     |Image$$ZI$$Base| :ZI段起始地址
      |Image$$ZI$$Limit| :ZI段结束地址加1
     这些符号的值是根据链接器中设置的中ro-base和rw-base的设置来计算的。 由于rw和zi相连,|Image$$ZI$$Base|就等于|Image$$RW$$Limit| .其它的值都是编译器自动计算出来的。我们还可以通过scatter文件更详细得指定各个输出段的工作地址。
      初始化用户执行环境主要是把ro、rw、zi三段拷贝到指定的位置。

     下面的程序是rw、zi段在运行域中的搬运过程:

                 IMPORT |Image$$RO$$Limit|   /*表示RO区末地址后面的地址,即RW数据源的起始地址*/
                 IMPORT |Image$$RW$$Base|    /*RW区在RAM里的执行区起始地址,也就是编译器选项RW_Base指定的地址*/
                 IMPORT |Image$$ZI$$Base|    /*ZI区在RAM里面的起始地址*/
                 IMPORT |Image$$ZI$$Limit|   /*ZI区在RAM里面的结束地址后面的一个地址*/

                 IMPORT Main   ; 声明C程序中的Main()函数

                 AREA Start,CODE,READONLY ; 声明代码段Start
                 ENTRY     ; 标识程序入口
                 CODE32     ; 声明32位ARM指令
  
Reset        LDR   SP,=0x40003F00

               ; 初始化C程序的运行环境
                 LDR      R0,=|Image$$RO$$Limit|    /* 取ROM区中数据段的首地址 */
                 LDR      R1,=|Image$$RW$$Base|   /* 取RAM区中RW段的目标首地址*/
                 LDR      R3,=|Image$$ZI$$Base|      /*取RAM区中ZI段的首地址 */
  
                CMP      R0,R1     /* 比较ROM区中数据段首地址和RAM区中RW段目标首地址*/
                BEQ      LOOP1     /*相等代表当前是在RAM中运行*/
LOOP0      CMP      R1,R3      /*不相等则和RAM区中ZI段的目标地址比较*/
                LDRCC    R2,[R0],#4     /*如果r1
               STRCC    R2,[R1],#4     /*如果r1
               BCC      LOOP0             /*如果r1

    
LOOP1       LDR      R1,=|Image$$ZI$$Limit| /* 取ZI段的结束地址 */
                MOV      R2,#0
LOOP2       CMP      R3,R1
                STRCC    R2,[R3],#4    /*如果r3

                BCC       LOOP2            /*如果r3                B   Main   ; 跳转到C程序代码Main()函数

阅读(1535) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~