arm link 第一章

第一章 镜像结构

注意:本文章只针对,裸机开发.至于SysV,BPABI,BP的链接模型请参考《armlink_user_guide》

1.1 重要的概念

1.1.1 镜像的构成

编译器将源文件编译成中间文件。链接器将中间文件最终生成镜像文件。

在中间文件中,逻辑最小单元称为section。链接器将所有中间文件的section收集起来,然后按照一定的规则,进行重新组织。将具有相同属性的section,组织在一起,称为输出section。相应的,中间文件的section称为输入section。然后再将不同的输出section组织在一起,起个名字叫做region。

他们之间的关系如下图

在这里插入图片描述

下面分别介绍输入section,输出section,region和segment

  1. 输入section:输入section来自于中间文件。它含有代码,初始化数据或者描述信息。描述信息用于表示未被初始化的段或者镜像执行之前必须设置为0的段。输入section具有RO,RW,XO,ZI这样的属性。这些属性被armlink用于组织成region或者输出section

  2. 输出section:输出section其实是具有相同属性的输入section的集合,因此输出section的属性和输入section的属性相同。这些输入section被连续的放置于内存中。

  3. region:一个region最多包含四个不同属性的输出section。默认情况下,在region中的输出section根据属性进行排序。XO输出section总是第一个,接着是RO输出section,然后是RW输出section,最后是ZI输出section。通常一个region被映射成一个物理内存设备,例如ROM,RAM。可以使用scatter改变输出section的顺序。

  4. segment:等同于region,之所以叫segment是因为在arm elf标准中使用了这个术语。

注意:armlink的单个segment的最大值为2GB

RO——read only

RW——read write

ZI——zero initialized

XO——execute only

1.1.2 镜像的地址

在执行镜像之前,可能必须要把部分region移动到它的执行地址处,或者创建ZI输出section。例如,对于已经初始化的RW数据可能必须将其从ROM移动到RAM处。

这样就会导致一个镜像具有两种不同的内存视图:加载视图,执行视图

  1. 加载视图:描述了镜像执行之前的地址
  2. 执行视图:描述了镜像执行时的地址

当region的加载地址和执行地址一样时,称为root region

下图展示了这两者的区别。

在这里插入图片描述

1.2 三种简单的镜像结构

为了帮助理解上述概念,这里介绍三种简单镜像。

1.2.1 类型1

类型1:一个加载region,三个执行region。如下图所示:

在这里插入图片描述

为了指定ro的地址,可以使用命令行选项–ro_base.命令如下:

armlink --ro_base 0x8000

注意:0x8000是默认地址,因此在这个例子中,也可以不用指定

加载视图:这个唯一的加载region由RO和RW两个输出section组成。ZI输出section在加载视图中不存在,他是在执行之前创建的。

执行视图:由三个连续的执行region组成,他们分别包含RO,RW和ZI输出section。RO和RW的执行地址与加载地址一样,因此无需做任何移动。但是,ZI执行region必须在运行时创建。

使用--ro_base address指定RO region的加载和执行地址。

使用--zi_base address指定ZI region的执行地址。

包含XO的加载视图

如果一个镜像包含XO section。那么XO输出section就被放置于--ro_base指定的位置处。RO和RW则连续排在其后

包含XO的执行视图

如果一个镜像包含XO section,那么XO执行地址为--ro_base指定的地址处,RO,RW和ZI紧随其后

1.2.2 类型2

类型2:一个加载region,三个执行region。但是RW执行region的地址和RO的执行地址不连续。

如下图:

在这里插入图片描述

使用下面的命令创建这种类型的镜像:

armlink --ro_base 0x0 --rw_base 0xA000

加载视图:一个加载region,包含RO和RW输出section,且这两者连续放置。

执行视图:第一执行region包含RO输出section。第二个执行region包含RW和ZI输出section

第一个执行region和加载region地址相同,因此不需要移动。第二个执行regoin和加载region的地址不同,因此它需要进行搬运。ZI 执行region在运行时创建

使用--ro_base address指定RO输出section加载和执行地址。

使用--rw_base address指定RW输出section的执行地址。

使用--zi_base address指定ZI执行region的地址

含有XO region的加载视图

如果一个镜像含有XO section。那么XO section被放置在--ro_base指定的地址处。RO和RW则紧随其后

含有XO region的执行视图

如果一个镜像含有XO section。那么XO section的执行region放置在--ro_base指定的地址处。RO则紧随其后

如果使用了--xo_base address,那么XO 执行region被放置在这个指定的地址处

1.2.3 类型3

类型3:该类型类似于类型2,但是跟类型2不同的是,类型3的加载视图,被分隔成多个root region。如下图:

在这里插入图片描述

使用下面的命令,生成这种类型的镜像:

armlink --split --ro_base 0x8000  --rw_base 0xE000

加载视图:第一个 加载region 包含 RO输出section 。第二个 加载region 包含 RW输出section。

执行视图:第一个执行region包含RO 输出section,第二个执行region包含RW输出section。第三个执行region包含ZI输出section。

RO和RW输出section都是root region,因此不需要移动,只有ZI需要在运行时创建。

使用–split,将默认的单个加载region分隔开。

含有XO的加载视图

如果一个镜像含有XO section,则XO被放置在--ro_base 所在的地址处,RO和RW紧随其后

含有XO的执行视图

如果一个镜像含有XO section,则放置在--ro_base 所指的地址处。

如果你指定了--split选项,XO和RO被放置在第一个加载regioin中,RW和ZI执行region放在第二个加载region中

如果你指定了--xo_base,XO的执行地址则是此处指定的地址。

本章完,下章,scatter文件语法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章