第1章 计算机系统漫游
1.1 信息就是位+上下文
系统中所有的信息——包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串比特表示的。区分不同数据对象的唯一方法是我们读到这些数据对象时的上下文 。比如,在不同的上下文中,一个同样的字节序列可能表示一个整数、浮点数、字符串或者机器指令。
C编程语言的起源: 贝尔实验室的Dennis Ritchie于1969~1973年创建。
C语言和Unix操作系统关系密切,C语言一开始就是作为用于Unix程序的语言所开发;
C语言小而简单;
C语言是为实践目的设计的;
1.2 程序被其他的程序翻译成不同的格式
#include<stdio.h>
int main()
{
printf("Hello,world\n");
return 0;
}
在Unix系统中,从源文件到目标文件的格式转换是由编译驱动程序完成的:
linux>gcc -o hello hello.c
GCC 编译驱动程序读取源程序文件hello.c,并将其翻译成一个可执行目标文件hello。翻译过程分为四个阶段完成,执行这四个过程的程序(预编译器、编译器、汇编器和链接器)一起构成了编译系统。
**预处理阶段:**预处理器(cpp)根据以字符#开头的命令,修改原始的C程序。例如:hello.c中的第1行#include<stdio.h> 命令告知处理器读取系统头文件stdio.h的内容,并将它直接插入程序文本中。结果得到了另一个C程序,通常以.i为文件拓展名。
编译阶段: 编译器(ccl)将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。汇编语言为不同的高级语言的不同编译器提供可通用的输出语句。
汇编阶段: 汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成可重定位目标程序的格式,并将结果保存在hello.o文件中。hello.o是一个二进制文件。
链接阶段: hello程序调用了printf函数,它是C标准库中的一个函数。printf函数存在于一个名为printf.o的单独的预编译好了的目标文件,必须将其合并入hello.o程序中。链接器(ld)就负责处理这种合并。结果得到了可执行目标文件(简称可执行文件),可以被加载到内存中,由系统执行。
1.3 了解编译系统如何工作是大有益处的
-
优化程序性能
-
理解链接时出现的错误
-
避免安全漏洞
1.4 处理器读取并解释存储在内存中的指令
1.4.1 系统的硬件组成
-
总线
贯穿整个系统的一组电子管道,它携带信息字节并负责在各个部件间传递。通常总线被设计成传送定长的字节块,一个定长为字(word)。
-
I/O设备
I/O(输入/输出)设备是系统与外界的联系通道。每个I/O设备都通过一个控制器或适配器与I/O总线相连。控制器和适配器的区别在于他们的封装方式。控制器是I/O设备本身或者系统的主印制电路板(通常称做主板)上的芯片组。适配器是一块插在主板卡槽上的卡。他们的功能都是在I/O总线和I/O设备之间传递信息。
CPU:中央处理单元
ALU:算术/逻辑单元
PC:程序计数器
USB:通用串行消息总线
-
主存
主存是一个临时存储设备,在处理器执行程序时,用来存放程序和程序处理的数据。从物理上说,主存是由一组**动态随机存储器(DRAM)**芯片组成。从逻辑上来说,存储器是一个线性的字节数组,每一个字节都有唯一的地址(数组索引),这些地址从零开始。
-
处理器
中央处理单元(CPU),简称处理器,是解释(或执行)存储在主存中指令的引擎。处理器的核心是一个大小为一个word的存储设备(或寄存器),称为程序计数器(PC)。在任何时候,PC都指向主存中的某条机器语言指令(含有该条指令的地址)。
CPU的操作模型由指令集架构决定,操作围绕着主存、寄存器文件和算术/逻辑单元(ALU)进行。
寄存器文件是一个小的存储设备,有一些单个字长(word)的寄存器组成。
CPU在指令的要求下可能会执行以下操作:
- 加载:从主存复制一个字节或者一个word到寄存器,已覆盖寄存器原来的内容
- 存储:从寄存器复制一个字节或者一个word到主存的某个位置,以覆盖这个位置上元来的内容
- 操作:将两个寄存器的内容复制到ALU,ALU对这两个字做算术运算,并将结果存放到一个寄存器中,以覆盖寄存器原来的内容
- 跳转:从指令本身抽取一个字(word),并将这个字复制到程序计数器(PC)中,以覆盖PC中原来的值
1.4.2 运行hello程序
初始时,shell程序执行它的指令,等待我们输入一个命令。当我们在键盘上输入字符串 "./hello"后,shell程序将字符串逐一读入寄存器,再把它存放到内存中,如下图所示:
当我们在键盘上敲回车键时,shell程序就知道我们已经结束了命令的输入。然后shell执行一系列的指令来加载可执行的hello文件,这些指令将hello目标文件中的代码和数据从磁盘中复制到主存。数据包括最终会被输出的字符串"hello,world\n"。
利用直接存储器存取(DMA)技术,数据可以不通过处理器而直接从磁盘到达主存。步骤如下图:
一旦目标文件hello中的代码和数据被加载到主存,处理器就开始执行hello程序的main程序中的机器语言指令。这些指令将"hello,world\n"字符串中的字节从主存复制到寄存器文件,再从寄存器文件中复制到显示设备,最终展示在屏幕上。这个步骤如下图:
1.5 高速缓存至关重要
上述示例揭示了一个重要的问题,系统花费了大量的时间把信息从一个地方挪到(复制)另一个地方。这些复制就是开销。
一个典型系统上的磁盘驱动器可能比主存大 1000 倍,但是对处理器而言,从磁盘驱动器上读取一个字的时间开销要比从主存中读取的开销大 1000 万倍。针对这种处理器与主存之间的差异,系统设计者采用了更小更快的存储设备,称为高速缓存存储器(cache memory,简称cache或高速缓存),存放CPU近期可能会需要的信息。高速缓存通过静态随机访问存储器(SRAM)的硬件技术实现。利用高速缓存的局部性原理,即程序具有访问局部区域内的数据和代码的趋势