我们编写的源文件(.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 段,并将其清零。为保证程序的正确执行,而进行必要的数据拷贝和清零,就是应用程序执行环境的初始化。
二、S3C2440启动的基本原理
Nand Flash启动
当S3C2440 开发板采用的是Nand Flash 启动,镜像一开始是存储在Nand Flash 中,而Nand Flash只能作为存储程序和数据之用,无法在其中运行程序,所以S3C2440 开发板启动代码中应用环境初始化这一步和上述步骤稍有不同。S3C2440 镜像文件加载和运行时的地址映射关系如下图所示:
S3C2440 没有上电之前映像文件存储在Nand Flash 中,Nand Flash 由专门的控制器控制,不占用存储器BANK。当开发板上电时,Nand Flash 的前4K 被复制到S3C2440 芯片内部的一块容量为4K 的SRAM(被称为“Steppingstone”),然后这块SRAM 被映射到地址0x00000000 处,程序从此处开始运行。因为Nand Flash 中不能运行程序,所以在这4K 的代码中必须包含一段代码将Nand Flash 中的程序拷贝至S3C2440 的SDRAM 中(0x30000000 开始)。应用环境初始化应该包含这段代码。
Nand Flash 中的映像文件被拷贝至从0x30000000 开始的SDRAM,这时候映像文件还没有真正被执行,此时是加载状态,加载域如上图所示,包括所有RO 属性的输出段和RW 属性的输出段,ZI 属性的输出段此时还不存在。在映像文件运行时,会生成3 个运行域,如上图所示,RO 和RW 属性的运行域的起始地址和加载时是相同的,所以在应用程序执行环境初始化中不需要对其进行拷贝,ZI 运行域则需要在映像开始被执行前建立并被初始化为0,所以应用程序执行环境初始化中也要包含这类代码。
Nor Flash启动
当S3C2440采用Nor Flash启动时,代码可以在上面直接运行。但为了运行的效率,还是把程序拷贝到SDRRAM中运行。加载时地址关系和运行时地址关系和Nand Flash的基本相似。Nand Flash启动时,会将RO段和RW段同时拷贝到SDRAM中,然后再建立ZI段。从Nor Flash启动时是先拷贝RO段,然后再拷贝RW段,最后建立ZI段。