计算机漫游1-Computer Systems笔记之编译系统

计算机漫游1-Computer Systems笔记之编译系统

从helloworld程序的前半生简单介绍编译系统

一个简单的hello.c程序:

#include

Int main(){

    Printf(“hello, world!\n”);

}

在linux下在shell中直接输入:gcc -0 hello hello.c然后找到home目录,就可以发现多出来了一个hello可执行程序。然后再在shell中敲入:./hello就可以看到shell上已经打印出“hello,world!”字符串了。

先凭自己理解的画个hello.c文件运行的过程:

计算机漫游1-Computer Systems笔记之编译系统_第1张图片
hello.c程序生命周期

上面的图用最简洁语言描述就是:创建-->运行-->出结果-->终止。但是,看似简单的东西背后一般都有很复杂的过程。为了搞清楚这个过程,可以询问下hello.c它在这个过程中都经历了啥。

问:hello.c,你从出生到进入休息状态都经历了什么啊?

Hello.c:我经历的事情可多了!嗯,主要历程分为两个(因为主人就在shell中输入了两条命令),先说说我的前半生—在编译系统中经历的四次格式转换过程吧:

首先,主人通过“一号输入小帮手”键盘把我送进了电脑的硬盘里头存起来,

接着主人在”口令发号中心“shell中用命令“gcc -o hello hello.c”告诉系统要执行我,系统收到这个命令,就开始了我前半生的风雨漂流:

我先是来到了四哥“预处理器”的办公场所,看见有两个仓库:一个写着“#include”,一个写着“#define”。我查了查自己的程序文本,发现我恰好有“#include”开头的东西,走进去后四哥立即将stdio.h放到我的程序文本中,这时候,我从hello.c变成了hello.i,表示“被修改的源程序”;

紧接着,我被送往三哥“编译器”那里,三哥太厉害了,三下五除二就把我翻译成了二哥“汇编器”能识别的汇编语言,这样,我的每条语句都以一种标准的文本格式确切地描述了一条低级机器语言指令,此时,我又从hello.i变成了hello.s,表示“汇编程序”;

然后,我就来到了二哥“汇编器”这里,二哥告诉我大哥“连接器”比他更厉害,但是很懒,在掌握了超级难的机器语言后就不想再去学其他东西了,所以才有了他们三个弟弟,(其实应该是在说主人很笨吧,看不懂机器语言和汇编吧:(),于是,我被二哥翻译成了机器语言指令,并把这些指令打包成一种叫做“可重定位目标程序”的格式,然后呢,我终于从hello.s变成了目标文件hello.o了(此时我也摇身一变,从文本文件变成了二进制文件)!要是主人在这个时候打开我,看到的就将是一堆乱码。

最后,我终于来到了大哥“链路器”这里,并在大哥的帮助下,找到了程序中printf函数需要的另一个标文件printf.o,大哥将我们合并,由此,我们就成了“可执行”的目标文件hello了。

然后我的前半生就到这了,回到磁盘中休息并等待主人的第二次命令,需要我的时候再出来。

老师告诉我上面hello.c经历上午四个过程刚好构成编译系统(compilation system):

计算机漫游1-Computer Systems笔记之编译系统_第2张图片
编译系统

1)预处理阶段(Preprocessing phase):预处理器(preprocessor,cpp)根据字符“#”开头的命令修改原始的C程序(就是由你自己写的那个程序),即插入所有用#include命令指定的文件,扩展所有用#define声明指定的宏。例如,hello.c文件中第一行的“#include ”命令告诉预处理器去读取系统头文件stdio.h的内容,并把它插入到程序文本中。然后hello.c的后缀就是.i。(这一步可以用命令”gcc -E hello.c -o hello.i”查看预处理过程)

2)编译阶段(Compilation phase):编译器(compiler,ccl)将文本文件hello.i转化为由汇编语言程序构成的hello.s文本文件。每一条汇编指令都包括确切的对于一个低级机器语言指令的描述。(这一步通过命令”gcc -S hello.i -o hello.s”查看)

3)汇编阶段(Assembly phase):汇编器(assembler,as)将文本文件hello.s转化成由机器语言构成的hello.o二进制文件。hello.o是机器代码的一种形式,包含所有指令的二进制表示,但还未填入地址的全局值,比如全局变量的地址(这一步可用命令”gcc -c hello.s -o hello.o)

4)链接阶段(Linking phase):因为hello程序调用了printf函数,而printf函数存在于一个名为printf.o的单独编译好的目标文件中,链路器(linker,ld)就负责将printf.o与hello.o合并起来的工作,最后得到hello可执行目标文件,可以被加载到内存中,由系统执行。(其实hello就是hello.exe,在执行时可以将后缀省略,使用命令”gcc hello.o –o hello.exe”)

转换文件如下:

hello.c

hello.c文本文件


hello.i

计算机漫游1-Computer Systems笔记之编译系统_第3张图片
hello.i文本文件

hello.s

计算机漫游1-Computer Systems笔记之编译系统_第4张图片
hello.s文本文件

hello.o

计算机漫游1-Computer Systems笔记之编译系统_第5张图片
hello.o二进制文件

最后就是可执行文件hello了,这里就不展示了,因为同hello.o一样也是一堆乱码。

你可能感兴趣的:(计算机漫游1-Computer Systems笔记之编译系统)