Noname's Blog
信息安全专业的小萌新,立志走上更大的舞台
《CSAPP》第一章 计算机系统漫游.md

《CSAPP》第一章 计算机系统漫游

万事开头难。。读这本书是真难

大概会结合一些视频,和书的内容来做这个笔记

第一个hello程序

书的第一页则是一个hello程序

#include<stdio.h>

int main()
{
	printf("hello, world\n");
    return 0;
}

hello.c也称为源程序,是一个由0和1组成的位序列,每8个位为一组称为字节,每个字节表示程序中的文本字符。其由ASCII字符构成,所以称为文本文件。

内存中存放的数据实际都是一串比特流,需要通过上下文(content)对其进行区分。

如何在系统上运行hello.c程序?

要将改程序内容转化为低级语言,让机器能看懂,即将源程序转换成目标程序(可执行目标文件)

每条C语句都必须被其他程序转化为一系列的地基机器语言指令,然后这些指令按照一种称为可执行目标程序的格式打好包,并以二进制磁盘文件的形式存放起来。

Unix系统下 编译器驱动程序:

gcc -o hello hello.c

1.png

  • 预处理阶段。预处理器将以字符#开头的命令修改原始的C程序,并将所引用的头文件的内容直接插入到程序文本中,得到hello.i
  • 编译阶段。编译器将hello.i翻译成hello.c,包含一个汇编语言程序
  • 汇编阶段。汇编器将hello.s翻译成机器语言指令,并打包成可重定位目标程序的格式,将结果保存在hello.o中
  • 链接阶段。由于printf是C标准库中的函数,所以C编译器中有已经编译好的printf.o,在该阶段将这个文件与hello.o合并,得到可执行目标文件hello,将文件加载到内存中由系统执行

利用shell执行可执行文件

./hello

shell:命令行解释器,输出提示符后等待输入一个命令行,然后执行该命令,若输入的不是内置命令,则会假设这是一个可执行文件的名字并加载运行这个文件。

系统硬件组成

1.总线:携带信息字节并负责在各个部件间传递

2.I/O设备:Input/Output

3.主存:临时存储设备,在处理器执行程序时,用来存放程序和程序处理的数据。

4.处理器:

CPU,是解释或执行存储在主存中指令的引擎。

处理器的核心:PC(程序计数器)[大小为一个字的存储设备]

寄存器文件由一些单个字长的寄存器组成,每个寄存器都有唯一的名字,由ALU计算新的数据和地址值。

cpu.png

hard.png

运行hello程序

2.png4.png3.png

当输入了./hello并敲击回车后,shell会认为我们已经结束输入,shell会执行一系列指令来加载可执行hello文件。

shell可以执行一系列指令让可执行hello文件不经过处理器直接从磁盘到达主存,执行后输出(DMA技术)。

一旦目标文件hello中代码和数据被加载到主存,处理器就会开始执行hello程序中的main程序中的机器语言指令,这些指令会一路经过各种硬件,最终显示在屏幕上。在信息从一个地方挪到另一个地方的过程中需要花费大量时间,所以如何减少这个过程上的各种开销,成为了程序员的主要工作。

高速缓存

在读取、内存、开销等方面,每个设备有着不一样的表现。

例如处理器寄存器中读取数据比从主存中读取要快非常多,这样的速度差异导致处理器有可能在很长一段时间保持闲置的状态,这样是一种资源的浪费。所以可以在这样两个工作速度差异很大的设备之间加一个高速缓存存储器(cache),专门用于存储近期还需要使用的信息。

即在处理器和一个较大较慢的设备(例如主存)之间插入一个更小更快的存储设备(例如高速缓存)

cache.png

操作系统

操作系统的基本功能:

(1)防止硬件被失控的应用程序滥用

(2)向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备

文件是对I/O设备的抽象,虚拟内存是对主存和磁盘I/O设备的抽象,进程则是对处理器、主存和I/O设备的抽象

当一个程序开始乱写数据,让它不会影响到其他程序,这波操作是操作系统的重要功能之一:Memory Protection

而另一种调度功能,能在单个cpu上实现同时运行多个程序

进程

进程是操作系统对一个正在运行的程序的一种抽象。能让我们在使用某一个程序的时候以为操作系统只在被该程序占用,实际上后台的程序是在交错的运行(并发运行),但是由于cpu的执行速度非常快,所以我们察觉不出来。

单核处理器在同一时刻只能执行一个程序,而现在有多核处理器使得能同时执行多个进程,这样在进程间来回切换,实现交错执行的机制称为上下文切换

context.png

上下文就是进程运行所需的状态,被记录在操作系统中,当进程A运行到某一阶段,需要切换到进程B,操作系统就会记录下当前进程A的上下文,再进行切换。这一的切换操作时由**操作系统内核(kernel)**管理的。

线程

一个进程由很多个线程组成,每个线程运行在进程的上下文并共享全局的信息。

虚拟内存

虚拟内存为每个进程提供一个独自占用主存的假象,每个进程看到的内存都是一致的,都是从0开始。实际的物理位置被操作系统隐藏和抽象了。操作系统会维护一张表,用于说明真实物理地址和虚拟地址的映射。

virtual.png

这是crash course简单说明虚拟内存的一张图,当程序A被分配两块不相邻的内存的情况。

当程序A运行时,操作系统分配给它0-999的内存空间,又将1000-1999的内存地址分配给了程序B,当A需要更大的空间,操作系统同意分配给它2000-2999的内存空间,但是在A的视角,它拥有一块连续的大小为2000的内存空间。当A要读取下一个地址1000时,实际上是映射到了物理地址2000。这样的动态内存分配为同时运行多个程序提供了灵活性,同时也起到了隔离的作用。

vv.png

可以看到用户栈位于虚拟地址空间的顶部,函数的调用和返回就是入栈和出栈。

文件

文件就是文字序列,仅此而已,每个I/O设备,包括磁盘、键盘、显示器甚至网络都可以看成是文件。

文件这个简单而精致的概念是非常强大的

众所周知Linux的设备本质上都是文件,所以精致这个词还是挺妙的

系统之间利用网络通信

把系统视为一个孤立的软件和硬件的集合体,就可以通过网络与其他系统相连。

Amdahl定律

主要思想:当我们对系统的某个部分加速时,其对系统整体性能的影响取决于该部分的重要性和加速程度

并发和并行

并发:指一个同时具有多个活动的系统

并行:指的是用并发来使一个系统运行得更快。

在20世纪60年代,出现了时间共享的概念,分时操作系统可以处理多个程序和多个用户,每个用户只能分到一小部分处理器和内存等。

线程级并发

在一个进程中执行多个控制流,实现多线程,一项允许一个cpu执行多个控制流的技术。进程并发实际上是一种模拟,在很短时间内实现进程间的快速切换,而多线程处理器又可以在单个桌旗的基础上决定要执行哪一个进程,减少资源的浪费。

xb.png

指令级并行

流水线(pipelining),将执行一条指令所需要的的活动划分成不同的部分,再将处理器的硬件组织成一系列的阶段,每个阶段执行一个步骤,这些阶段可以并行地操作,处理不同指令的不同部分。

单指令、多数据并行

在最低层次上,许多现代处理器拥有特殊的硬件,允许一条指令产生多个可以并行执行的操作。

计算机系统中抽象的重要性

chouxiang.png