对于计算机语言的初学者来说,通常程序都是在集成开发环境(IDE)下开发的,而很少有人去了解程序的编译、链接原理,今天就让我们来揭开程序编译链接原理的神秘面纱。
话不多说先上代码:
#include <stdio.h>
int Sum(int a,int b,int c)
{
return a+b+c;
}
int main()
{
Sum(10,20,30);
printf("%d\n",Sum(10,20,30));
return 0;
使用visual studio 2013运行上面的代码,相信很多人都知道运行结果是60吧,运行结果如下图:
那么程序运行的整个过程编译器都做了哪些事情呢?
事实上,从程序到输出结果60一共经过了五个步骤,分别是:预编译、编译、汇编、链接、运行。
预编译
程序在预编译阶段,预编译器会将.cpp文件预编译成.i文件。具体做的事情有:
-
删除#define,进行文本替换。所谓的文本替换是指展开所有的宏定义
-
处理所有的预编译指令,如#if,#endif,#elif等
-
处理#include预编译指令,将包含的文件插入到指令位置
-
删除注释
-
添加行号和文件标识
-
保留所有的#program
编译
在编译阶段会生成.s文件,具体做的事情有:
-
词法分析
-
语法分析
-
语义分析
-
代码优化
-
生成汇编指令
汇编
在汇编阶段汇编器会将汇编代码转换成机器可以执行的指令,生成.o文件。汇编阶段只做一件事,那就是翻译指令。
链接
链接是指将程序的各个模块之间相互引用的部分使之能够正确地衔接,会生成.exe文件。具体做的事情有:
- 合并段和符号
- 符号解析 ——所谓的符号解析是指在每个文件符号引用(引用外部符号)的地方找到符号的定义。
- 分配地址和空间
- 符号重定位
运行
程序的运行指的是将程序变成进程的过程。说到程序运行,不得不说的是,程序并不是在磁盘上运行的,而是通过虚拟地址空间这一中间层映射到“内存”上运行的。
程序并不是直接加载到内存中运行的,而是出于安全的考虑,通过虚拟地址空间来映射到部分内存上运行的,映射关系如下图:
具体做的事情有:
- 创建内核映射结构体并建立虚拟地址空间和真实物理内存的映射
- 加载指令和数据
- 把入口地址写入下一行指令寄存器
以上就是程序运行的整个过程,相信大家已经清楚了程序运行的基本原理,好了今天就到这里了,我们下期再见!