深入理解计算机系统_Hello World的一生

背景

一个Hello.c程序如表所示。

1
2
3
4
5
6
#include <stdio.h>
int main()
{
printf(“Hello World\n”);
return 0;
}

这个Hello World程序,看似简单,可是为了让它完成运行,需要系统的各个组成部分协调工作,本文将通过跟踪Hello World短暂的一生,来揭秘程序运行的奥义。

Hello 程序生成过程

首先,为了将Hello.c变成可执行的二进制目标文件,需要将其推入加工车间—编译系统中进行加工,加工过程如图1.1所示。

图1.1编译系统

预处理阶段

预编译器(cpp)根据以字符#开头的命令,将头文件stdio.h的内容直接插入到Hello.c文件中,最终的得到一个以i为扩展名的C文件—Hello.i文件。

编译阶段

编译器(ccl)将Hello.i文件翻译成文本文件Hello.s,这是个汇编语言程序。注意,汇编语言是计算机底层世界通用通用的语言,不同的高级语言、不同的编译器,最终得到的还是一样的汇编语言。

汇编阶段

汇编器(as)将Hello.s文件翻译成机器语言指令,并将结果保存到二进制文件Hello.o,后者的字节编码是机器语言指令而不是字符。

链接阶段

这里的Hello World程序调用了printf函数,它是每个C编译器都会提供的标准C库中的一个函数。printf函数存在于一个名为printf.o的单独的预编译好了的目标文件中,而这个文件必须通过链接合并到我们的Hello.o文件中,链接器(ld)就是做这个工作的,它最终会输出一个可执行目标文件Hello,这个可执行目标文件可以被加载到内存中,由系统执行。

以上就是Hello World的生成过程,现在讲讲当系统开始执行这个程序到屏幕完整的输出这句激动人性的“Hello World”的时候,计算机内部系统都干了些什么?
首先,我们先看看一个典型的计算机系统的硬件组成图,如图1.2所示。

图1.2 一个典型的计算机系统的硬件组成

Hello 程序执行过程

然后,我们开始观赏Hello程序的执行过程,主要分为三个步骤:

从键盘读取Hello命令

打开终端,在Hello的目录下,通过键盘输入“./Hello”后,系统会将这些字符读入到寄存器中,如图1.3所示,然后再存放到主存储器中,如图1.4所示。

图1.3 系统读入“./Hello”到寄存器中

图1.4 系统将“./Hello”从寄存器搬到主存储器中

从磁盘加载可执行文件到主存储器中。

当系统接收完“./Hello”命令以后,将开始执行一系列指令来加载可执行的Hello文件,将Hello目标文件中的代码和数据从磁盘复制到主存储器中,当然,这些数据包含那句“Hello World\n”。

图1.5 系统从磁盘加载可执行文件到主存储器中

将输出字符串从内存写到显示器

一旦目标文件Hello中的代码和数据被加载到内存中,处理器就开始执行Hello程序的main程序中的机器语言指令,这些指令将“Hello World\n”字符节中的字节从主存复制到寄存器文件,如图1.6所示。

图1.6 系统将“Hello World\n”从主存复制到寄存器文件

接着,指令会继续将这次字符从寄存器文件中复制到显示设备,最终显示到屏幕上,如图1.7所示。

图1.7 系统将“Hello World\n”从寄存器文件复制到显示设备

自此,Hello World完成了它伟大的使命!