前言
.cpp :源文件
.s : 源文件的汇编代码
.o : 可重定位目标文件
.a: 静态链接库
.so: 动态链接库
.exe :可执行文件,点击即可运行
C++程序编译过程
整个编译过程分为两大步:
1)编译 :把文本形式的源代码翻译成机器语言,并形成目标文件
2)连接 :把目标文件 操作系统的启动代码和库文件组织起来形成可执行程序
3)加载:
1.编译
1.1 编译预处理
预处理又称为预编译,是替换插入工作。编译器执行预处理指令(以#开头,例如#include),这个过程会得到不包含#指令的**.i文件**。这个过程会插入#include 包含的文件代码,进行#define 宏定义的替换 , 处理条件编译指令 (#ifndef #ifdef #endif)等
1.2 编译
通过预编译输出的.i文件中,只有常量:数字、字符串、变量的定义,以及c语言的关键字:main、if、else、for、while等。这阶段要做的工作主要是,通过语法分析和词法分析,确定所有指令是否符合规则,之后翻译成汇编代码。
这个过程将.i文件转化位**.s文件**。
1.3 汇编
汇编过程就是把汇编语言翻译成目标机器指令的过程,生成目标文件(.obj .o等)。目标文件中存放的也就是与源程序等效的目标的机器语言代码。
目标文件由段组成,通常至少有两个段:
代码段.text:包换主要程序的指令。该段是可读和可执行的,一般不可写
数据段:存放程序用到的全局变量或静态数据。可读、可写、可执行。
这个过程将.s文件转化成.o文件。
2.链接Linking
链接可以在三个时刻进行:并分为静态链接和动态链接
编译时(compilation time),也就是在源代码被翻译成机器代码时。
加载时(load time),在程序被加载器loader加载到内存并执行时。
运行时(run time),由应用程序负责加载。
2.1静态链接
LD是静态链接器,它的输入是一组ELF可重定位目标文件和命令行参数,输出是一个完全链接的,可以加载和运行的ELF可执行目标文件。
为了构造可执行文件,静态链接器有以下任务:
1.符号解析。目标文件定义并且引用符号,每一个符号对应于一个函数,一个全部变量,或者一个静态变量。符号解析的目的是将每个符号引用和一个符号定义关联起来。
2.重定位。编译器和汇编器生成的section都是从地址0开始的,链接器通过把每个符号定义和一个内存位置关联起来,对这些section进行重定位,然后修改对这些符号的引用,使得它们指向相应的内存位置。链接器使用汇编器产生的重定位条目执行这样的重定位。
###和静态库链接
一个静态库包含多个可重定位文件,每个可重定位文件都是根据一个函数创建的。在应用时,只需要指定静态库的名字,链接器会只会复制其中被应用程序引用的目标模块。
Linux中的静态库以archive(后缀名为.a)的文件形式存在
2.2可重定位目标文件
一个ELF可重定位目标文件由以下section组成:
2.3 动态链接
静态库的问题:
需要定期维护和更新,当静态库更新时,需要将引用程序和更新了的库重新链接。每一个进程都需要把这些函数复制到代码段中。
因此动态链接共享库能弥补该缺陷
共享库是一个目标模块,在运行或者加载时,可以加载到任意的内存地址,并且和一个在内存中的程序链接起来。这个过程叫做动态链接。共享库也叫作共享目标(shared object),在linux中用.so后缀,在windows中叫做DLL(动态链接库)。
共享库共享的方式:
一个库只有一个.so文件,所有引用该文件的可执行目标文件共享这个。
在内存中,一个共享库的.text节的副本可以被不同的进程共享。