S3C2440启动代码中应用程序执行环境的初始化
2016-03-03 来源:eefocus
一、基础知识
我们编写的源文件(.c 或.s)经过ARM 编译器的编译生成ELF 格式的目标文件(后缀名为.o),目标文件经过ARM 连接器连接以后生成ELF 格式的映像文件(后缀名为.axf),此时的映像文件还包含一些调试信息,我们还需要通过fromelf 工具将其转换成适合在ROM 或RAM 中运行的二进制代码(后缀名为.bin),这时生成的二进制映像文件就可以被烧写入目标板的ROM 或FLASH 中,当目标板上电后可以通过各种方式在ROM 或RAM 中运行。
一个可执行程序的映像文件由一个或多个域组成,域分为两种:一种是映像文件在存储器中存放的地址,称为加载域;另一种是映像文件运行时的地址,称为运行域。每个域由一个或3 个输出段组成,每个输出段则由一个或多个输入段组成。输入段包含程序代码、已经初始化的数据、未经初始化的存储区、被初始化为0 的存储区,输入段据此可分为三种属性:RO(只读,包括代码和常量)、RW(可读可写,包括已经初始化的全局变量和静态变量)、ZI(未初始化的变量,需初始化为0), 连接器根据属性将输入段分组,组成不同的输出段。一个输出段是有具有相同属性的输入段组成的,输出段的属性与其中输入段的属性相同,因而输出段也分为三种。域由不同属性的输出段组成,输出段在域中的排列顺序为RO 输出段排在最前,然后是RW 输出段,RW 输出段和RO 输出段可以不连续,最后是ZI 输出段,ZI 输出段是紧接着RW 输出段的(加载域只包含RO、RW 输出段,原因见后述)。
可执行镜像一开始一般是存储在系统的ROM 或FLASH 中,RO 段是只读的,在运行的时候我们不能改变它,所以RO 段在运行的时候可以驻留在ROM 或FLASH 中,也可以拷贝到运行速度更快的RAM 中;RW 段在运行的时候,我们需要对其读写,在运行前这一段必须被拷贝至RAM 中;ZI 段为未初始化的全局变量段,只需要在程序运行之前建立ZI 并将其所在区域全部清零即可,因此镜像装载域不必包含ZI 输出段,但在运行域需要包含ZI,并且ZI 必须处于RAM。
通过以上说明,我们知道如果某个镜像只有RO 段的话,程序可以不必拷贝至RAM,但是如果程序包含RW 段的话,RW 段是必需要拷贝至RAM 中的,如果有必要的话还需在RAM 中创建ZI 段,并将其清零。为保证程序的正确执行,而进行必要的数据拷贝和清零,就是应用程序执行环境的初始化。
view plain copy
print?
- ;一个arm 程序是由R0,RW,ZI 三个段组成。其中R0 为代码段,RW 是已经初始化的全局变量,ZI 是未
- ;初始化的全局变量,启动代码要将RO段和RW段复制到RAM 中并将ZI 段清零。编译器使用下列变量
- ;来记录各段的起始地址和结束地址。这些标号的值是通过编译器的设定来确定的如ADS中对ro-base 和
- ;rw-base 的设定。
- IMPORT |Image$RO$Base| ; Base of ROM code
- IMPORT |Image$RO$Limit| ; End of ROM code (=start of ROM data)
- IMPORT |Image$RW$Base| ; Base of RAM to initialise
- IMPORT |Image$ZI$Base| ; Base and limit of area
- IMPORT |Image$ZI$Limit| ; to zero initialise
- ;===========================================================
- ldr r0, =BWSCON
- ldr r0, [r0]
- ands r0, r0, #6 ;通过判断OM[1:0] != 0, 得知是NOR FLash boot
- bne copy_proc_beg ;不用读取 nand flash
- adr r0, ResetEntry ;OM[1:0] == 0, 从NAND FLash 启动
- cmp r0, #0 ;再比较入口是否为0地址处,如果不是则用了仿真器
- bne copy_proc_beg ;用仿真器的情况也不要用 nand flash启动
- ;nop
- ;===========================================================
- nand_boot_beg ;这一段代码完成从NAND读代码到RAM
- [ {TRUE}
- bl RdNF2SDRAM
- ]
- ldr pc, =copy_proc_beg ;此时的PC已经在0x30000000以后,是copy_proc_beg连接时的地址
- ;这个标号下面的代码完成的功能就是把nor flash 的内容拷贝到ram 当中。
- ;===========================================================
- copy_proc_beg
- adr r0, ResetEntry ;装载地址,ResetEntry值->r0
- ldr r2, BaseOfROM ;BaseOfROM值
- cmp r0, r2 ;比较RO,R2
- ldreq r0, TopOfROM ;如果相等的话(说明在内存中运行),TopOfROM->r0 当从Nand Flash中启动时r0=r2,当从Nor Flash启动时则不相等
- beq InitRam ;同时跳到InitRam
- ;下面这个是针对代码在NOR FLASH时的拷贝方法
- ;功能为把从ResetEntry起,TopOfROM-BaseOfROM大小的数据拷到BaseOfROM
- ;TopOfROM和BaseOfROM为|Image$RO$Limit|和|Image$RO$Base|
- ;|Image$RO$Limit|和|Image$RO$Base|由连接器生成为生成的代码的代码段运行时的起启和终止地址
- ;BaseOfBSS和BaseOfZero为|Image$RW$Base|和|Image$ZI$Base|
- ;|Image$RW$Base|和|Image$ZI$Base|也是由连接器生成,两者之间就是初始化数据的存放地放
- ldr r3, TopOfROM
- 0
- ldmia r0!, {r4-r7}
- stmia r2!, {r4-r7}
- cmp r2, r3
- bcc %B0
- sub r2, r2, r3 ;这两句代码是修正字非对齐的情况,因为是按4个字节拷贝的,但RO段大小不一定是4个字节对齐的
- sub r0, r0, r2
- InitRam
- ldr r2, BaseOfBSS
- ldr r3, BaseOfZero
- 0
- cmp r2, r3
- ldrcc r1, [r0], #4
- strcc r1, [r2], #4
- bcc %B0 ;这一段是对ResetEntry 里面定义好的数据拷贝到RW 段。
- mov r0, #0
- ldr r3, EndOfBSS
- 1
- cmp r2, r3
- strcc r0, [r2], #4
- bcc %B1 ;初始化ZI段
- ldr pc, =%F2 ;goto compiler address
- 2
- ; [ CLKDIV_VAL>1 ; means Fclk:Hclk is not 1:1.
- ; bl MMU_SetAsyncBusMode
- ; |
- ; bl MMU_SetFastBusMode ; default value.
- ; ]
- [ :LNOT:THUMBCODE
- bl Main ;不要用main()因为main()是ADS默认入口,编译器会添加其他代码
- b . ;跳转到Main不成功则挂起
- ]
- [ THUMBCODE ;for start-up code for Thumb mode
- orr lr,pc,#1
- bx lr
- CODE16
- bl Main ;Do not use main() because ......
- b .
- CODE32
- ]
- BaseOfROM DCD |Image$RO$Base|
- TopOfROM DCD |Image$RO$Limit|
- BaseOfBSS DCD |Image$RW$Base|
- BaseOfZero DCD |Image$ZI$Base|
- EndOfBSS DCD |Image$ZI$Limit|
进入单片机查看更多内容>>
上一篇:详解ARM9的CPSR寄存器
相关文章