CSAPP第八章-异常控制流(一)

来源:互联网 发布:linux 内核是什么 编辑:程序博客网 时间:2024/05/16 12:10

前言

这一章真是解惑众多啊,关于中断、信号、进程。非常非常值得一看,CSAPP真是神书。

异常

定义和场景

  1. 现代系统通过使控制流发生突变来对这些情况做出反应。异常发生在计算机系统的各个层次,比如:

    • 硬件层,硬件检测到的事件会出发控制突然转移到异常处理程序。

    • 操作系统层,内核通过上下文转换将控制从一个用户进程转移到另一个用户进程。

    • 应用层,一个进程可以发送信号到另一个进程,信号接收者会将控制突然转移到它的一个信号处理程序。

  2. 应用程序通过陷阱(trap)或者系统调用(system call)的ECF形式,向操作系统请求服务。

异常的执行

异常的剖析

异常处理程序在执行结束后,会发生以下三种情况之一:
1. 返回应用程序当前指令Icurr
2. 返回应用程序的下一条指令Inext
3. 异常处理程序终止被中断的应用程序

异常的处理

基本知识

  1. 系统中的美中类型异常都分配了一个唯一的非负整数,作为异常号。系统启动时会初始化一张异常表,异常表的起始地址存在一个特殊的CPU寄存器里,异常表基址寄存器。
    异常表
  2. 异常处理程序运行在内核模式,这意味着它们对所有的系统资源都有完全的访问权限。
  3. 异常分类:
    中断是异步的,不由任何一条指令造成。其他三种异常是同步的,是执行当前指令的结果。
    异常的类别

中断

  1. 来自处理器外部I/O设备的信号的结果。硬件中断不是由任何一条专门的指令造成的。I/O设备通过向处理器芯片上的一个引脚发信号,并将异常号放到系统总线上,以触发中断,这个异常号标识了引起中断的设备。(也有软件中断?比如信号?)

  2. 中断处理的重点:

    • 检测到引脚电压变高,当前的指令会继续执行结束
    • 返回下一条指令
    • 中断处理

陷阱和系统调用

  1. 陷阱是有意的异常,是执行一条指令的结果。最重要的用途是在用户程序和内核之间提供一个接口,称为系统调用

  2. 从程序员角度,系统调用和普通函数调用是一样的,然而它们的实现不同。普通函数运行在用户模式,用户模式限制了函数可以执行的指令类型,而且它们只能访问与调用函数相同的栈。系统调用运行在内核模式,内核模式允许系统调用执行指令,并访问定义在内核中的栈。

  3. 陷阱处理的重点:

    • 程序员主动调用,比如syscall指令。
    • 返回下一条指令,上一条指令就是syscall。
    • 陷阱处理

故障

  1. 故障时由于指令执行发生了错误。这个错误可能被修复,若处理程序修复了,则返回重新执行这条指令,否则返回到内核中的abort例程(当做内核对外提供的一个服务即可),abort例程会终止引起该故障的应用程序。

  2. 一个经典的故障是缺页异常,当指令引用一个虚拟地址,而该虚拟地址相对应的物理页面不在存储器(包含缓存,主存等)中,因此必须从磁盘中取时,就会发生故障。当缺页处理程序加载好后,就将控制返回给应用程序。此时原指令再次执行,由于相应页面已经被加载到存储器中,因此此次执行不会引起故障。

  3. 故障处理的重点

    • 指令执行的结果。
    • 故障恢复成功。返回当前指令,重新执行一次。(会不会出现死循环?)
    • 故障恢复失败。通过abort例程,终止程序。
    • 故障处理

终止

  1. 终止时由于不可恢复的致命错误造成的结果。通常是一些硬件错误。终止处理程序直接将控制返回给abort例程,abort例程去终止这个应用程序。

  2. 终止处理的重点

    • 执行指令时,发生了不可恢复的致命错误。
    • 应用程序会直接终止。
    • z

Linux/IA32中的异常

异常

  1. 有256种异常类型。0~31号为Intel架构师定义,32~255由操作系统定义的中断或陷阱。举例:
    异常示例

    特别出名的,比如“段错误”对应的是13,一般保护故障,通常是由于程序引用了一个未定义的虚拟存储器区域。系统调用是0X80.

Linux/IA32系统调用

  1. 系统调用是异常的一种,属于陷阱,有意的异常。

  2. IA32系统上,系统调用通过一条称为int n的陷阱指令来提供。Linux提供上百种系统调用。每个系统调用都有一个唯一的整数号,对应于一个到内核中跳转表的偏移量。看图:
    系统调用示例
    C语言用syscall函数可以直接调用任何系统调用。然而实际中没必要这么做,标准C库做了很多封装的工作,使用更方便。所有到Linux系统调用的参数都是通过通用寄存器,而不是栈来传递的。

0 0
原创粉丝点击