文章目录
异常控制流
-
什么是控制流?
从给处理器加电开始,直到断电为止,程序计数器中值的序列 a0, a1, ..., an-1, 其中,每个ak是某个相应的指令Ik的地址。 每次从ak到ak+1的过渡称为控制转移。这样的控制转移序列叫做处理器的控制流。
-
什么是异常控制流?Exceptional Control Flow
“平滑的”序列是指Ik和Ik+1正在内存中都是相邻的,而平滑流的突变就是指异常控制流(但是这里看起来并不包括过程调用,goto,条件分支和循环这样的控制流,而是指以下3个层次上列举的异常控制流)
-
异常控制流可分为哪几个层次,每个层次上有哪些异常控制
- 硬件层:异常是由处理器中的事件触发的控制流中的突变。控制会突然转移到异常处理程序(内核)。异常可分为4类:
- 中断:由外部I/O设备的在管脚触发信号(异步)。
- 故障:可能恢复,可能终止。
- 终止:一定终止
- 陷阱:系统调用
- 操作系统层:利用ECF提供“进程“的基本概念,而进程的切换就是发生在此层面的异常控制流。内核通过上下文切换完成。
- 应用层:信号和非本地跳转。
- 信号:信号的接收者会将控制流突然转移到它的一个信号处理程序,允许进程和内核中断其他进程。
- 非本地跳转:规避正常的调用/返回栈规则,跳转到其他函数的位置来对错误做出反应。
- 硬件层:异常是由处理器中的事件触发的控制流中的突变。控制会突然转移到异常处理程序(内核)。异常可分为4类:
一、硬件层次ECF—异常
1.1 异常
-
异常的概念
异常(Exception)就是控制流的突变,用来响应处理器状态中的某些变化。
-
异常和当前指令相关也可能无关
处理器的状态变化被称为事件(event),事件可能和当前指令的执行直接相关,如虚拟内存缺页、算数溢出;也可能和当前指令无关,如一个系统定时器产生信号 或者 I/O请求完成。
-
异常表
在任何情况下,当处理器检测到有异常发生时,他就会通过“异常表(exception table)”进行一个间接过程调用(异常),(这里称为间接应是因为通过异常表获取指令地址),到一个专门设计用来处理这类事件的操作系统自程序(异常处理程序(exception handler))。当异常处理程序完成处理后,根据引起异常的类型,会发生以下3种情况之一:
- 处理程序将控制返回给当前指令Icurr
- 处理程序将控制返回给Inext
- 处理程序终止被中断的程序
1.2 异常处理
-
硬件和软件的分工
-
异常号
系统中可能的每种类型的异常都分配了一个唯一的非负整数的异常号(exception number)。其中的一些号码是由处理器的设计者分配的,其他号码则是由操作系统内核的设计者分配的。
- 处理器异常号:零除,缺页,内存访问违例,断点,算数运算溢出
- 操作系统异常号:系统调用,来自外部的I/O设备的信号
-
-
异常处理过程
-
系统启动,操作系统初始化“异常表”,使得表目k包含异常k的处理程序的地址
-
运行时,处理器检测到发生了一个事件,并确定异常号k。异常表的起始地址放在异常处理表基址寄存器,处理器执行间接过程调用。异常类似于过程调用,但是有一些重要的不同之处:
-
返回地址不同
过程调用时,跳转到过程程序之前,处理器会将返回地址压入栈中;然而,根据异常类型,返回地址要么是当前指令,要么是下一条指令。
-
额外的处理器状态压入栈
处理异常程序调用前,处理器会把一些额外的处理器状态压入栈中;因为,在异常处理程序完成后,重新执行被中断的程序会需要这些状态。
-
控制从用户程序转移到内核,则以上项目会被压入内核栈
而不是用户栈
-
异常处理程序运行在内核模式下
-
-
处理完事件后,执行一条特殊的“从中断返回”指令,此指令:
- 将适当的状态弹回处理器的控制和数据寄存器中
- 恢复到被中断的程序的模式——内核模式or用户模式
- 控制返回给被中断的程序
-
1.3 异常类别
异常分为四类:中断(interrupt),陷阱(trap),故障(fault),终止(abort)
类别 | 原因 | 异步/同步 | 返回行为 |
---|---|---|---|
中断 | 来自I/O设备信号 | 异步 | 总是返回到下一条指令 |
陷阱 | 有意的异常 | 同步 | 总是返回到下一条指令 |
故障 | 潜在可恢复的错误 | 同步 | 可能返回到当前指令 |
终止 | 不可恢复的错误 | 同步 | 不会返回 |
注意:
- 异步异常是指由外部I/O设备中的事件产生的,同步异常则指当前指令执行的产物
1.3.1 中断
- 中断来源:中断是异步发生的,是来自外部的I/O设备的信号的结果。异常处理程序常常被称为中断处理程序(interrupt handler)。
- 中断产生:I/O设备,例如网络适配器、磁盘控制器和定时器芯片,通过向处理器芯片上的一个引脚发送信号,并将异常号放在系统总线上,来触发中断。
- 异步异常:硬件层四类异常中,只有中断是异步的异常,剩下的陷阱,故障和终止都是由当前指令触发的同步异常。
1.3.2 陷阱和系统调用
-
陷阱来源:有意的异常,并和中断异常处理完成后将控制返回到下一条指令
-
系统调用:系统调用是陷阱最重要的用途,指在用户程序和内核之间提供一个像过程一样的接口。
-
syscall:用户程序经常需要向内核请求服务,比如读一个文件(read),创建一个新的进程(fork),加载一个新的程序(execve),或者终止当前进程(exit)。处理器提供了一条特殊的“syscall n”指令,当用户想要请求服务n时,可以执行这条指令。
syscall指令会导致一个到异常处理程序的陷阱,这个程序解析参数,并调用适当的内核程序。
1.3.3 故障
- 故障来源:故障是由错误情况引起,它可能能够被故障处理程序修正。
- 返回行为不确定:如果处理程序能够修正这个错误情况,它就将控制返回到引起故障的指令,从而重新执行它;否则,处理程序返回到内核中的abort例程,abort例程会终止引起故障的应用程序。
1.3.4 终止
- 终止来源:终止是不可恢复的致命错误造成的结果,通常是一些硬件错误,比如DRAM或者SRAM位被损坏时发生的奇偶错误。
- 终止程序:处理终止程序从不将控制返回给应用程序,而将控制返回给一个abort例程,该例程终止这个应用程序。
1.4 Linux/x86-64 系统中的异常
-
异常类型:256种。0-31号码对应Intel架构师定义的异常,因此对任何x86-64系统都是一样的。32-255的号码对应的是操作系统定义的终端和陷阱。示例:
异常号 描述 异常类别 0 除法错误 故障 13 一般保护性故障 故障 14 缺页 故障 18 机器检查 终止 32~255 操作系统定义的异常 中断或陷阱
1.4.1 Linux/x86-64 故障和终止
- 除法错误:当试图除以零时,或者当一个除法指令的结果对于目标操作系统来说太大(?),就会发生除法错误(异常0)。Unix不会试图从除法错误中恢复,而是终止程序。Linux shell通常会把这种一般保护性故障报告为“浮点异常(Floating exception)”。
- 一般保护性故障