深入理解计算机系统 - 读书笔记

416 阅读10分钟

这篇是笔者在初读CSAPP时的读书笔记,写的比较简陋,如果有掘友感兴趣我会继续完善,欢迎交流~

深入理解计算机系统

系统的四大硬件组成

处理器CPU 解释执行主存中指令的引擎

主存RAM 临时存储设备,存放程序和数据

I/O设备 与外部设备连通的通道,如硬盘、显示器

系统总线BUS 在系统各个部件传递信息(字)

指令集架构和微体系结构

指令集架构关注每条机器指令实现的效果,而微体系结构关注处理器如何实现。

处理器体系结构

核心:运算+控制

指令集体系结构ISA:指令+指令的编码

微体系结构:处理器如何实现

CPU基本组成

  • ALU算术逻辑单元

  • PC程序计数器 正在运行的指令的主存地址

  • 寄存器组REG

    • 通用寄存器
    • 特殊寄存器
      • 指令寄存器IR

      • 存储器数据寄存器MDR、存储器地址寄存器MAR

      • PSW程序状态字寄存器:

        • 条件码 运算结果的保存 ,如进位标志、零标志、符号标志

        • 状态码 控制指令正常/异常,如中断、溢出

  • 总线接口

以CISC 复杂指令集计算机为例:

RISC和CISC区别

指令数量 早期RISC不到100个,现在妥协

指令编码长度,RISC为定长

寻址方式 RISC只支持简单寻址

操作对象 RISC只能对寄存器进行,必须先从内存中载入(被称为Load/Store提携结构),并且没有状态码,需要用测试指令进行。

指令类型

  • 数据传送指令:立即数 寄存器 内存 mov

  • 运算指令(整数、浮点数、逻辑)add sub

  • 跳转指令 jmp

  • 条件传送 cmov

  • 函数调用返回 call ret、入栈出栈、结束

**寻址方式(**寻址:本质是寻数据)

立即数:指令中直接给出数据,传送到寄存器中

寄存器寻址:给出寄存器名,用寄存器的值进行操作

寄存器间接:给出寄存器名,取出寄存器中的存储的地址上的数据

寄存器偏移寻址:给出寄存器名,在数据移动前先进行算术偏移

基址寻址:给出基址寄存器,以及偏移量,但通常基址不可变

变址寻址:基址可变的基址寻址,如采用PC作为基址。

对于CISC,其还可以直接访问内存:

直接寻址:给出操作数在内存的地址

间接寻址:给出操作数内存地址的地址

执行过程

取指、fetch

译指、decode

执行、execute

访存、写回:memory 从内存读取或写入数据

中断检查:

更新PC

流水线

流水线即不同阶段并行操作

处理一条指令时,将其划分为一个个环节,在完成一个环节后,进入下一条指令,而无需等待一整个指令处理完成后才进入下一条。

流水线性能

冒险或冲突:前后的依赖性导致流水线计算错误。

数据冒险:由于延迟导致还未写回时就被下一条读取。解决:数据旁路

控制冒险:转移指令等导致PC值断流。解决:预测PC而不保存

资源冲突:多条指令同时访问某个互斥资源

周期

  • 指令周期 执行一条指令的完成时间
    • 取指 PC-》IR
    • 间址 取操作数
    • 执行
    • 中断
  • 机器周期 定义读取一个指令的时间
  • 时钟周期 最小单位,T周期或节拍,晶振频率的倒数

Clock Per Instructions,CPI:执行一条指令所需时钟周期数

MIPS:每秒多少百万条指令=主频/CPI

存储器层次结构

主要思想:上一层的存储器都是下一层存储器的缓存。

结构

CPU寄存器 L1-L3高速缓存(SRAM)主存DRAM 辅存 (磁盘) 网盘

随机访问存储器

SRAM 采用双稳态触发器、速度快、不敏感

DRAM 用电容来存储、需要不断刷新、速度较慢、对光和电噪声敏感

局部性原理

时间 空间

高速缓存

高速缓存基本结构

对于一个存储器位宽为m的,共有2m2^m个存储单元,缓存通过类似哈希的结构(索引+数据)进行映射。

高速缓存结构(S,E,B)的主要组成:

组S:多个行构成一组,共有S=2sS=2^s组(组的一级索引)。

​ 按照组数和行数的关系,缓存可分为:

  • 直接映射高速
  • 组相连映射
  • 全相联映射

行E:一行中包括有效位、标记位(组内的二级索引)和块(数据)。

块B:一个块中有多个字。

直接映射高速缓存

每组只有一行。

  • 寻址方法

    • 三步走:组选择、行匹配、块抽取

    将m位存储器地址划分为三个部分:

    ​ 组索引位于地址的中部,而不是首部。

    ​ 原因:如果用首部作索引,那么存储器连续的一段地址是冲突的,这样连续访问时每次都不命中,而用中间位使得连续的一段地址映射到不同的组,进而彼此不冲突,可以连续读完一段后再替换,缓存命中率更高。

组相连高速缓存

  • 替换策略

    直接映射由于组内只有一行,因此直接替换即可。而组相连则设计组内选择哪一行替换。

    最不常使用LFU:替换时间窗口内使用次数最少

    最近最少使用LRU:替换上一次访问最久远的那个。

全相连映射

