4.2 程序的启动
相信各位同学已经编写了不少高级语言的程序,我们可以理解自己编写代码的含义,但是计算机是如何理解并准确无误地执行我们的代码的。这一过程并不是一个启动按钮,或是一行指令。
实际上,程序的启动是一个相当复杂的过程,对于C语言而言,涉及了四个相对独立的功能模块,分别是:编译器(Compiler),汇编器(Assembler),链接器(Linker),加载器(Loader)。他们按照一定的次序工作,上一层的输出产物成为下一层的输入,逐步将程序转换成与实际计算机系统硬件相关的,计算机可以理解执行的程序(C.A.L.L.过程)。如下图所示:
- 为了确定文件类型UNIX使用文件的后缀,
x.c表示C源文件,x.s表示汇编文件,x.o表示目标文件,x.a表示静态链接库,x.so表示动态链接库。默认情况下,a.out表示可执行文件。 - MS-DOS使用
.C, .ASM, .OBJ, .LIB, .DLL, .EXE来完成相同功能。
4.2.1 代码编译
编译器将C程序转换成一种机器可以理解的符号形式的汇编语言程序,它能够被进一步翻译成二进制机器语言。
4.2.2 代码汇编
由编译器生成的汇编程序中,存在着简化程序转换和编程的一些实际硬件不支持的指令,这类指令称为伪指令(pseudoinsruction)。
例如,MIPS硬件确保寄存器$zero保持0。即一旦使用该寄存器,它都能提供0,而且程序员不能修改寄存器$zero的值。寄存器$zero用于生成汇编语言指令move。move的功能是将一个寄存器中的内容复制到另一个中。因此即使MIPS体系结构不存在这条指令,MIPS汇编器依然可以识别它。
move $t0, $t1 # 寄存器$t0得到寄存器$t1的值
汇编器将这条汇编语言指令转换成等价的机器语言指令:
add $t0, $zero, $t1
总的来说,伪指令使得MIPS拥有比硬件所实现的更为丰富的汇编语言指令集。唯一的代价是保留了$at寄存器。本次实验中也存在着将伪指令扩展成通用指令的任务。
汇编器的主要任务是汇编成机器代码。汇编器将汇编语言程序转换成目标文件(object file),它包括机器语言指令,数据和指令正确放入内存所需要的信息。
为了产生汇编语言程序每条指令对应的二进制表示,汇编器必须处理所有标号对应的地址,汇编器将分支和数据传输指令中用到的标号都放入一个**符号表(Symbol Table)**中。这个表由标号和地址组成。
UNIX系统中的目标文件通常包括以下6个不同部分:
- 目标文件头,描述目标文件其他部分的大小和位置
- 代码段,包含机器语言代码
- 静态数据段,包含在程序生命周期内分配的数据
- 重定位信息,标记了一些在程序加载进内存时依赖于绝对地址的指令和数据
- 符号表,包含未定义的剩余标记,如外部引用
- 调试信息,包括了一份说明目标模块如何编译的简明描述
4.2.3 代码链接
到目前为止我们描述的所有内容表明,对源程序的任意一行代码的修改都需要重新编译和汇编整个程序,全部的编译和汇编效率是低下的,尤其对于标准库而言。因而出现了另一种方法,即单独编译和汇编每个过程,使得某一行代码的修改只需要编译和汇编一个过程,这种方法需要一个新的系统程序,称为链接器(Linker)。它把所有独立汇编的机器语言程序拼接在一起。
链接器的工作分为三个步骤:
- 将代码和数据模块象征性地放入内存
- 决定数据和指令标签的地址
- 修补内部和外部引用
链接器使用每个目标模块中的重定位信息和符号表,来解析所有未定义标签,这种引用发生在分支指令,跳转指令和数据寻址处。它的工作非常像一个编辑器,寻找所有旧地址并用新地址加以代替。 如果所有外部引用都解析完成,链接器接着要确定每个模块将要占用的内存位置。因为文件是单独汇编的,所以汇编器不可能知道该模块指令和数据相对于其他模块而言的位置,因此也就无从确定他们的内存位置。当链接器将一个模块放到内存中的时候,所有的绝对引用(与寄存器无关的内存地址),必须重定位来反映它们的真实地址。 链接器将产生一个可执行文件(Executable file),它可以在一台计算机上运行,通常,这个文件与目标文件具有相同的格式,但是它不包含未解决的引用。
4.2.4 代码加载
现在可执行文件已经存在于磁盘中,操作系统就可以将其读入内存并启动执行该程序,在UNIX系统中,**加载器(Loader)**按照以下步骤工作:
- 读取可执行文件头来确定代码段和数据段的大小
- 为正文和数据创建一个足够大的地址空间
- 将可执行文件中的指令和数据复制到内存中
- 把主程序的参数复制到栈顶
- 初始化机器寄存器,将栈指针指向第一个空位置
- 跳转到启动例程,它将参数复制到参数寄存器并且调用程序的main函数,当main函数返回时,启动例程通过系统调用exit终止程序
接下来,就让我们一起构造我们自己的汇编器和链接器!