ARM基础知识 -- ELF映像文件

来源:互联网 发布:新闻视频下载软件 编辑:程序博客网 时间:2024/04/30 08:24

ARM映像文件

记录一些简单的ARM的映像文件的内容组成及原理。

1.ARM映像文件(axf和bin文件)的组成。

ARM是32位处理器,地址位宽也是32位,因此其存储器的映射范围可以达到4GB空间。基本上对于ARM处理器,上电或复位时都会从0x00000000出开始执行指令,因此必须保证映像文件的起始位置放置在0x00000000处,无论是采用NAND或NOR flash,这一点都无法改变。正确放置之后,处理器会获取到正确的指令从而顺序执行。

ARM的映像文件(即可执行文件)。生成的ARM映像文件有分为axf和bin两种。bin文件时真正的可执行文件,而axf文件是ARM特有的调试文件,除了包含了bin文件的内容外还包含了很多其他的调试信息。在axf的文件头和文件尾部都包含了可以用在ADW或AXF的load image的调试中。

2.ARM的映像文件的加载域和运行域的不同

加载域映像文件。尽量简单地说,即那些可执行文件例如bin文件,一般由域组成。而域由最多的三个输出段组成即(RO、RW、ZI),RO是只读的代码段,RW是可读写的数据段和ZI未初始化的数据段。分析bin映像文件的具体内容,也可以印证上面的内容,基本上在bin的前半部分是RO的内容而后半部分是RW的内容,ZI由于是为初始化数据,因此不需要保存在bin文件中。即bin文件时RO+RW的内容的集合。而这三个输出段又是可以由多个输入段组成的,因为在汇编文件中,可以设置多个段名称,只需要在链接的时候链接到相应的位置即可,因此多个输入段可以对应到一个输出段上。上面所说的bin文件都是指的是加载域的情况,因为这都是可执行文件被初始放置在flash中时各个部分的分布情况,即是加载到系统时的情况,所以叫加载域。但系统此时是并不能运行的。

加载域的映像文件必须顺利地过渡到运行时域,这时系统才能够正确地被执行。因为有个很明显的一点,程序一般都固化在flash中。而flash是只读的,上面也说到可读写的RW数据段的内容是跟在RO段后面(即bin文件中),被放置在了flash上,RW段要求可读写,flash显然不满足要求,因此加载域必须过渡到运行时域。最直观的理解就是,我们必须把RW段的内容转移到可读写的SDRAM或SRAM上去,因此就引发了运行域的问题。

如何转换,如何保证前面RO段的程序的内容能够正确地寻址到被转移了的RW段的内容。因为大部分汇编程序的转移指令都是绝对寻址的,比较少的伪指令能提供相对寻址,绝对寻址的效率显然比较高。因此我们必须在代码中就必须知道将来运行时RW段被放置在了什么一个地方。在程序链接之后,所有的代码中的地址都将固定。解决这样的问题也并不复杂,需要链接器确保RO段的运行时起始地址和RW段的运行时起始地址,这就是为什么我们要在ADS设置连接选项ro_base和rw_base的目的了。所有的RO段的地址都是基于ro_base指定的内容,而所有代码段的内容也是基于rw_base上的,这样程序在链接后就已经确定了所有的相对地址,剩下的事就是将相应的段的内容从加载域的位置搬移到运行时域的位置。

这样的代码搬移的工作如果是在调试状态的话,一般调试器就会帮我们做好所有事情了,而如果是在非调试状态,就需要我们自己复制代码段的搬移工作,有趣的是,不少ARM都支持从NAND flash中启动,而NAND flash本身就是不能直接执行的,需要将代码搬移到SDRAM中,因此这里的运行时域和加载域的区别被屏蔽掉了。一般我们做代码搬移这样的工作的时候,采用的跳转地址都要用相对跳转指令。这样的好处是,无论用户将程序加载到什么地址,代码搬移指令都能正确地将程序从加载域转换到运行时域,从而保证程序顺利执行。


