深入理解计算机系统(CSAPP)第一章 计算机系统漫游
计算机系统是由硬件和系统软件组成的
1.1 信息就是位+上下文
程序的生命周期是从一个源程序开始的。源程序实际上是一个由0和1组成的位(比特),8个位被组织成一组,称为字节。
大部分的现代计算机系统都是用ASCII标准来表示文本字符。
每个文本行都是以一个看不见的换行符\n
来结束的,对应的整数值 为10。像hello.c
这样只由ASCII字符构成的文件称为文本文件,所有其他文件都成为二进制文件
系统中所有的信息,比如磁盘文件、内存中的数据以及网络上传输的数据,都是有一串比特表示的。区分它们的唯一方法就是我们读到这些数据时的上下文。
1.2 程序被其他程序翻译成不同的格式
GCC编译器将每条C语句转化为一系列的低级机器语言指令,然后这些指令按照可执行目标程序的格式打包,最后以二进制磁盘文件的形式存放起来。因此最后编译出来的目标程序也叫可执行目标文件。
Unix上,从源文件到目标文件的转化是由编译器驱动的:
linux> gcc -o hello hello.c
如下图所示:
以上四个阶段的程序共同组成了编译系统(compilation system)
- 预处理阶段:预处理器(cpp)读取头文件,并直接插入到程序中去,便得到了
hello.i
文件。 - 编译阶段:编译器(ccl)将
hello.i
翻译成汇编语言,得到hello.s
文件 - 汇编阶段:汇编器(as)将
hello.s
文件翻译成机器语言指令,并打包成可重定位目标程序(relocatable object program)格式,将结果保存在hello.o
中,该文件是一个二进制文件。 - 链接阶段:链接器(ld)将多个文件链接到一起进行合并,得到
hello
文件,该文件是一个可执行目标文件(或简称可执行文件),可以被加载到内存中,被系统执行。该文件也是一个二进制文件。
1.3 了解编译系统如何工作是大有益处的
- 优化程序性能:
switch
语句是否总是比if-else
更高效?一个函数的调用开销有多大?指针引用是否比数组索引更高效?等等 - 理解链接时出现的错误:一些令人困扰的程序错误往往都与连接器的操作有关。
- 避免安全漏洞:比如缓冲区溢出,这个错误是造成大多数网络和服务器上安全漏洞的原因。
1.4 处理器读并解释储存在内存中的指令
已经得到可执行目标文件hello
,并且存放在磁盘上,以下方式可以执行:
linux> ./hello hello, world linux>
shell
是一个命令行解释器,它输出一个提示符,等待命令的输入,然后执行这个命令。
为什么要加./
符号呢:
shell
拿到一个命令后,它搜寻该命令的顺序是:别名(alias)-> 内置命令 -> PATH环境变量。并不会搜寻当前目录,因此需要加绝对路径在指定。
不在当前路径搜寻的原因:用./
的原因是unix为了防止黑客,path中不包含当前目录,搜索一个命令的时候并不会搜索当前目录,所以想执行当前目录下的命令就必须用./xxxx
,其中.表示当前目录。
如果搜索命令的时候会从当前目录下搜索,黑客就会在自己有权限的一些目录构造一些类似cd..
这样的木马程序,万一管理员执行cd ..
的时候中间的空格打太快漏掉了,就把木马给执行了。要是像windows这样当前目录还要优先搜索的操作系统,甚至直接构造cd,ls
这样的木马就可以轻松让管理员中招。[链接]
1.4.1 系统的硬件组成
下图为Intel系统产品族的模型:
- 总线
总线是贯穿整个系统的一组电子管道。负责在各个部件之间传递信息字节,总线一般被设计成传送定长的字节块,成为字(word) 。一个字中有多少字节是一个基本的系统参数,但是根据系统的不同而有所不同,比如32位机器(4个字节)、64位机器(8个字节)。
- I/O设备
I/O设备是与外界联系的通道,每个IO设备都由控制器或者适配器与I/O总线连接。控制器与适配器之间的不同主要在于封装方式不同。控制器是设备本身或者系统的主印制电路板(主板)上的芯片组,而适配器则是一块插在主板插槽上的卡(比如显卡)。但是他们的功能都是一样的:在I/O总线和I/O设备间传递信息。
- 主存
主存是一个临时存储设备,程序运行时存放程序和程序处理的数据。物理上说,主存是由一组动态随机存取存储器(DRAM) 芯片组成。逻辑上来说,存储器是一个线性的字节数组,每个字节都由唯一的地址(数组索引),地址从零开始。
4. 处理器
即中央处理单元(CPU)。它是解释/执行存储在主存中指令的引擎。处理器的核心是一个大小为一个字的存储设备(或寄存器),成为程序计数器(PC) 。任何时候,程序计数器都指向主存中的某条机器语言指令(即含有该条指令的地址)。
处理器按照指令集架构去顺序执行指令。
CPU在指令的要求下可能会进行以下操作:
- 加载:从主存复制一个字或字节到寄存器,覆盖原来内容。
- 存储:从寄存器复制一个字或字节到主存,覆盖原来内容。
- 操作:把两个寄存器的内容复制到ALU做计算,将结果放到另一个寄存器,覆盖。
- 跳转:从指令本身抽取一个字,并将这个字复制到PC中,覆盖。
指令集架构:描述每条机器指令的效果。
微体系结构:处理器实际是如何实现的。
1.4.2 运行hello程序
在shell中输入./hello
后:
- shell读取字符到寄存器,然后再存放到主存中:
- 敲回车键后,shell执行一系列指令将hello目标文件中的代码从磁盘复制到主存。可以利用直接存储器存取(DMA) 技术。数据可以不通过处理器而直接从磁盘到达主存。
- 代码和数据被加载到主存后,处理器开始执行hello程序的main程序中的机器语言指令。
"hello,wor\n"
字符串从主存复制到寄存器文件,再从寄存器文件复制到显示设备。最终显示在屏幕上。
1.5 高速缓存至关重要
系统花费了大量的时间将信息从这个地方复制到另一个地方,这就是开销,系统设计者的一个主要目标就是减少这些开销。
根据机械原理,较小的存储设备要比较大的存储设备运行的快,但是相应的造价就更高。
针对处理器和主存之间的差异,设计者采用了更小更快的存储设备,称为高速缓存存储器(cache memory) ,作为暂时的集结区域,主要存放处理器近期可能会需要的信息。一般会有三级高速缓存:L1、L2、L3,他们都是
静态随机访问存储器(SRAM) 。
1.6 储存设备形成层次结构
存储器层次结构的主要思想是:上一层的存储器作为低一层存储器的高速缓存。比如:L3是主存的高速缓存,主存又是磁盘的高速缓,以此类推。
1.7 操作系统管理硬件
所有应用程序对硬件的操作尝试都必须通过操作系统。作用主要在于:
- 防止硬件被失控的应用程序滥用
- 提供简单一致的接口去操作复杂且大不相同的低级硬件设备。
操作系统通过几个基本的抽象概念去实现以上两个功能:进程、虚拟文件和文件。
1.7.1 进程
进程是操作系统对一个正在运行的程序的一种抽象。在一个系统上可以同时运行多个进程,而每个进程对外都好像在独占硬件。
并发运行是指一个进程的指令和另一个进程的指令交错执行,这个过程叫做上下文切换。上下文是指操作系统为了保持跟踪进程运行所需要的所有的状态信息,比如PC、寄存器文件的当前值和主存的内容。
从一个进程到另一个进程的转换是由操作系统内核(kernel)管理的。内核是操作系统代码常驻在内存的部分。
内核不是一个独立的进程,它是系统管理全部进程所用代码和数据结构的集合
1.7.2 线程
现代系统中,一个进程实际上是由多个称为线程的执行单元组成,每个线程都运行在进程的上下文之中,并且共享同样的代码和全局数据。因为线程比进程更容易共享数据,所以线程一般来说都比进程更加高效。
1.7.3 虚拟内存
虚拟内存是一个抽象概念,它给每一个进程提供了一个假象:每个进程都在独占地使用主存。每个进程看到的内存都是一致的,称为虚拟地址空间。
在Linux中,地址空间最上面是保留给操作系统中的代码和数据的。最下面是存放用户进程定义的代码和数据的。从下往上,地址增大。
- 程序代码和数据:进程一开始就被制定了大小。
- 堆:可以在程序运行时动态地扩展和收缩(malloc,free等)。
- 共享库:位于中间部分,存放C标准库和数学库这样的共享库的代码和数据。
- 栈:编译器使用它来实现函数调用。也可以动态地扩展和收缩。调用一个函数,栈增加;返回一个函数,栈减小。
- 内核虚拟内存:顶部区域,为内核保留。不允许应用程序读写,或者直接调用内核函数。
虚拟内存的主要思想是把一个进程的虚拟内存的内容存储在磁盘上,然后用主存作为磁盘的高速缓存。
1.7.4 文件
文件就是字节序列。每个IO设备甚至网络都可以看做是一个文件。
1.8 系统之间利用网络通信
现代系统一般都通过网络和其他系统连接在一起。通过网络传输信息无非就是把自己主机的信息复制到另外一台主机。与之前执行hello程序一样,只不过这次传输用的是网络,而不是总线。
1.9 重要主题
系统不仅仅是硬件,而是软件和硬件的结合体,他们必须共同协作已达到运行应用程序的目的。
1.9.1 Amdahl定律
Gene Amdahl,计算机领域的早起先锋之一。
主要观点:要想显著加速整个系统,必须提升系统中相当大的部分的速度。
1.9.2 并发和并行
- 线程级并发
- 指令级并发
- 单指令、多数据并发
1.9.3 计算机系统中抽象的重要性
1.7中已经介绍了三种基本抽象,现在再添加一个虚拟机
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!