ARM中的各种源文件(包含汇编文件,C言语程序及C++程序等)经过ARM编译器编译后生成ELF(Executable and linking format)格局的方针文件。这些方针文件和相应的C/C++运转 时用到的库经过ARM衔接器处理后,生成ELF格局的映像文件(image),这种ELF格局的映像文件是一种可履行文件,可被写入嵌入式设备的ROM 中。
bin文件是真实的可履行文件,axf文件是ARM的调试文件,除了包含bin的内容之外,还附加了其他的调试信息,这些调试信息加在可履行的二进制数据的前面,所以把axf文件写到ARM的指令履行地址(一般是0x0)将不能运转,因为在此地址前几十个字节的数据不是可履行的二进制数据,而是头部的调试信息;而bin文件正是去掉了调试信息的能够履行的“精华”部分。
ARM映像文件的组成:ARM映像文件是一个层次性结构的文件,包含了域(region),输出段(output section)和输入段(input section)。一个映像文件由一个或许多个域组成;每个域最多由三个输出段组成组成;每个输出段又包含一个或许多个输入段;各输入端包含了方针文件中的代码和数据。
相关术语:
1。域 (region):一个映象文件由一个或多个域组成。反过来说域是组成映象文件的最大的结构。所谓域,指的便是整个bin映像文件所在在的区域,它又分为加载域和运转域。加载域便是映像文件被静态寄存的作业区域,一般来说flash里的整个bin文件地点的地址空间便是加载域,当然程序一般都不会放在flash里履行,一般都会搬到sdram里运转作业,它们在被搬到sdram里作业所在的地址空间便是运转域。一个域一般映射到一个物理存储器上,如ROM和RAM等。
2。段(Section):一个域包含一个或多个输出段,一个输出段包含一个或多个输入段。咱们输入的代码,一般有代码部分和数据部分,这便是所谓的输入段,每个输入段都有相应的特点,能够为只读(ro),可读写的(rw)以及初始化成0的(zi)。
3。RO,RW,ZI:输入段中包含4类内容:代码、现已初始化的数据、未经初始化的存储区域、内容初始化为0的存储区域。每个输入段有相应的特点,能够为只读(RO)、可读写(RW)以及初始化为0的(ZI)。ARM衔接器依据各输入段的特点将这些输入段分组,再组成对应特点的输出段。关于加载域中的输出段,一般来说ro段后边紧跟着rw段,rw段后边紧跟着zi段。在运转域中这些输出段并不接连,但rw和zi一定是连着的。zi段和rw段中的数据其实能够是rw特点。
注:(1); C中的指令以及常量被编译后是RO类型数据。
(2); C中的未被初始化或初始化为0的变量编译后是ZI类型数据。
(3); C中的已被初始化成非0值的变量编译后市RW类型数据。
4。加载时地址:是映象文件坐落存储器(还没有运转,一般在ROM中)时的地址
5。运转时地址:是映象文件运转时的地址。
一般一个映像文件中包含若干个域,各个域又包含若干的输出段。ARM衔接器就需要知道如下信息以决议生成相应的映像文件。烧录到ROM中的image文件与实践运转时的ARM程序之间并不是彻底相同的。因而就有必要了解ARM程序是怎样从ROM中的image抵达实践运转状况的。
*分组信息 :决议怎样各将输入段组织成相应的输出段和域。
*定位信息 :决议各个域在存储器空间中的开始地址。
依据映像文件中地址映射的杂乱程度有两种办法告知ARM衔接器这些相关的信息。
(1)当映像文件中最多包含两个域,每个域最多有三个输出段时,能够运用衔接器选项告知衔接器相关的地址映射联系。选项有-ropi,-rwpi,-ro_base,-rw_base,-split等。
(2)当映像文件地址映射联系更杂乱时,能够运用一个配置文件(涣散加载文件)告知衔接器相关的地址映射联系。ARM映像文件
数据移动:
上面现已提到了RW段加载地址一般在ROM中,运转时需要被转移到RAM中。加载时状况的映象文件中的RO、RW和ZI的地址都是暂时的,他们在运转时要被BootLoader程序转移到真实的运转时地址。这个地址是衔接时设置的地址。这个问题很重要,假如在编译前没有正确的设置运转时地址,那么程序就不能被转移到正确的RAM地址中运转。
了解了以上内容,那么就能够翻开ADS1.2来看一下具体的设置。
翻开ADS的一个工程后,点击如下图所示的Debug Settings按钮翻开对话框。翻开Target Settings对话框后,在左面列表中挑选Linker选项。点击它下面的的ARM Linker。然后在右面的选项卡挑选Output选项卡。如下图所示。
看看ADS 开发文档ARMDeveloper suite 1.2 的ADS_CodeWarriorIDEGuide.pdf 怎样说的
RO Base This text field sets both the load address and execution address of the region containing the RO
section. If you do not enter a value, the value defaults to 0x8000.
意思是,这个文本框设置加载时地址和运转时地址。假如没有设置值,默许时0x8000。这个值将会对应ADS的预界说变量Image$$RO$$Base,指定了RO的base。这个变量能够被初始化程序IMP
依据上面的1,2可知,假如要烧写FLASH 那么RO Base 应该设置成ARM片选的FLASH 的首地址;假如要调试那么RO Base要设置成RAM地址。
RW Base 这个文本框设定包含RW和ZI输出段的运转时域地址。假如你在这儿输入一个值,衔接器创立一个包含两个运转时域的映象,这两个域是:
包含RO输出段的运转时域
包含RW和ZI输出段的运转时域
假如你输入了RW Base值而且挑选了Split image选项,衔接器创立的映象文件别离包含RW输出段和ZI输出段的装载时地址和运转时地址,并都由你输入的RW Base值指定。
关于简略衔接方法,当没有输入RW Base值时,映象文件包含一个加载时域和一个运转时域。这时,RO输出段、RW输出段、ZI输出段都包含在一个域中。当输入RW Base值时,映象文件包含两个运转时域,一个包含RO输出段,一个包含RW输出段和ZI输出段。当指定了-split选项时,映象文件又多包含两个加载时域,一个包含RO输出段,一个包含RW输出段和ZI输出段。
简略的初始化用户程序的履行环境
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 (在加载域中,是RW的开始地址)
|Image$$RW$$Base| :RW段开始地址 (在运转域中即运转的时分,是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段在运转域中的转移进程:
;Copy and paste RW da
ldr r0, =|Image$$RO$$Limit| /*取RO区末地址后边的地址,即RW数据源的开始地址*/
ldr r1, =|Image$$RW$$Base|/*取RW区在RAM里的履行区开始地址,即编译器选项RW_Base指定的地址*/
ldr r3, =|Image$$ZI$$Base|/*取ZI区在RAM里边的开始地址*/
;Zero init base => top of initialised da
cmp r0, r1 /* 比较ROM区中数据段首地址和RAM区中RW段方针首地址*/
beq %F2 /*持平代表当时现已是在RAM中运转*/(F表明after,B表明before,r0与r1持平则转跳)
/*B %F2表向前跳到标号为2的Lable处*/
1
cmp r1, r3 /*不持平则和RAM区中ZI段的方针地址比较*/
ldrcc r2, [r0], #4/*假如r1
ldr r1, =|Image$$ZI$$Limit| /* 取ZI段的完毕地址 */
mov r2, #0 /*将r2赋值为0*/
3
cmp r3, r1 ; Zero init
strcc r2, [r3], #4 /*假如r3