今年开了操作系统课,课上老师提了一个问题:从一个保存程序代码的文本文件到可执行的程序,编译器做了啥?由于之前买过<<深入了解计算机系统>>这本书,刚买来时受热就翻了其中一部分章节,其中就有讲到上述所问的讲解,索性就参考其上的讲解写出来
我会以一个hello.c的c程序贯穿整个文章,具体代码如下
#include<stdio.h>
int main(int argc,char **argv)
{
printf("hello world\n");
return 0;
}
该程序通过编译器编译生成hello程序,其运行结果如下
那么此程序从保存它的文本文件到可执行程序hello的中间编译器究竟做了啥,不说话先上图了
由上图可知gcc编译器驱动程序在读取了hello.c文件之后,把它翻译成了一个可执行代码。此过程共经历了4个阶段的程序,分别是预处理器,编译器,汇编器,链接器,此4个截断程序一起构成了编译系统。接下来我就为大家详细说明以下此4个阶段程序各自的具体工作
1.预处理阶段
预处理器会将以字符#开头的语句,修改为原始的c程序,比如hello.c中的#include
gcc -E hello.c -o hello.i
用vim打开hello.i文件之后如下图
这是文件开头
这是文件结尾处
我想大家一定会惊讶的发现一个简简单单的hello,world程序竟然会平白无辜的增加了800多行,没错这就是预处理器干的,它将程序中以#开头的stdio.h文件的内容都加了进来
需要强调的是,经预处理器的文件是文本文件
2.编译器
编译器会将上文中提到的hello.i(预编译好的文件)近一步翻译成保存汇编语言的文本,其后缀会变为.s
我们可以通过如下方式将hello.c编译成.s文件
gcc -S hello.c -o hello.s
打开hello.s文件如下图
可以看到里面的代码变为了汇编代码
需要注意的是.s文件依然是文本文件
3.汇编器
汇编器会将上述的hello.s文件翻译成机器语言指令,并把这些指令打包成一种叫做可重定位目标程序的格式并将结果保存在新生成的二进制文件hello.o中
4.链接阶
我们的程序hello中调用了printf函数,而printf函数存在于由c标准库提供的名为printf.o的单独预编译好了的目标文件中,所以我们要调用printf函数,就得通过链接器,使其通过它自己的方式将hello.o和printf.o这俩个文件合并在一起,经过合并后的文件就是可执行的hello文件了