《程序是怎样跑起来的》第八章
文章主要讲的是从源文件到可执行文件。源代码就是用某种编程语言编写的程序,将源代码保存成一个文件,就称为源文件。编写好源文件之后,对源文件进行编译和链接,就可以生成可执行文件了,编译和链接的操作需要使用编译器和链接器来完成。CPU能直接解释和执行的只有本机代码CPU是计算机的大脑,它只能理解本机代码形式的程序,对CPU来说,用它的母语机器语言来编写的程序就是本机代码,用其他编程语言编写的源代码必须翻译成本机代码才能被CPU理解和执行。反过来说,不同编程语言所编写的源代码翻译成本机代码之后就变成了同一种语言。
负责将用C语言等高级语言编写的源代码翻译成本机代码的程序就称为编译器。编译器负责翻译源代码,用不同的编程语言编写的源代码,需要使用该语言专用的编译器来进行编译。编译器和读取源代码的内容,并将其翻译成本机代码。也就是说,编译器中有一张源代码和本机代码的对应表,但实际上仅靠对应表是无法生成本机代码的。编译器需要对读取的源代码进行词法分析,语法分析,语义分析等处理,这样才能生成本机代码。CPU的类型不同,其对应的本机代码也不同,因此不仅不同的编程语言所使用的编译器不同,不同类型的CPU所使用的编译器也是不同的,例如用X86构架CPU的C编译器用于PowerPC架构CPU的C编译器就是不同的,这样其实很方便,因为我们可以将同一段源代翻译成配饰不同的CPU的本机代码。编译器本身也是一种编程,因此也有其对应的运行环境。例如有WINDOWS版的c编译器,也有linux版的c编译器,同时也有一些编译器本身运行在一种CPU上,但它能够生成适配,另一种CPU的本机代码。这样的编译器称为交叉编译器,如果要在配备了X86架构CPU的PC上制作,配备了PowerPC架构CPU的计算机的程序就可以使用交叉编译器。作为源代码的翻译,结果编译器生成的是包含本机代码的文件,但这个文件不能直接运行,要得到可执行的EXE文件在编译之后还要进行链接操作。。EXE文件作为一个独立的文件,存储在硬盘中。当我们在资源管理器中双击EXE文件时,EXE文件中的内容会被加载到内存并运行PC机代码中,对变量的读写是通过访问存放变量数据的内存地址来实现的对函数的调用,也是通过让程序流程跳转到存放函数体的内存地址来实现的。尽管EXE文件中包含完整的本机代码程序,但变量和函数在内存中的实际地址是不确定的,像window因此这种支持同时加载多个可执行程序的操作系统,每次运行程序时都会为程序内部的变量和函数分配不同的内存地址。在EXE文件中,变量和函数被分配的内存地址都是虚拟的,在程序运行时,这些虚拟的内存地址会转换成实际的内存地址,链接器会在EXE文件的开头记录需要进行内存地址转换的各个位置,该信息被称为重定位信息。在EXE文件中,重定位信息中记录的是变量和函数的相对地址。所谓相对地址,就是某个地址与基地址之间的相对距离,也就是偏移量。要想使用相对地址,就需要进行一些额外的处理。在源代码中,变量和函数都是分散在各个位置的,但是在连接后的EXE文件中,变量和函数会被集中起来,分成两组,连续排列。于是,每个变量的内存地址就可以表示为该变量相对变量趋起始位置的偏移量,每个函数的内存地址也可以表示为该函数相对函数趋于起始位置的偏移量,每个区的基地址是在程序运行时确定的。

浙公网安备 33010602011771号