组索引退化,只剩标记位。

写回策略

需要更新时,如何通过缓存进而写主存。

  • 直写write-through:有更改时立即写入,问题时耗费总线资源过大。
  • 写回write-back:尽可能推迟更新,该快要被替换前才写入,问题是需要引入额外的修改位。
  • 写不命中时,直写通常采用写分配(读-更改-写),而写回则采用非写分配(直接写存储器)。

操作系统管理硬件

虚拟内存空间:给每个进程提供了一种假象,每个进程都独占一个连续空间,因此无需关注(物理)寻址问题,由操作系统进行虚拟地址和物理地址的转换。

这个空间根据进程切换来从磁盘到主存之间进行缓存。

  • 进程的虚拟地址空间,从上到下依次为:

    内核

    栈区

    共享库的内存(给库函数分配的)

    堆区

    读写数据

    只读代码和数据

IO设备

总线

程序运行

信息表示和处理

信息 = 位(bit串) + 上下文信息(到底是整数、字符串还是指令)

程序机器级表示

程序编译过程

编译系统

1 预处理器:插入头文件 .c->.i

2 编译器:将程序转换为汇编程序 ->.s

3 汇编器:将汇编程序转换为机器语言(二进制),可重定位目标程序

4 链接器:将库函数程序段合并进来

经历上述步骤后,可执行文件储存在磁盘中

处理器读取磁盘中的程序

链接

将各种代码和数据片段合成一个单一文件

编译时

加载时

运行时

编译器驱动程序

执行预处理、编译器、汇编、链接四个步骤,如果最终需要被执行,加载器加载到内存中

链接器的输入是多个已编译好的可重定位目标文件.o文件,输出为可执行目标文件

如何进行链接?

静态链接

可重定位目标文件 生成 可执行目标文件

链接器的两个任务(步骤)

  • 符号解析 将符号定义(函数变量名的定义)和符号引用(函数变量的引用)关联起来
  • 重定位 将符号定义和内存地址关联起来,使得所有的符号引用指向到该内存地址
目标文件

链接器的输入或输出。纯粹是字节块的集合,包含程序和数据。

  • 可重定位目标文件 编译时静态地连接建立
  • 共享目标文件 特殊的可重定位,可以在加载时和运行时动态地
  • 可执行目标文件 包含二进制程序和数据,可直接复制到内存中执行

目标文件格式有很多,现代系统使用的是可执行可连接格式(ELF)

可重定位目标文件

ELF标准格式。

包含程序机器代码、变量、只读数据。

符号和符号表

.symtab

根据谁定义、谁引用,划分为三种不同的符号:全局符号、局部符号

区分局部链接器符号和局部变量。

static创建的静态局部变量将不在

符号解析
  • 对全局符号的解析

    • 多符号重名时,有限选择强符号的定义(被初始化过的值)
  • 与静态库链接 func.o -> lib.a

    • 静态库:将相关的目标文件打包成一个单独的文件

    • 使用库可以节约内存、节约编译时间、减少手动链接错误

    • 在链接时,链接器只复制被程序调用到的目标模块到内存

      • 如何用静态库解析引用

        • 维护可重定位目标文件集合E 待解析符号U 已解析D

        • 对于所有输入文件f,如果是目标文件E,就添加到E并且修改UD

        • 如果是库,则对于库中的每一个文件m,如果其中有解析U中的引用,则将m加入E并修改UD

重定位

解析后,知道了代码和数据的大小,重定位中进行模块合并,并分配运行地址。

从大到小两步走:

  • 合并同一类型的节并分配地址 聚合节,最终每条指令和全局变量有了地址

  • 依赖于重定位条目,修改节中每个符号的引用为各自的地址。

可执行目标文件

同样是ELF文件头

中断和异常

计算机正常的控制流是连续的,而为了使计算机具备能够响应外部事件,调用跳转以及处理故障等功能,出现了异常控制流ECF,异常就是控制流中的突变。

异常发生的过程:由事件触发,控制转移到异常处理程序,最后异常返回(也可能不返回)。

系统启动时,初始化异常表,其中存储的是异常处理程序的入口地址,对于中断而言,是中断向量。

异常分为中断、陷阱、故障和中止。中断是异步发生的,即外部信号导致。而后三者是同步的,由指令执行导致。

中断

由硬件触发异常,软件进行响应。

  • 当指令执行时CPU的中断引脚的电平发生变化(中断信号产生)

  • 在指令执行完后,从系统总线读取异常号

  • 根据异常号来寻找中断服务程序的地址(中断向量表),并保存断点(PC压栈)

    • 调用前保护现场,即将当前程序压栈(PC、PSW和寄存器数据)
    • 跳转到中断服务程序的第一句
    • 恢复现场
  • 注意,在执行中断控制操作时,必须要关中断,防止现场保护恢复不完整

  • 中断屏蔽

    在处理器处理关键事件时,中断允许寄存器复位,不响应某些中断。

  • 中断嵌套

    ​ 中断运行时,又遇到中断,此时根据优先级来决定是否响应,处理完高优先级后再处理低优先级

陷阱

有意的异常,用于请求系统服务调用。

故障

执行错误(可恢复),缺页中断等

中止

执行错误(不可恢复),内存错误

虚拟内存

(未完待续)