1.ELF格式文件的结构

1.1 映像文件组成部分

    * 一个映像文件有一个或多个域组成
    * 每个域包含一个或多个输出段
    * 每个输出段包含一个或多个输入段
    * 各输入段中包含了目标文件中的代码和数据

    输入段中包含了四类内容:代码、已经初始化的数据、未经初始化的存储区域、内容初始化成0的存储区域。每个输入段有相应的属性,可以为只读的(RO)、可读写的(RW)以及初始化成0的(ZI)。ARM连接器根据个输入段的属性将这些输入段分组,再组成不同的输出段及域。

    一个输出段中包含了一系列的具有相同的RO、RW和ZI属性的输入段。输出段的属性与其中包含的输入段的属性相同。在一个输出段的内部,各输入段是按照一定的规则排序的,这将在1.3节油详细地介绍。

    一个域中包含1-3个输出段,其中个输出段的属性各不相同。各输出段的排列顺序是由其属性决定的。其中RO属性的输出段排在最前面,其次是RW属性的输出段,最后是ZI属性的输出段。一个域通常映射到一个物理存储器上,如ROM或RAM。

1.2 ARM映像文件各组成部分的地址影射

    ARM映像文件各组成部分在存储系统中的地址有两种:一种是映像文件位于存储器中时(也就是该映像文件运行之前)的地址,称之为加载地址;一种是映像文件运行时的地址,称之为运行时地址。之所以有这两种地址,是因为映像文件在运行时,其中的有些域是可以移动的新的存储区域。比如,已经初始化的RW属性的数据所在的段运行之前可能保存系统的ROM中,在运行时,他被移动至RAM中。

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

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

    根据映像文件中地址映射的复杂程度,有两种方法来告诉arm连接器这些相关信息。对于映像文件中地址映射关系比较简单的情况,可以使用命令行选项;对于映像文件中地址映射关系比较复杂的情况,可以使用一个配置文件。

2.arm映像文件的入口点

2.1 arm映像文件的入口点有两种类型:一种是映像文件运行时的入口点,称为初始入口点(initial entry point),另一种是普通入口点(entry point).

    初始入口点是映像文件运行时的入口点,每个映像文件只有一个唯一的初始入口点,它保存在ELF头文件中。如果映像文件是被操作系统加载的,操作系统是通过跳转到该初始入口点处来加载该映像文件。

    普通的入口点是在汇编中用ENTRY伪操作定义。他通常用于标志该段代码是通过异常中断处理程序进入的。这样连接器删除无用的段时不会将该段代码删除。一个映像文件中可以定义多个普通入口点。

    应该注意的是,初始入口点可以使普通入口点,但也可以不是普通入口点。

2.2定义初始入口点

    初始入口点必须满足下面两个条件:

    * 初始入口点必须位于映像文件的运行时域内。 
    * 饱含初始入口点的运行时域不能被覆盖,他的加载地址和运行地址必须是相同的。

    可以使用连接选项-entry address来指定映像文件的初始入口点。这时,address指定了映像文件的初始入口点的地址值。

    对于地址0x0处为rom的嵌入式应用系统,可以使用-entry 0x0来指定映像文件的初始入口点。这样当系统复位后,自动跳转到该入口开始执行。

    如果映像文件是被一个加载器加载的,该映像文件该映像文件必须包含一个初始化入口点。这种映像文件通常还包含了其他普通入口点,这些普通入口点一般为异常中断处理程序的入口地址。

    当用户没有指定-entry address时,连接器根据下面的规则决定映像文件的初始入口点。

    * 如果输入的目标文件中只有一个普通入口点,该普通入口点被连接器当成映像文件的初始入口点。

    * 如果输入的目标文件中没有一个普通入口点,或者其中的普通入口点多于一个,则连接器生成的映像文件中不包含初始入口点,并产生警告信息。

