深入理解计算机系统_第1章 计算机系统漫游

引言

通过学习深入理解计算机系统(CSAPP),你将收获:

  • 一些实践技巧,比如如何避免计算机表示数字引起的奇怪的数字错误。
  • 一些小窍门来优化自己的C代码,以充分利用现代处理器和存储器系统的设计。
  • 了解编译器是如何实现过程调用的,以及如何避免缓冲区溢出错误带来的安全漏洞。
  • 学会如何识别和避免链接时那些令人讨厌的错误。
  • 学会如何编写自己的Unix shell、自己的动态存储分配包,甚至于自己的web服务器。
  • 认识并发带来的希望和陷阱,这个主题随着单个芯片上集成了多个处理器核变得越来越重要。

在某种意义上,这本书的主要内容是通过以下hello程序在系统中的运行,了解系统发生了什么以及为什么会这样。

#include <stdio.h>
int main()
{
    
    
	printf("hello world\n");
	return 0;
}

1.1 信息就是位+上下文

  • hello程序的生命周期是从一个源程序开始的,这个源程序被命名为hello.c。
  • 源程序实际上是由0和1序列组成的位序列,8个位被组织成一组,称为字节(byte),每个字节表示程序中的某些文本字符。
  • 大部分现代计算机采用ASCII码表示文本字符,这种方式其实就是用一个唯一的单字节大小的整数值来表示每个字符。
  • hello.c程序是以字节序列的方式存储在文件中的,每个字节都有一个整数值,对应于某些字符。
  • hello.c的表示方式说明了一个基本思想:系统中的所有信息——包括磁盘文件、内存中的程序、用户数据以及网络上传送的数据,都是由一串比特表示的。
  • 区分不同数据对象的唯一方法就是根据我们读到的这些数据对象的上下文。

1.2 程序被其他程序翻译成不同的格式

  • hello程序从高级C语言程序开始,因为这容易被人读懂。
  • 然而,为了在系统上运行hello.c程序,需要将C语言转化为低级机器语言指令
  • 然后将这些指令按照一种称为可执行目标程序的格式打包好,并以二进制磁盘文件的形式储存起来。目标程序也称为可执行目标文件
  • 在unix系统上,从源文件到可执行目标文件的转化是由编译器驱动完成的。
  • 编译器驱动将c源程序文件翻译成可执行目标文件,这个翻译过程有四个阶段(预处理器,编译器,汇编器,链接器),它们构成了编译系统
hello.c源程序文本
hello.i修改的源程序文本
hello.s汇编程序文本
hello.o可重定位二进制目标程序
hello可执行二进制目标程序
printf.o文件
开始
预处理器cpp
编译器ccl
汇编器as
链接器ld
结束
printf函数
  • 预处理阶段:预处理器cpp根据以#开头的命令,修改原始的c程序。
  • 编译阶段:编译器ccl将文本文件hello.i翻译成hello.s,它包含一个汇编语言程序。
  • 汇编阶段:汇编器as将hello.s翻译成机器语言的指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o中。hello.o是二进制文件,它包含的17个字节是函数main的指令编码。如果我们在文本编辑器中打开了hello.o文件,我么将看到一堆乱码。。
  • 链接阶段:hello程序调用了printf函数,它是每个c编译器都提供的标准c库中的一个函数。printf函数存在于一个名为printf.o的单独的预编译好了的文件中,链接器ld负责将hello.o和printf.o合并,最后得到hello可执行目标文件,可以被加载到内存中,由系统执行。

1.3 了解编译系统如何工作是大有益处的

下面是一些重要的原因促使程序员必须知道编译系统是如何工作的。

  • 优化程序性能:为了在C程序中做出好的编码选择,我们需要了解一些机器代码以及编译器的不同的C语句转化为机器代码的方式。
  • 理解链接时出现的错误:根据经验一些令人困扰的程序错误往往都与链接操作有关,尤其是当你想要构建大型的软件系统时。
  • 避免安全漏洞:缓冲区溢出错误是造成大多数网络和Internet服务器安全漏洞的主要原因。存在这些错误是因为很少有程序员能够理解需要限制从不受信任的源接收数据的数量和格式。学习安全编程的第一步就是理解数据和控制信息存储在程序栈上的方式会引起的后果。

1.4 处理器读并解释储存在内存中的指令

1.4.1 系统的硬件组成

  • 总线
  • 贯穿整个系统的是一组电子管道,称作总线。
  • 它携带信息字节并负责在各个部件之间传递。
  • 通常总线被设计成传送定长的字节块,也就是
  • 字中的字节数(字长)是一个基本的系统参数,现代大多数机器字长要么是四个字节(32位),要么是8个字节(64位)。
  • I/O设备
  • I/O设备是系统与外部联系的通道,比如鼠标、键盘、显示器以及磁盘。
  • 每个I/O设备都通过控制器或者适配器与I/O总线相连。
  • 主存
  • 主存是一个临时存储设备,在处理执行程序时,用来存放程序和程序处理的数据。
  • 从物理上说,主存是由一组动态随机存取存储器(DRAM) 组成的。
  • 从逻辑上来说,存储器是一个线性的字节数组,每个字节都有一个唯一的地址(数组索引),这些地址是从零开始的。
  • 处理器
  • 中央处理单元(CPU) (简称处理器)是解释或者执行存储在主存中指令的引擎。
  • 处理器的核心为一个大小为一个字节的存储设备(寄存器),称为程序计数器(PC),PC始终指向主存中的某条机器语言指令(即含有该条指令的地址)。
  • CPU在指令的要求下可能会执行以下简单操作:
  • 加载:从主存拷贝一个字节或者一个字到寄存器。
  • 存储:从寄存器拷贝一个字节或者一个字到主存的某个位置。
  • 操作:把两个寄存器的内容复制到ALU,ALU对这两个数做算术运算,然后再把计算的结果放到寄存器中。
  • 跳转:从指令中抽取一个字,将这个字复制到程序计数器中。

1.4.2 运行hello程序

运行hello程序需要经历三个阶段,首先从键盘上读取hello命令,其次从磁盘加载可执行文件到主存,最后将输出字符串从存储器写到显示器。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.5 高速缓存至关重要

1.6 存储设备形成层次结构

在这里插入图片描述

1.7 操作系统管理软件

  • 操作系统的定义:操作系统是硬件和应用程序之间的一层软件。
  • 操作系统的功能:
    • 防止硬件被失控的应用程序滥用。
    • 向应用程序提供一些简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。
  • 实现机制:
  • 文件:对I/O设备的抽象。
  • 虚拟内存:对主存和I/O设备的抽象。
  • 进程:对处理器、主存和I/O设备的抽象。

1.7.1 进程

  • 进程:是对正在运行的应用程序的抽象。
  • 并发运行:一个进程的指令和另外一个进程的指令是交错执行的。
  • 上下文切换:系统实现交错执行的机制。此时会保存当前进程的上下文,回复新进程的上下文。

1.7.2 线程

  • 线程:一个进程可以由多个称为线程的执行单元组成,每个线程都运行在进程的上下文中。

1.7.3 虚拟内存

虚拟内存由大量准确的区构成,每个区都有专门的功能,这些区的名称如下:

  • 程序代码和数据
  • 共享库
  • 内核虚拟存储器

1.7.4 文件

  • 文件只不过是字节序列。每个I/O设备都可以看成文件。

1.8 系统之间利用网络通信

猜你喜欢

转载自blog.csdn.net/weixin_43567146/article/details/115253719