跳转至

异常控制流

约 1221 个字 预计阅读时间 4 分钟

从给处理器加电开始直到断电为止,程序计数器假设一个值的序列 \(a_0,a_1,\cdots,a_{n-1}\),其中每个 \(a_k\) 是某个相应指令 \(I_k\) 的地址。每次从 \(a_k\)\(a_{k+1}\) 的过渡称为控制转移。这样的控制转移序列叫做处理器的控制流。

当每个 \(I_k\)\(I_{k+1}\) 在内存中是相邻的,则称这种控制流是平滑的,否则会存在突变,突变通常由跳转、函数调用、返回等指令造成的。但有时系统状态也会发生变化,现代系统通过使控制流发生突变来对这些情况做出反应。一般而言,我们把这些突变称为异常控制流(ECF)。

异常

异常就是控制流中的突变,用来响应处理器状态中的某些变化。

如上图所示,当处理器状态中发生一个重要的变化时,处理器正在执行某个当前指令 \(I_{curr}\)。状态变化称为事件(event)。事件可以和当前执行的指令相关(虚拟内存缺页、算术溢出),也可以无关(系统定时器产生信号,I/O 请求完成)。

当处理器检测到事件发生时,它会通过一张异常表(exception table), 进行一个间接过程调用,到一个专门设计用来处理这类事件的操作系统子程序(异常处理程序 exception handler)。

异常处理

  • 系统每种类型的异常都分配了一个唯一的非负整数异常号(excpetion number)。其中一些号码是由处理器的设计者分配的(被零除、缺页、内存访问违例、算术溢出等),其它号码是由操作系统内核的设计者分配的(系统调用,外部 I/O 设备信号)。
  • 系统启动时,操作系统分配和初始化一张称为异常表的跳转表。表目 \(k\) 包含异常 \(k\) 的处理程序的地址。

  • 运行时,处理器检测到发生了一个事件,并且确定了相应的异常号 \(k\)。随后,处理器触发异常,通过异常表的表目 \(k\) 转到相应的处理程序。
    • 异常号是到异常表中的索引。
    • 异常表的起始地址放在异常表基址寄存器的特殊 CPU 寄存器中。

  • 异常类似于过程调用, 但有一些不同:
    • 根据异常的类型, 返回地址要么是当前指令(事件发生时正在执行的指令), 要么是下一条指令.
    • 处理器把一些额外的处理器状态压到栈里, 在处理程序返回时, 重新开始执行被中断的程序也需要这些状态.
    • 如果控制从用户程序转移到内核, 所有这些项目被压到内核栈中, 而不是用户栈.
    • 异常处理程序运行在内核模式下, 对所有的系统资源有完全的访问权限.
  • 一旦硬件触发了异常,剩下的工作就是由异常处理程序在软件中完成。

异常的类别

  • 中断
    • 异步发生,来自处理器外部 I/O 设备的信号的结果。
    • I/O 设备通过向处理器芯片上的一个引脚发送信号,并将异常号放到系统总线上来触发中断。这个异常号标识了引起终端的设备。
    • 当前指令执行完之后,处理器注意到终端引脚的电压变高了,就从系统总线上读取异常号,调用相应的中断处理程序。
    • 处理程序返回时,将控制返回给下一条指令。
  • 陷阱(Trap)
    • 陷阱是有意的异常,是执行一条指令的结果。
    • 最重要的用途是在用户程序和内核之间提供一个像过程一样的接口,称作系统调用
      • 用户程序经常需要向内核请求服务(读文件,创建进程,加载程序,终止进程等)
      • 用户想要请求服务 \(n\) 时,执行 syscall n 指令。
      • 导致一个到异常处理程序的 trap,这个处理程序解析参数并调用适当的内核程序。
  • 故障
    • 由错误情况引起,可能能够被故障处理程序修正。
    • 故障发生时,处理器将控制转移给故障处理程序。
      • 如果能修复错误情况,返回引起故障的指令,重新执行。
      • 否则返回到内核中的 abort 例程,终止该程序。
  • 终止
    • 不可恢复的致命错误造成的结果,通常是一些硬件错误(DRAM/SRAM 位损害发生的奇偶校验异常)
    • 终止处理程序将控制返回给 abort 例程。

进程


最后更新: 2024年9月27日 11:34:32
创建日期: 2024年9月27日 11:34:32