深入理解计算机基础第八章
说明
读书笔记
异常的类型
异常表
系统中每种可能的异常类型,都分配了一个唯一的非负整数的异常号
其中一些由处理器的设计者分配(被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);
}
本文来自博客园,作者:XDU18清欢,转载请注明原文链接:https://www.cnblogs.com/XDU-mzb/p/15380349.html