版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/tomatolee221/article/details/89468371
C语言编译链接----幕后小故事
我们在计算机中写的.c
文件,被称为C语言源代码,这种源代码机器是不认识的,为了让机器认识C语言源代码,那么必须要经过这么几个过程(预处理、编译、汇编、链接、加载),让源代码变为机器语言的目标文件,才可以变为可执行程序。
下图为编译过程:
讲解上图:
这里的源代码姑且叫它sample.c
,将它经过预处理器;
- 预处理器(预处理)的描述: 预处理器对源代码进行宏替换、条件编译、展开头文件、去掉注释、处理特殊符号操作;产生扩展源代码
sample.i
; - 编译器(编译): 编译器对
sample.i
进行语法和词法的分析以及代码的优化处理,在确认所有的语法符合C语言规则后,将sample.i转化为等价的中间源代码或汇编源代码sample.s
; - 汇编器(汇编): 汇编器对
sample.s
进行汇编,汇编就是将汇编源代码转化为目标代码sample.o
也就是二进制文件; - 链接器(链接): 有将
sample.o
文件转换为了sample.exe
文件些人会提出疑问,在汇编阶段不是已经产生了二进制代码文件了吗?机器不是可以识别二进制代码文件吗?为什么还要进行下一步的链接处理呢?
答:由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。
例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。
链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。
根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:
(1)静态链接
在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。
(2) 动态链接
在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。
- 加载器(加载): 每当我们给出执行特定程序的命令时,加载器就会开始工作。加载程序将.exe文件加载到RAM中,并通知CPU加载此程序的地址的起始点,就可以开始运行程序。
链接器与加载器的区别:
链接器 | 加载器 |
---|---|
链接器生成源程序的可执行模块 | 加载器将可执行模块加载到主存储器以供执行 |
链接器将汇编程序生成的目标代码作为输入 | 加载器将链接器生成的可执行模块作为输入 |
链接器组合源代码的所有对象模块以生成可执行模块 | 加载器将地址分配给主存储器中的可执行模块以供执行 |
链接器的类型是链接编辑器,动态链接器 | 加载器的类型是绝对加载,可重定位加载和动态运行时加载 |