深入理解计算机基础第八章

说明

读书笔记

异常的类型

异常表

系统中每种可能的异常类型,都分配了一个唯一的非负整数的异常号
其中一些由处理器的设计者分配(被0除、缺页、内存访问违例、断点、算术运算溢出),其他号码由操作系统内核的设计者分配(系统调用、来自外部设备的io信号)

流程

1.处理器检测到异常,并且确定对应的异常号
2.通过异常表基址寄存器 + 异常号 * 4得到异常处理程序的入口地址
3.进入异常调用

异常调用步骤

1.处理器根据异常的类型,将返回地址(当前指令或者下一条指令)压栈
2.把上下文压栈(EFLAGS寄存器、其他寄存器),方便返回的时候继续执行
3.如果控制从用户程序转移到内核,所有项目都被压入内核栈,而不是用户栈
4.异常处理程序运行在内核模式下,这意味这他们对所有的系统资源都有完全的访问权限
一但硬件触发了异常,剩下的工作在软件中完成,完成之后,通过一条特殊的"从中断返回指令",可选的返回到程序

1.中断(唯一的异步中断)

来自io设备的信号,总是返回到下一条指令

2.陷阱和系统调用

有意的异常,总是返回到下一条指令
通过syscall指令可以陷入内核,调用linux系统调用(参数通过寄存器而不是栈传递)

3.故障

潜在可恢复的错误,可能返回到当前指令

4.终止

不可恢复的错误,不会返回

上下文切换

包含通用目的寄存器,浮点寄存器,程序计数器,用户栈,状态寄存器,内核栈
各种内核数据结构:描述地址空间的页表,进程表,文件表

Linux信号

非本地跳转(c++异常的底层实现)

setjmp

int setjmp(jmp_buf env)
在env缓冲区中保存当前调用环境,以供后面的longjmp使用,并返回0
调用环境包括:程序计数器、栈指针、通用目的寄存器
出于某种高深的原因,返回值不能赋值给变量,不过可以安全的用在switch、if中

longjmp

void longjmp(jmp_buf env,int retval)
返回setjmp设置的点,并且返回retval,也就是使得setjmp二次返回
retval不能为0,为0的时候自动改为1


代码很清楚了,setjmp返回两次,第一次返回0,第二次返回longjmp设置的retval


/*
---- From XDU's mzb
*/
#include <bits/stdc++.h>
#include <setjmp.h>

using namespace std;
using ll = long long int;

jmp_buf buf;
int error1 = 1;
int error2 = 0;
void foo(void),bar(void);

int main()
  {
  	switch (setjmp(buf))
  	  {
  	  	case 0:
  	  		cout << "case 0" << "\n";
  	  		foo();
  	  		break;
  	  	case 1:
  	  		cout << "error 1 foo" << "\n";
  	  		break;
  	  	case 2:
  	  		cout << "error 2 foo" <<"\n";
  	  		break;
  	  	default :
  	  		cout << "Unknow error condition in foo" << "\n";
		}
	return 0;
  }
void foo(void)
  {
  	if (error1)
  	  longjmp(buf,1);
  	bar();
  }
void bar(void)
  {
  	if (error2)
  	  longjmp(buf,2);
  }
posted @ 2021-10-08 16:13  XDU18清欢  阅读(45)  评论(0)    收藏  举报