CSAPP 第一章:计算机系统漫游
文章目录
前言
本文是根据CSAPP书的第一章记录的笔记(本章CMU 15-213没有对应的课程),从下一章开始会结合课和书来记录自己的学习笔记。
本章是对整个计算机系统的一个简单介绍。从一个C语音程序的生命周期出发,依次介绍了程序在系统中的创建和执行,计算机硬件,操作系统,计算机网络的一些基本概念,最后还涉及其他一些重要思想。
一、一个源程序的生命周期
本章从一个C语言程序出发,围绕它的生命周期开始对系统的学习——从它被程序员创建开始,到在系统上运行,输出简单的消息,然后终止。
创建
首先创建一个hello.c的程序如下图所示
代码如下:
#include <stdio.h>
int main()
{
printf("hello, world\n");
return 0;
}
该源程序实际上是一个由0和1组成的位序列,8个位组成一组称为字节,每个字节表示程序中的某些文本字符。大部分现代计算机都使用ASCII标准来表示文本字符,实际上就是用一个唯一的单字节大小的整数值表示每个字符。比如图中hello.c程序的ASCII表示如下
像hello.c程序这样只有ASCII字符组成的文件称为文本文件,所以其他的文件称为2进制文件。系统中所有信息(eg.磁盘文件, 程序,内存中存放的用户数据)都是由一串比特表示的。区分数据对象的不同方法就是读到这些数据对象时的上下文。
执行
图中的C语言程序还不能直接在机器上直接运行,因为计算机只能够识别机器语言(即2进制串),所以首先要将程序转为计算机能处理的程序,称之为目标程序也叫可执行文件。C语言中的每一条语句被转化为一系列低级的机器语言指令,然后以可执行目标程序的格式打包好,以二进制磁盘文件形式存起来。这个过程是由一个叫编译器驱动程序完成的,它由以下四个阶段完成
预编译
预处理器(cpp)根据以#开头的命令,修改原始程序。如hello.c程序中,预处理器就读取了stdio.h的内容,并把它直接插入程序文本中,得到以.i作为文件扩展名的程序。
编译
编译器(ccl)将文本文件 hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。如main函数的汇编程序如下图所示
汇编语言为不同高级语言的不同编译器提供了通用的输出语音
汇编
汇编器(as)把hello.s翻译成机器语言指令,并把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在文件hello.o中,它是一个2进制文件。
链接
hello程序调用了printf函数,它是每个C编译器都提供的标准C库中的一个函数,它存在于一个名为printf.o的目标程序中,它必须以某种方式合并到我们的hello.o程序中,链接就是负责干这事的。合并完成后,就得到hello文件,它是一个可执行文件,可以被加载到内存,由系统执行。
二、计算机硬件
上面我们介绍了一个程序执行的过程,但是是从逻辑层面介绍的,那真正在物理层面是如何执行的呢?这就需要我们先了解一下基本的计算机硬件才能够讲明白。
一个典型系统的硬件组成
一个典型的计算机硬件系统包括:总线,I/O设备,主存,中央处理器(CPU)。如下图所示,接下来我们将一 一介绍它们。
1. 总线
总线是贯穿整个计算机系统的一组电子管道,它携带信息字节并负责在各个部件间传递。通常总线被设计成传送定长的字节块,也就是以字为单位传输。字中的字节数也被称为字长,是一个基本的系统参数,各个系统中字长不尽相同。大多数计算机字长要么4个字节(32位),要么8个字节(64位)。
2. I/O设备
I/O(输入/输出)设备是与外界交互的通道,如示例图中包括的I/O设备有四个:键盘、鼠标(输入),显示器(输出),磁盘驱动器(磁盘)。最开始可执行程序hello就放在磁盘上。
每个I/O设备都通过一个控制器或适配器与总线相连。它们之间主要区别就是控制器是I/O设备本身或者系统主板上的芯片组,而适配器则是一块插在主板插槽上的卡。
3. 存储器
现在计算机的存储器一般包括:寄存器,高速缓存(多级),主存,本地磁盘。如果与远程服务器连接的话则还包括分布式文件系统,或Web服务器。
主存
主存是一个临时存储设备,在处理器执行程序时,用来存放程序以及程序处理的数据。从物理上来看,主存是有一组动态随机存取存储器(DRAM)芯片组成。从逻辑上来看,存储器是一个线性的字节数组,每个字节都有其唯一的地址(数组索引),这些地址从零开始的。
高速缓存
根据机械原理,较大的存储设备要比较小的存储设备运行得慢,比如说,一个典型系统上的磁盘驱动器容量可能比主存大1000倍,但是对于处理器而言,从磁盘驱动器读取一个字的时间开销要比主存读取开销大1000万倍。类似地,处理器从寄存器文件读取的数据比从主存读取快几乎100倍,主存读取慢的缺点,很大程度上浪费了处理器的处理时间。而且随着半导体技术发展,处理器与主存之间的差距还在拉大。
为了弥补这种差距,系统设计者采用了更小更快的存储设备,称为高速缓存器(Cache),作为暂时的集结区域,存放处理器近期可能会需要的信息。一个典型系统中的高速缓存存储器如下图所示
L1高速缓存容量可以达到数万字节,访问速度几乎和访问寄存器文件一样。L2高速缓存容量为数十万到数百万字节通过一条特殊总线连到处理器。进程访问L2高速缓存的时间要比访问L1高速缓存时间长5倍,尽管这样仍比访问主存时间快5-10倍,高速缓存使用静态随机访问存取器(SRAM)的硬件技术实现的。Cache访问速度快的原因是利用了高速缓存的局部性原理,即程序具有访问局部区域里的数据和代码的趋势。通过让高速缓存里存放可能经常访问的数据,大部分内存操作都能在快速的高速缓存中实现。
存储器层次结构
上面用很多篇幅介绍了存储器,介绍了存储器的容量和读取速度的关系,那整个存储器结构是怎样的呢?其实可以用下面这幅图表示
从上至下设备的存储容量越来越大,每个字节的造价越来越便宜,但是访问速度越来越慢。于是在处理器和一个较大较慢的设备之间插一个更小更快的存储设备(如cache)这种想法已经成为一种普遍的观念。存储器层次结构正是这种思想衍生而来,它就是用上一层的存储器作为下一层存储器的高速缓存,这既提高了计算机系统存储容量,又提高了读写速度。
运行hello程序
上面我们把计算机硬件大概介绍了一下,接下来我们看看hello程序是如何在硬件系统上执行的。初始时,shell程序执行它的指令
4. 处理器(CPU)
CPU是解释或执行存储在主存(或Cache)中指令的引擎。它的核心是一个大小为一个字的存储设备(或寄存器),称为程序计数器(PC).在任何时候,PC都指向主存中的某条机器语音指令(即含有该条指令的地址)。
‘从系统通电开始,到系统断电,CPU一直执行程序计数器指向的指令,再更新程序计数器,使其指向下一条指令。CPU看上去是按照一个非常简单的指令执行模型来操作的,这个模型是由指令集架构决定的。
CPU执行指令的操作,围绕着主存,寄存器文件和**算术/逻辑单元(ALU)**进行。寄存器文件是一个小的存储设备,由一些单个字长的寄存器组成&#