设为首页 加入收藏

TOP

3.2.4 区与重定位
2013-10-12 06:49:11 来源: 作者: 【 】 浏览:86
Tags:3.2.4 定位

3.2.4 区与重定位

区(Section)(也称为段、节或部分)用于表示一个地址范围,操作系统将会以相同的方式对待和处理在该地址范围中的数据信息。例如,可以有一个"只读"的区,只能从该区中读取数据而不能写入。区的概念主要用来表示编译器生成的目标文件(或可执行程序)中不同的信息区域,例如目标文件中的正文区或数据区。若要正确理解和编制一个as汇编语言程序,我们就需要了解as产生的输出目标文件的格式安排。有关Linux 0.12内核使用的a.out格式目标文件格式的详细说明将在本章后面给出,这里首先对区的基本概念作一简单介绍,以理解as汇编器产生的目标文件基本结构。

链接器ld会把输入的目标文件中的内容按照一定规律组合生成一个可执行程序。当as汇编器输出一个目标文件时,该目标文件中的代码被默认设置成从地址0开始。此后ld将会在链接过程中为不同目标文件中的各个部分分配不同的最终地址位置。ld会把程序中的字节块移动到程序运行时的地址处。这些块是作为固定单元进行移动的。它们的长度以及字节次序都不会被改变。这样的固定单元就被称做区(或段、部分)。而为区分配运行时刻的地址的操作就被称为重定位(Relocation)操作,其中包括调整目标文件中记录的地址,从而让它们对应到恰当的运行时刻地址上。

as汇编器输出产生的目标文件中至少具有3个区,分别被称为正文(text)、数据(data)和bss区。每个区都可能是空的。如果没有使用汇编命令把输出放置在.text或.data区中,这些区会仍然存在,但内容是空的。在一个目标文件中,其text区从地址0开始,随后是data区,再后面是bss区。

当一个区被重定位时,为了让链接器ld知道哪些数据会发生变化以及如何修改这些数据,as汇编器也会往目标文件中写入所需要的重定位信息。为了执行重定位操作,在每次涉及目标文件中的一个地址时,ld必须知道:

目标文件中对一个地址的引用是从什么地方算起的?

该引用的字节长度是多少?

该地址引用的是哪个区?(地址)-(区的开始地址)的值等于多少?

对地址的引用与指令计数器PC相关吗?

实际上,as使用的所有地址都可表示为:(区)+(区中偏移)。另外,as计算的大多数表达式都有这种与区相关的特性。在下面说明中,我们使用记号"{secname N}"来表示区secname中偏移N。

除了text、data和bss区,我们还需要了解绝对地址区(absolute区)。当链接器把各个目标文件组合在一起时,absolute区中的地址将始终不变。例如,ld会把地址{absolute 0}"重定位"到运行时刻地址0处。尽管链接器在链接后决不会把两个目标文件中的data区安排成重叠地址处,但是目标文件中的absolute区必会重叠而覆盖。

另外,还有一种名为"未定义的"区(Undefined Section)。在汇编时不能确定所在区的任何地址都被设置成{undefined U},其中U将会在以后填上。因为数值总是有定义的,所以出现未定义地址的唯一途径仅涉及未定义的符号。对一个称为公共块(Common Block)的引用就是这样一种符号:在汇编时它的值未知,因此它在undefined区中。

类似地,区名也用于描述已链接程序中区的组。链接器ld会把程序所有目标文件中的text区放在相邻的地址处。我们习惯上所说的程序的text区实际上是指其所有目标文件text区组合构成的整个地址区域。对程序中data和bss区的理解也同样如此。

1.链接器涉及的区

链接器ld只涉及如下4类区:

text区、data区。这两个区用于保存程序。as和ld会分别独立而同等地对待它们。对其中text区的描述也同样适合于data区。然而当程序在运行时,通常text区是不会改变的。text区通常会被进程共享,其中含有指令代码和常数等内容。程序运行时data区的内容通常是会变化的,例如,C变量一般就存放在data区中。

bss区。在程序开始运行时这个区中含有0值字节。该区用于存放未初始化的变量或作为公共变量存储空间。虽然程序每个目标文件bss区的长度信息很重要,但是由于该区中存放的是0值字节,因此无须在目标文件中保存bss区。设置bss区的目的就是为了从目标文件中明确地排除0值字节。

absolute区。该区的地址0总是"重定位"到运行时刻地址0处。如果你不想让ld在重定位操作时改变你所引用的地址,那么就使用这个区。从这种观点来看,我们可以把绝对地址称做"不可重定位的",即在重定位操作期间它们不会改变。

undefined区。对不在先前所述各个区中对象的地址引用都属于本区。

图3-2中是3个理想化的可重定位区的例子。这个例子使用传统的区名称:.text和.data。其中水平轴表示内存地址。后面小节中将会详细说明ld链接器的具体操作过程。

(点击查看大图)图3-2 链接两个目标文件产生已链接程序的例子

2.子区

汇编取得的字节数据通常位于text或data区中。有时候在汇编源程序某个区中可能分布着一些不相邻的数据组,但是你可能会想让它们在汇编后聚集在一起存放。as汇编器允许你利用子区(Subsection)来达到这个目的。在每个区中,可以有编号为0~8192的子区存在。编制在同一个子区中的对象会在目标文件中与该子区中其他对象放在一起。例如,编译器可能想把常数存放在text区中,但是不想让这些常数散布在被汇编的整个程序中。在这种情况下,编译器就可以在每个会输出的代码区之前使用.text 0子区,并且在每组会输出的常数之前使用.text 1子区。

使用子区是可选的。如果没有使用子区,那么所有对象都会被放在子区0中。子区会以其从小到大的编号顺序出现在目标文件中,但是目标文件中并不包含表示子区的任何信息。处理目标文件的ld以及其他程序并不会看到子区的踪迹,它们只会看到由所有text子区组成的text区和由所有data子区组成的data区。为了指定随后的语句被汇编到哪个子区中,可在".text表达式"或".data表达式"中使用数值参数。表达式结果应该是绝对值。如果只指定了.text,那么就会默认使用.text 0。同样地,.data表示使用.data 0。

每个区都有一个位置计数器(Location Counter),它会对每个汇编进该区的字节进行计数。由于子区是仅供as汇编器使用方便而设置的,因此并不存在子区计数器。虽然没有什么直接操作一个位置计数器的方法,但是汇编命令.align可以改变其值,并且任何标号定义都会取用位置计数器的当前值。正在执行语句汇编处理的区的位置计数器被称为当前活动计数器。

3.bss区

bss区用于存储局部公共变量。你可以在bss区中分配空间,但是在程序运行之前不能在其中放置数据。因为当程序刚开始执行时,bss区中所有字节内容都将被清零。.lcomm汇编命令用于在bss区中定义一个符号;.comm可用于在bss区中声明一个公共符号。


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇3.2.7 编写16位代码 下一篇3.2.6 as汇编命令

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: