预处理阶段。预处理器(cpp)根据以字符 # 开头的命令,修改原始的 C 程序。比如 hello.c 中第 1 行的 #include 命令告诉预处理器读取系统头文件 stdio.h 的内容,并把它直接插入到程序文本中。结果就得到了另一个 C 程序,通常是以 .i 作为文件扩展名。
编译阶段。编译器(cc1)将文本文件 hello.i 翻译成文本文件 hello.s,它包含一个汇编语言程序。汇编语言程序中的每条语句都以一种标准的文本格式确切地描述了一条低级机器语言指令。汇编语言是非常有用的,因为它为不同高级语言的不同编译器提供了通用的输出语言。例如,C 编译器和 Fortran 编译器产生的输出文件用的都是一样的汇编语言。
汇编阶段。接下来,汇编器(as)将 hello.s 翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序(relocatable object program)的格式,并将结果保存在目标文件 hello.o 中。hello.o 文件是一个二进制文件,它的字节编码是机器语言指令而不是字符。如果我们在文本编辑器中打开 hello.o 文件,看到的将是一堆乱码。
链接阶段。请注意,hello 程序调用了 printf 函数,它是每个 C 编译器都会提供的标准 C 库中的一个函数。printf 函数存在于一个名为 printf.o 的单独的预编译好了的目标文件中,而这个文件必须以某种方式合并到我们的 hello.o 程序中。链接器(ld)就负责处理这种合并。结果就得到 hello 文件,它是一个可执行目标文件(或者简称为可执行文件),可以被加载到内存中,由系统执行。
链接
链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或被拷贝)到存储器并执行。链接可以执行于编译时(源代码被翻译成机器代码时);也可以执行于加载时(程序被加载器加载到存储器并执行时);还可以执行与运行时,由应用程序来执行。
链接是由叫做连接器linker的程序自动执行的。链接器使得分离编译成为可能。我们不需要将一个大型的应用程序组织为一个巨大的源文件,而是可以把它分解为更小、更好管理的模块,可以独立的修改和编译这些模块。
理解链接器将帮助你构造大型程序;将帮助你避免一些编程错误;将帮助你理解语言的作用域规则如何实现;有助于理解和使用共享库等。
目标文件三种形式:
-
可重定位目标文件
-
可执行目标文件
-
共享目标文件。可以在加载或者运行时被动态地加载到存储器并链接。
编译器和汇编器生成可重定位目标文件(包括共享目标文件)。链接器生成可执行目标文件。一个目标模块就是一个字节序列,一个目标文件就是一个存放在磁盘文件中的目标模块。 现代系统通过使控制流发生突变来对这些情况做出反应。我们把这些突变称为异常控制流(execptional control flow)。异常控制流发生在计算机系统的各个层次。 在硬件层,硬件检测到的事件会触发控制突然转移到异常处理程序。 在操作系统层,内核通过上下文切换将控制从一个用户进程转移到另一个用户进程。 在应用层,一个进程可以发送信号到另一个进程,而接收者会将控制突然转移到他的一个信号处理程序。一个程序可以通过回避通常的栈规则,并执行到其他函数中任意位置的非本地跳转来对错误做出反应。
————————————————
原文链接:https://blog.csdn.net/dearyangjie/article/details/78801439