c语言 什么是映像文件,ARM映像文件简介及简单的初始化C运行环境

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     /*如果r1STRCC    R2,[R1],#4     /*如果r1BCC      LOOP0             /*如果r1LOOP1       LDR      R1,=|Image$$ZI$$Limit| /* 取ZI段的结束地址 */

MOV      R2,#0

LOOP2       CMP      R3,R1

STRCC    R2,[R3],#4    /*如果r3BCC       LOOP2            /*如果r3B   Main   ; 跳转到C程序代码Main()函数

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值