CSAPP读书笔记–综述
CSAPP第一章“a tour of computer systems”是整本书的综述,主要介绍了计算机的基本组成原理和系统概貌,为后面的具体章节提供一个总领纲要,具体包含内容如下:
信息
计算机能理解的机器语言是以0、1组成的二进制序列,因此,信息在计算机系统中的表现形式就是二进制的bit序列,8个bit组织成一个语块,称为byte。
计算机系统中的信息主要分为程序和数据,程序源代码由各种字母符号组成,而每一个字符都会表示成一个字节长度的整型数值,转化的方式就是通过ASCⅡ标准,把字符转换为ASC码。
因此,系统中所有的信息,包括磁盘文件、内存中存储的代码和用户数据、通过网络传输来的数据等,都是会表示成bit的形式,而他们最终表示的含义取决于环境(context).
程序源文件如何运行
一段程序源文件是由各种字符组成,而计算机要能够运行,必须将其转化为计算机可识别的二级制可执行文件。这个过程就需要编译器来完成,具体的过程如下:
假设源文件为hello.c,它是一个C源文件,它首先通过预处理器进行一些头文件和宏展开,形成一个hello.i文件,然后经过编译,转换成汇编程序文件hello.s,汇编文件再经过汇编器转换成二进制的可重定位目标文件(relocatable object program),到此为止,源文件已经被编译成了二进制的目标文件,但整个过程还没有结束,因为.o文件对应的源C文件中,往往存在调用其他文件或库中函数的情况,因此还需要将相关的所有.o文件merge到一起,这一步就需要由linker(链接器)来完成,通过链接后就会生成可执行目标文件。计算机系统加载可执行文件即可将程序运行起来。
为什么要理解编译系统工作原理
- 更好地优化程序性能
重点关注章节:
第三章:介绍X86-64架构的机器语言,以及编译器如何将C文件转化为这种语言;
第五章:介绍如何通过调整代码结构使编译器能更好地工作,从而提高程序的性能;
第六章:介绍内存系统层级,以及C编译器如何在内存中保存数组,如何通过这部分知识提升C程序的运行效率; - 理解link阶段的错误
第7章会介绍link阶段的细节。 - 避免安全漏洞
第三章汇编语言的部分内容会提到栈规则和缓冲区溢出缺陷等。
计算机硬件结构
一个典型的计算机系统的硬件组成如下:
可以看到,一个计算机硬件组成大致如下:
-
总线(bus)
总线是一组导线组成的线束,它的作用就是在计算机的各组成部件之间传输信息。按照计算机所传输的信息种类,计算机的总线可以划分为数据总线、地址总线和控制总线,分别用来传输数据、数据地址和控制信号。总线是一种内部结构,它是cpu、内存、输入、输出设备传递信息的公用通道,主机的各个部件通过总线相连接,外部设备通过相应的接口电路再与总线相连接,从而形成了计算机硬件系统。总线每次能传输的数据长度成为字(word),一个word相当于多少个byte则取决于系统,对32位系统,一个word相当于4个字节(32bit),而对64位系统而言,则等于8个字节(64bit)。 -
I/O设备
I/O device是计算机系统连接外部世界的接口。I/O device连接到I/O bus是通过controller或者adapter,两者的区别主要在于包装方式。controller是设备本身的芯片集或者在系统主板上,而adapter则是插在模板插槽上的一张卡。第6章会介绍I/O device如磁盘是怎样工作的,第10章则会介绍应用程序如何通过UNIX的I/O接口访问设备。 -
主存
主存是处理器运行程序时存储程序和数据的临时存储设备,物理层面讲,主存是由DRAM(dynamic random access memory)组成的;逻辑层面讲,内存则被组织成字节数组的形式。第6章会介绍内存技术是如何工作的,以及DRAM芯片是如何组合成主内存的。 -
处理器
处理器,即CPU,负责解释和执行内存中的命令。CPU中有一个重要的寄存器叫PC(program counter),它保存的是即将执行的命令的内存地址(a word-size address)。CPU会读取PC指向的命令,解释指令,执行指令,然后把PC指向下一条待执行的指令。CPU中除了有各种寄存器以外,还有一个重要组成部分叫做ALU(算数逻辑单元),它主要负责对数据和地址的值进行计算。
CPU常见的指令操作有:
1) load:将数据从内存中读取加载到寄存器中;
2)store: 将寄存器中内容复制保存到内存中;
3)operate: 执行运算。复制两个寄存器的内容传给ALU,去执行数学运算,然后将执行结果保存到寄存器里,
4)jump: 程序跳转。从指令中获取另一个指令执行地址,保存到PC中,使程序跳转到该新指令。 -
其他重要组件
1)DMA
计算机执行程序的时候,由于程序源文件保存在磁盘中,因此CPU需要首先从磁盘中将目标文件读取出来,然后将其加载到内存中,然后才能开始执行。这显然是一个耗费CPU性能的操作,因此DMA(direct memory access)技术出现了。DMA其实就是一个控制器,它负责的事情比较单一,就是将磁盘等外设中的数据直接传输加载到内存,中间不经过CPU,从而减轻了CPU的负担。
2) 缓存
当CPU在处理程序的时候,需要频繁从内存中读取指令或数据,而这样的操作无疑拖累了程序的运行。为了解决这个问题,于是就有了缓存(cache memory),缓存一般由SRAM(static random access memory)实现,CPU从缓存中读取信息所用的时间会比主存快至少5到10倍。因此,缓存的作用就是将近期常用或即将使用的信息存在缓存中,这样CPU就可以直接通过缓存读取信息,减少从主存中读取,从而大大提高程序运行效率.
缓存一般又会分级,分为L1 CACHE、L2 CACHE,比较新、比较强大的系统甚至还有L3 CACHE。CPU访问速度:寄存器>L1 CACHE>L2 CACHE>L3 CACHE>主存。L1 CACHE容量大约10,000字节,CPU访问耗时接近于寄存器,L2 CACHE容量约100,000到1,000,000字节,CPU访问耗时比L1 CACHE长约5倍,比主存要短5到10倍。
存储设备按照访问耗时和容量,按如下层级所示:
程序运行过程
结合上述计算机硬件组成,我们可以总结一下程序在计算机系统中的运行过程,计算机将程序从磁盘中加载到内存中(DMA),然后CPU通过PC从内存中读取指令到寄存器中,对指令进行解析,并在ALU中进行地址或数据的计算。程序执行过程中,如果需要的话,CPU还会从鼠标、键盘等外部输入设备获取信息,程序运行的结果还可以向显示器等输出设备输出。如图:
操作系统
操作系统是整个计算机系统的管理者,它位于应用程序和计算机硬件之间,它主要有两个作用:1)保护硬件,防止其被程序误用;2)为上层应用提供简单统一的机制,操控底层复杂且各不相同的硬件。
- 进程(process):它是计算机对运行的程序的抽象。当单个CPU执行多个进程时,它通常会在多个进程之间频繁切换,以造成每个进程都在独立并行执行的假象,这就是并发。操作系统切换进程时,一般会先保存切换前进程当前的context(当前程序执行的位置(PC),各种寄存器的值等等),然后进入操作系统内核,切换到新的进程。当从其他进程再次切换回来时,需要先加载之前保存的context信息,然后在之前的位置继续往下运行。不同的进程间资源不共享。
- 线程(thread):它可以被认为是一个轻量级进程,位于进程内部,进程内部可以有多个线程,线程的运行机制跟进程类似,只是他们之间的资源是共享的。
- 虚拟内存:虚拟内存也是一种抽象,它让每个进程都有一种假象:每个进程都独享整个物理内存空间。进程中使用的地址均为虚拟地址。计算机在运行过程中会通过MMU(内存管理单元)将虚拟地址翻译成物理地址再使用。每个进程都有统一的相同的虚拟地址空间,但内存映射表却不同,因此相同的虚拟地址会被映射到不同的物理地址。进程虚拟地址空间的常见布局见下图:
操作系统中各进程公用的程序和数据位于较高的地址,而各进程私有的程序和数据则位于较低的地址,如图,虚拟内存空间常包含如下几个部分:
1) 代码段(text)和数据段(data),从某个固定的较低地址开始,存放的是可执行文件中的代码段,然后是数据段,数据段存的是进程的全局变量;
2) 堆:堆内存通过malloc和free动态分配和释放;
3)共享库:在中间区域存放的是公共的一些库,如C标准库,数学库等;
4) 栈:栈在整个程序过程中也是动态的,当调用函数的时候,栈会变深(增长),当从函数返回时,栈会变浅(释放)。
5) 内核虚拟内存:最顶端是留给操作系统内核的,是内核虚拟内存,应用程序不能直接访问这段内存,只能通过system call来执行想要的操作。内核与用户程序的隔离,这样的设计也提升了安全性和系统稳定性。
- 文件
文件本质上讲就是一串字节序列,每个I/O设备包括磁盘、键盘、显示器,甚至网络都可以被看作是文件。正所谓“一切皆文件”,这为各种不同的I/O设备提供了统一的视角。
网络
计算机之间通过网络形成连接互通,计算机将一段内存的数据发送到网络适配器(即网卡),数据流通过网路适配器发送到网络中进行传输,另一端的计算机可通过网卡接收到数据。同样的,计算机也可以从网络中读取到数据。以下是一个通过telnet传输hello到远端的示意图:
几个重要主题
- 阿姆达尔定律(Amdahl’s law)
其核心思想是,当我们对系统的一部分组件进行加速时,对系统整体性能的提升效果取决于这部分在整个性能中的占比和对这部分组件的提升程度。
假设系统在执行某个程序的时候,它本来需要耗时Told, 现在对系统某部分进行提升,这部分在总耗时中占比为α,现在这部分的速度提升为原来的k倍,优化性能之后的用时为Tnew, 则设Told/Tnew=S, S满足:
-
并发和并行化
1)线程级并发;
2)指令级并行化;
3)单指令多数据的并行化。 -
计算机系统中的抽象
1)文件是I/O设备的抽象;
2)虚拟内存是主存和磁盘的抽象;
3)进程是处理器、主存和I/O设备的抽象。
1)线程级并发;
2)指令级并行化;
3)单指令多数据的并行化。 -
计算机系统中的抽象
1)文件是I/O设备的抽象;
2)虚拟内存是主存和磁盘的抽象;
3)进程是处理器、主存和I/O设备的抽象。