参考博客https://blog.csdn.net/csdn_violin/article/details/79430384
概念
1.编译:把源文件中的源代码翻译成机器语言,保存到目标文件中。如果编译通过,就会把.C/.CPP转换成.obj文件(Windows系统)/.o(Linux系统)。
2.编译单元:每个.c/.cpp就是一个编译单元,每个编译单元相互之间是独立且相互不知的。一个编译单元(Translation Unit)是指一个.c/.cpp文件以及它所include的所有.h文件,.h文件里面的代码将会被扩展到包含它的.c/.cpp文件里,然后编译器编译该.c/.cpp文件为一个.obj/.o文件,后者拥有PE(Portable Executable,即Windows可执行文件)文件格式,并且本身包含的就是二进制代码,但是不一定能执行,因为并不能保证其中一定有main函数。当编译器将一个工程里的所有.cpp文件以分离的方式编译完毕后,再由链接器进行链接成为一个库文件.lib、.dll文件(Windows系统)/.a、.so文件(Linux系统)或可执行文件.exe。
3.目标文件:编译后生成的文件,以机器码的形式包含了编译单元里所有的函数和数据、导出符号表、未解决符号表、地址重定向表等。目标文件类型包含有:可重定位文件(.obj/.o)、共享的目标文件(库文件)、可执行文件。
1)可重定位文件(.obj/.o):其中包含有适合于其它目标文件链接来创建一个可执行的或者共享的目标文件的代码和数据,每个.cpp会被编译成一个.obj/.o文件。
2)共享的目标文件(库文件):静态库(.lib/.a)或动态库(.dll/.so)。
Windows下的静态库和动态库 参考:https://blog.csdn.net/qq1623803207/article/details/78341247
3)可执行文件:一个可以被操作系统创建一个进程来执行之的文件。
备注:.obj/.o文件在编译后就能获得,但是库文件、可执行文件都需要在链接后才能获得。
c++程序编译过程图
整个程序编译过程分为编译和链接两个过程。
1.编译过程:
作用:编译是读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再转换为机器代码,生成目标文件(.obj/.o)。
编译分为两个过程:编译(预处理阶段和编译优化阶段)、汇编。
1)编译:预处理阶段:宏#define;条件编译指令,如#ifdef、#ifndef、#else、#elif、#endif等;头文件包含,如#include
编译、优化阶段:针对代码优化,不依赖具体计算机;针对计算机优化。
2)汇编:把汇编语言代码翻译成目标机器指令,生成目标文件(.obj/.o),此过程会依赖机器的硬件和操作系统环境。
.obj/.o文件至少要提供3张表:
① 导出符号表:即该目标文件可以提供的符号及地址;
② 未解决符号表:即找不到地址的符号的列表,告诉链接器这些符号没找到地址;
③ 地址重定向表:链接的时候,链接器会为目标文件的“未解决符号表”里的符号在其他目标文件中寻找地址,但是每个目标文件的地址都是从0x0000开始的,这样直接将对方文件中符号的地址拿过来用显然会是不正确的,为了区分不同的文件,链接器在链接时就会对每个目标文件的地址进行调整。在这个例子中,假如B.obj的0x0000被定位到可执行文件的0x00001000上,而A.obj的0x0000被定位到可执行文件的0x00002000上,那么实现上对链接器来说,A.obj的导出符号地地址都会加上0x00002000,B.obj所有的符号地址也会加上0x00001000,这样就可以保证地址不会重复。因为被加上了起始地址,所以符号在自身文件中的实际地址就不对了,需要再用一张地址重定向表记录符号相对自身文件的地址。
2.链接过程:
作用:链接程序的主要工作就是将有关的目标文件(库文件、.obj/.o文件)彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。
具体工作:当链接器进行链接的时候,首先决定各个目标文件在最终可执行文件里的位置。然后访问所有目标文件的地址重定义表,对其中记录的地址进行重定向(加上一个偏移量,即该编译单元在可执行文件上的起始地址)。然后遍历所有目标文件的未解决符号表,并且在所有的导出符号表里查找匹配的符号,并在未解决符号表中所记录的位置上填写实现地址。最后把所有的目标文件的内容写在各自的位置上,再作一些另的工作,就生成一个可执行文件。
链接方式:静态链接和动态链接。
① 静态链接:函数的代码将从其所在的静态链接库中被拷贝到最终的可执行程序中,这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。
② 动态链接:函数的代码被放到称作是动态链接库或共享对象的某个目标文件中,链接程序时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息,在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间,动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。
C++程序编译的四个过程(参考:https://blog.csdn.net/wqx521/article/details/52625408):
1)预处理:条件编译,头文件包含,宏替换的处理,生成.i文件;
2)编译:将预处理后的文件转换成汇编语言,生成.s文件;
3)汇编:汇编变为目标代码(机器代码)生成.o的文件;
4)链接:连接目标代码,生成可执行程序。