2.3普通入口点的用法

    普通入口点是在汇编中用ENTRY 伪操作定义。在嵌入式应用中,各异常中断的处理程序入口使用普通入口点标示。这样连接器在删除无用段时不会将该段代码删除。

    一个映像文件中可以定义多个普通入口点。没有指定连接选项-entry addres时,如果输入的目标文件中只有一个普通入口点,该入口点被连接器当成映像文件的初始入口点。

3 输入段的排序规则

    连接器根据输入段的属性来组织这些输入段,具有相同属性的输入段被放到域中一段连续的空间中,组成一个输出段。在一个输出段中,各输入段的起始地址与输出段的起始地址和该输出段中个输入段的排列顺序有关。

    通常情况下,一个输出段中个输入段的排列顺序由下面几个因素决定的。用户可以通过连接选项-first和-last来改变这些规则。

    * 输入段的属性。 
    * 输入段的名称 
    * 各输入段在连接命令行的输入段列表中的排列顺序

    按照输入段的属性,其排列顺序如下所示:

    * 只读的代码段 
    * 只读的数据段 
    * 可读写的代码段 
    * 其他已经初始化的数据段 
    * 未出世化的数据

    对于具有相同属性的输入段,按照其名称来排序。这是输入段名称是区分大小写的,按照其ASCII码顺序进行排序。

    对于具有相同属性和名城的输入段,按照其在输入段列表中的顺序进行排序。也就是说,几十个输入段的属性和名称保持不变,如果其在编译时,各输入段在输入段列表中的排列顺序不同,生成的映像文件也将不同。

    可以通过连接选项-first和-last来改变这些规则。如果连接时使用了配置文件,可以在配置文件中通过伪属性FIRST和LAST达到相同的效果。

    连接选项-first和-last不能改变根据输入段进行排序的规则,它只能改变根据输入段名称和其在输入列表中的顺序的排序规则。也就是说,如果使用-first指定

    一个输入段,只有该输入段所在的输出段位于运行时域的开始位置时,该输入段才能位于整个运行时域的开始位置。

    各个输入段排好顺序后,在确定各个输入段的起始地址之前,何以通过填充补丁是个输入段满足地址对齐的要求。

ARM连接器介绍

    ARM连接器armlink将编译得到的ELF格式文件以及相关的C/C++运行时库连接生成相应的结果文件。armlink可以完成下面的操作:

    * 连接编译后得到的目标文件相应的c/c++运行时库,生成可执行的影像文件。
    * 将一些目标文件进行连接,生成一个新的目标文件,供将来进一步连接时使用,这成为部分连接。 
    * 指定代码和数据在内存中的位置。 
    * 生成被连接文件的调试信息和相互间的引用信息。

    Armlink在进行部分连接和完全生成可执行文件时作进行的操作是不同的。下面分别介绍:

    (1)解析输入的目标文件之间的符号引用关系。
    (2)根据输入目标文件对c/c++函数的调用关系,从c/c++运行时库中提取相应模块。
    (3)将各个输入段排序,组成相应的输出段。
    (4)删除重复的调试信息。
    (5)根据用户指定的分组和定位信息,建立映像文件的地址映射关系。
    (6)重定位需要重定位的值。
    (7)生成可执行的映像文件。

    armlink在进行部分连接生成新的目标文件时执行下面的操作。

    (1)删除重复的调试信息
    (2)最小化符号表的大小
    (3)保留那些未被解析的符号
    (4)生成新的目标文件

    下面根据各armlink的命令行选项的功能分类列举了armlink的命令行选项,各选项的具体用法将在后面有详细地介绍。

    * 提供关于armlink的帮助信息 
    * 指定输出文件的名称和类型:*-output;*-partial;*-elf 
    * 使用选项文件,其中可以包含一些连接选项。 
    * 制定可执行映像文件的内存映射关系。*-rwpi;*-ropi;*-rw_base;*-ro_base;*-spit;*-scatter 
    * 控制可执行映射文件的内容。*-first;*-last 
    * 生成与映像文件的相关信息 
    * 控制armlink生成相关的诊断信息。

原创粉丝点击