第二次看:2021-11-09
补充:
1 程序代码文件实际上就是一个由值0和1组成的位(又称为比特)序列,8个位被组织成一组,称为字节。
1 其实系统中所有的信息(包括磁盘文件,内存中的查询,网络上的数据等)都是由一串比特,0和1来表示。区分不同数据对象的唯一方法就是我们读这些数据对象时的上下文
2 C语言程序经过四个阶段生成一个可执行目标文件,四个阶段(预处理器,编译器,汇编器和链接器)
- 预处理阶段:预处理器(cpp)根据以字符#开头的命令,修改原始的C程序,比如hello.c中第一行的 # include < stdio.h > 命令告诉预处理器读取系统头文件stdio.h的内容,并将它直接插入程序文本中,得到另一个C程序,通常以 .i 作为文件扩展名。
- 编译阶段:编译器(ccl)将文本文件hello.i翻译成hello.s,它包含一个汇编语言程序。该程序包含函数main的定义,如下所示
- 汇编阶段:汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o中。hello.o是一个二进制文件。
- 链接阶段:链接器(ld)将几个关联文件合并起来,得到最终的hello文件。hello是一个可执行目标文件。比如hello程序中用到了printf函数,而printf函数在printf.o文件中,需要将printf.o文件合并到hello.o文件中,而链接器就是负责这种合并。
3 系统的硬件组成
- 总线: 贯穿整个系统的是一组电子管道,称作总线,它携带信息字节并负责在各个部件间传递。通常总线被设计成传送定长的字节块,也就是字(word)。字中字节数(即字长)是一个基本的系统参数。有些计算机是4个字节(32位),有些是8个字节(64位)。
- I/O设备:键盘和鼠标就是I/O设备。每个I/O设备都通过一个控制器或适配器与I/O总线相连。控制器和适配器之间的区别主要在于他们的封装方式。控制器是I/O设备本身或系统的主印制电路板上的芯片组。而适配器是一块插在主板插槽上的卡。
- 主存:临时存储设备。在处理器执行程序时,用来存放程序和程序处理的数据。从物理上说,主存是由一组动态随机存取存储器(DRAM)芯片组成的。从逻辑上说,存储器是一个线性的字节数组,每个字节都有其唯一的地址(数组索引),这些地址是从零开始的。
- 处理器:中央处理单元(CPU),简称处理器,是解释(或执行)存储在主存中指令的引擎。处理器的核心是一个大小为一个字的存储设备(或寄存器),称为程序计数器(PC)。在任何时刻,PC都指向主存中的某条机器语言指令(即含有该条指令的地址)。
4 处理器一直在不断地执行程序计数器指向的指令,再更新程序计数器,使其指向下一条 指令。处理器看上去是按照一个非常简单的指令执行模型来操作的,这个模型是由指令集架构决定的。在这个模型中,指令按照严格的顺序执行,而执行一条指令包含执行一系列的步骤,处理器从程序计数器指向的内存处读取指令,解释指令中的位,执行该指令指示的简单操作,然后更新PC,使其指向下一条指令,而这条指令并不一定和在内存中刚刚执行的指令相邻。
4 处理器执行的简单操作,围绕主存,寄存器文件(register file)和算术/逻辑单元(ALU)进行。寄存器文件是一个小的存储设备,由一些单个字长的寄存器组成,每个寄存器都有唯一的名字。ALU计算新的数据和地址值。
5 CPU在指令的要求下可能会执行这些操作
- 加载:从主存复制一个字节或一个字到寄存器,以覆盖寄存器原来的内容
- 存储:从寄存器复制一个字节或一个字到主存的某个位置,以覆盖这个位置原来的内容
- 操作:把两个寄存器的内容复制到ALU,ALU对这两个内容做算术运算,并将结果存放到一个寄存器中,以覆盖该寄存器中原来的内容
- 跳转:从指令本身中抽取一个字,并将这个字复制到程序计数器(PC)中,以覆盖PC中原来的值
6 针对处理器与主存间的差异,系统设计者采用了更小更快的存储设备,称为高速缓存存储器(cache memory,简称为cache或高速缓存),作为暂时的集结区域,存放处理器近期可能会需要的信息。
高速缓存还分几级,位于处理器芯片上的L1高速缓存访问速度几乎和寄存器一样,L2高速缓存通过一条特殊的总线链接到处理器。L1和L2高速缓存是用一种叫做静态随机访问存储器(SRAM)的硬件技术实现。
7 存储设备的层次结构
8 所有应用程序对硬件的操作都必须通过操作系统。操作系统有两个基本功能:防止硬件被失控的应用程序滥用;向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。
9 操作系统的抽象表示
文件是对I/O设备的抽象表示,虚拟内存是对主存和磁盘I/O设备的抽象表示,进程则是对处理器,主存和I/O设备的抽象表示。
10 并发运行,是说多个进程的指令交错执行
11 无论是在单核还是多核系统中,一个CPU看上去都像是在并发地执行多个进程,这是通过处理器在进程间切换来实现。操作系统实现这种交错执行的机制称为上下文切换。操作系统保持跟踪进程运行所需的所有状态信息。这种状态就是上下文,比如PC和寄存器文件的当前值,以及主存的内容。
12 从一个进程到另一个进程的转换都是由操作系统内核(kernel)管理。内核是操作系统代码常驻主存的部分。当应用程序需要操作系统的某些操作时,比如读写文件,它就执行一条特殊的系统调用(system call)指令,将控制权传递给内核。然后内核执行被请求的操作并返回应用程序。
内核不是一个独立的进程,它是系统管理全部进程所用代码和数据结构的集合。
13线程:在现在系统中,一个进程实际上可以由多个称为线程的执行单元组成,每个线程都运行在进程的上下文中,并共享同样的代码和全局数据。
14 虚拟内存:每个进程看到的内存是一致的,称为虚拟地址空间。下图为Linux进程的虚拟地址空间。
在Linux中,地址空间最上面的区域是保留给操作系统中的代码和数据的。地址空间的底部区域是用户进程定义的代码和数据。图中的地址是从下往上增大的。
虚拟地址空间从下往上,依次为 程序代码和数据, 堆,共享库,栈,内存虚拟内存。
- 程序代码和数据:直接按照可执行目标文件的内容初始化。在进程一开始进行时就被指定了大小。
- 堆:如C语言时,当调用像malloc和free这样的C标准库函数时,堆可以在运行时动态扩展和收缩。
- 共享库:存放像C标准库和数学库这样的共享库的代码和数据
- 栈:编译器用它来实现函数调用。用户栈在程序执行期间可以动态扩展和收缩。特别地,每次调用一个函数时,栈就会增长;从一个函数返回时,栈会收缩。
- 内核虚拟内存:为内核保留的,不允许应用程序读写这个区域的内容或直接调用内核代码定义的函数。
15 虚拟内存的运作基本思想是把一个进程虚拟内存的内容存储在磁盘上,然后用主存作为磁盘的高速缓存。
16 文件是字节序列。