从文本文件到可执行文件
以hello world举例。
#include<stdio.h>int main(){printf("hello,world!\n");return 0;}
这样的一个.c文件如何被编译成可执行文件的呢?
1.1信息就是位+上下文
文本文档一般是通过ASCII码表示的。比如上面的hello.c文件,其内部的编码为:
像.c文件这样的,以ASCII字符组成的文件称为文本文件,所有其他文件都称为二进制文件
hello.c文件的表示方法说明了一个基本思想:系统中的所有信息都是由一串比特表示的,如何区分不同的数据对象呢?需要看他的上下文。
1.2 程序的“翻译”
.c文件如何一步步变成可执行文件的呢?
c语言的编译命令可能如下:
linux > gcc -o hello hello.c
整个翻译过程分四个阶段完成:
编译系统(complolation system):由上述的四个程序(预处理器、编译器、汇编器和链接器)组成
预处理阶段:根据以#开头的命令,修改原始的c程序。比如#inlcude<stdio.h>
,处理后的hello.i文件将stdio.h中的文件全部插入到hello.c文件中
编译阶段: 将hello.i翻译成hello.s,hello.s也是一个文本文件,但它描述的是一个汇编语言程序,内容可能是这样的:
- 汇编阶段。
汇编器将hello.s翻译成机器语言指令,并把这些指令打包**为可重定位目标程序(relocatable object program)**并将结果保存在目标文件hello.o中,hello.o是一个二进制文件
链接阶段hello.o调用了printf函数,printf函数存在于一个名为printf.o的单独的预编译好了的目标文件中。链接器负责将printf.o与hello.o合并。结果得到hello文件,这是一个可执行文件。
前一部分《c语言的编译过程》已经介绍了hello.c文件如何被转换为可执行文件hello。那么hello文件在具体执行时,计算机内部又发生了什么呢?
程序运行时,指令和数据在计算机中的传递
初始时,用户从键盘输入运行命令./hello
。shell程序将字符逐一读入寄存器,再把它放入内存中。
当我们敲完回车键后,shell程序就知道我们已经结束了命令的输入。shell会执行一系列指令,把hello目标文件中的代码和数据从磁盘复制到主存。
图1.5中,磁盘中的数据需要经过处理器才能到达主存。而采用DMA技术的话,数据可以直接到达主存。
当代码和数据被加载到主存后,处理器就开始执行hello程序的main程序中的机器语言指令。这些指令将"hello,world\n字符串中的字节从主存复制到寄存器文件,再从寄存器文件中复制到显示设备,最终显示在屏幕上。"
以上可以看到,程序在执行时要不断地执行数据的传输。包括指令和数据,一遍又一遍地在主存和寄存器中传输。使用高速缓存存储器可以使程序运行速度提高几个数量级。