#include
int main(){
printf("hello, world\n");
return 0;
}
源文件为hello.c,是文本文件。为了运行hello.c程序,每条C语句都必须被其他程序转换成一系列的低级机器语言指令。然后这些指令按照一种称为可执行文件(exe)的格式打好包,并以二进制磁盘文件的形式存放起来。
在Unix操作系统上,从源文件到目标文件的转化是由编译器驱动程序完成的:
linux> gcc -o hello hello.c
此刻hello.c已经被编译成了可执行文件hello,并被存放在磁盘上。在Unix系统上运行可执行文件:
linux> ./hello
hello, world
linux>
./hello不是内置的shell命令,它会被认为是可执行文件,被加载并运行。那我们就来探索一下,hello程序运行所涉及的硬件吧
上图为一个典型系统的硬件组成,以下对其组成部分详细介绍
总线,贯穿整个系统的一组电子管道,它携带信息字节并负责在各个部件之间传递。通常总线被设计为传送定长的字节块,也就是字(word)。字中的字节数(即字长)是一个基本的系统参数,各个系统都不尽相同。大多数机器字长要么是4个字节(32位),要么是8个字节(64位)
I/O(输入/输出)设备是系统与外界世界的联系通道,我们的示例系统包括4个I/O设备:作为用户输入的鼠标、键盘,作为用户输出的显示器,以及用于长期存储数据和程序的磁盘驱动器(简单地说就是磁盘)。最开始,可执行程序hello存放在磁盘上。
每个I/O设备都通过一个控制器或适配器与IO总线相连。控制器和适配器之间的区别主要在于它们的封装方式。控制器是I/O设备本身或系统的主印制电路板(通常称为主板)上的芯片组。而适配器则是一块插在主板插槽上的卡。它们的功能都是在I/O总线和I/O设备之前传递信息。
主存是一个临时存储设备,在处理器执行程序时,用来存放程序和程序处理的数据。从物理上来说,主存由一组动态随机存储芯片(DRAM)组成。从逻辑上来讲,主存是一个线性的字节数组,每个字节都有其唯一的地址(数组索引),这些地址是从零开始的。
中央处理单元(CPU),简称处理器,是解释(或执行)存储在主存中指令的引擎。处理器的核心是一个大小为一个字的存储设备(或寄存器),称为程序计数器(PC)。在任何时刻,PC都指向主存中某条机器语言指令(即含有该条指令的地址)。
从系统通电开始,直到系统断电,处理器一直在不断地执行程序计数器指向的指令,再更新程序计数器,使其指向下一条指令。下一条指令不一定和在内存中刚刚执行的指令相邻。
寄存器文件是一个小的存储设备,由一些单个字长的寄存器组成,每个寄存器都有唯一的名字。ALU计算新的数据和地址值。下面是一些简单的操作例子,CPU在指令的要求下可能会执行这些操作。
加载:从主存复制一个字节或一个字到寄存器,以覆盖寄存器原来的内容
存储:从寄存器复制一个字节或者一个字到主存的某个位置,以覆盖这个位置原来的内容
操作:把两个寄存器的内容复制到ALU,ALU对这两个字做算术运算,并将结果存放到一个寄存器中,以覆盖该寄存器中原来的内容
跳转:从指令本身中抽取一个字,并将这个字复制到程序计数器(PC)中,以覆盖PC中原来的值
初始时,shell程序执行它的指令,等待我们输入一个命令。当我们在键盘上输入字符串"./hello"后,shell程序将字符逐一读入寄存器,再把它存放在内存中。
当我们在键盘上敲回车键时,shell程序就知道我们已经结束了命令的输入。然后shell执行一系列指令来加载可执行的hello文件,这些指令将hello目标文件中的代码和数据从磁盘复制到主存。数据包括最终会被输出的字符串“hello, world\n”。
利用直接存储器访问(DMA)技术,数据可以不通过处理器,而直接从磁盘到达主存。
一旦目标文件hello中的代码和数据被加载到主存,处理器就开始执行hello程序的main方法的机器语言指令。这些指令将“hello, world\n”字符串中的字节从主存复制到寄存器文件,再从寄存器文件中复制到显示设备,最终显示在屏幕上。
这个简单的示例揭示了一个重要的问题,即系统花费了大量的时间把信息从一个地方挪到另一个地方。hello程序的机器指令最初是存放在磁盘上,当程序加载时,它们被复制到主存;当处理器运行程序时,指令又从主存复制到处理器。这些复制就是开销,减慢了程序“真正”的工作。
根据机械原理,较大的存储设备要比较小的存储设备运行得慢,而快速设备的造价远高于同类的低速设备。一个典型系统上磁盘驱动器可能比主存大1000倍,但是对于处理器而言,从磁盘驱动器上读取一个字的时间开销要比从主存中读取的开销大1000万倍。
类似地,一个典型的寄存器文件只存储几百字节的信息,而主存里可以存放几十亿字节。然而,处理器从寄存器文件读数据比从主存中读数据几乎要快100倍。更麻烦的是,随着这些年半导体技术的进步,这种处理器与主存之间的差距还在持续增大。加快处理器的运行速度比加快主存的运行速度要容易和便宜得多。
针对这种处理器与主存之间的差异,系统设计者采用了更小更快的存储设备,称为高速缓存存储器(cache memory,简称为cache或高速缓存),作为暂时的集结区域,存放处理器近期可能会需要的信息。位于处理器芯片上的L1高速缓存的容量可以达到数万字节,访问速度几乎和访问寄存器文件一样快。一个容量为数十万到数百万字节的更大的L2高速缓存通过一条特殊的总线连接到处理器。进程访问L2高速缓存的时间要比访问L1高速缓存的时间长5倍,但这仍然比访问主存的时间快5~10倍。
利用局部性原理(即程序具有访问局部区域里的数据和代码的趋势),在高速缓存里存放可能经常访问到的数据,大部分的内存操作都能在快速的高速缓存中完成。
1、《深入理解计算机系统》(第三版)第一章 计算机系统漫游