首先思考下面的问题:为什么要有编译链接呢?
有两点原因:1.编译器无法直接运行.c和.cpp文件,因此需要将源文件转化为计算机可以识别的二进制文件;2.如果想要运行一段代码,就会产生进程,进程是在内存中,而源文件存放在内存中,因此需要编译链接,将文件加载到内存中,CPU才能执行。
编译链接分为4个阶段,接下来具体看每个阶段做了什么事情。
1.预编译-->.i文件
(1)删除#define并做文本替换;
(2)处理预编译指令,如#ifndef、#if 0、#endif等;
(3)递归展开头文件;
(4)删除注释;
(5)添加行号和文本标识;
(6)保留#pargma编译器处理。
2.编译-->.s文件
(1)词法分析(如变量名不能以数字开头等);
(2)语法分析(如int a=10;delete a;);
(3)语义分析(结合上下文分析);
(4)代码优化(调整指令);
(5)生成汇编指令。
3.汇编-->.o文件(可重定位的二进制文件)
将汇编代码翻译为机器指令
4.链接-->.exe文件
(1)合并段和符号表;相同的段进行合并,一个段映射一个页面。合并符号表:同名查找替换。
强符号:已初始化的全局变量。
弱符号:未初始化的全局变量。(C++中无强弱符号之分)
强弱符号规则:两强会报重定义错误;一强一弱选择强符号;两弱选字节数大的。
(2)符号解析;
(3)分配地址和空间;
(4)符号重定位。
运行阶段:
1.创建虚拟地址空间和内存的映射(创建虚拟结构体--PCB),创建页目录、页表;
2.加载指令和数据;
3.入口地址写入下一行指令寄存器。
Linux中编译链接命令:
假设编译源程序main.c,生成可执行程序main。
预编译:gcc -E main.c -o main.i
-E:指定预编译
-o:output,后加输出文件名称。若无此参数则将预编译结果直接输出到终端界面,不保存到文件。
编译:gcc -S main.i
编译后默认生成.s文件,存放汇编指令
汇编:gcc -c main.s
链接:gcc main.o -o main
链接过程在不指定生成文件名的情况下,默认均生成a.out文件。
一般的编译链接过程直接用命令gcc -o main main.c生成,包含上述全过程。
此处可能会用到的命令:objdump readelf