20145319 《信息安全系统设计基础》第十一周学习总结
20145319 《信息安全系统设计基础》第十一周学习总结
一 教材内容总结
异常
-
异常:控制流中的突变,用来响应处理器状态中的某些变化
-
异常处理程序完成后的三种可能结果:
-
将控制返回给当前指令
-
将控制返回给如果没有异常发生将会执行的下一条指令
-
终止被中断的程序
-
-
异常处理:
- 异常号:到异常表的索引,系统中可能的每种类型的异常都分配了一个唯一的非负整数
- 异常表:一张跳转表,其中条目k包含异常k的处理程序代码的地址
- 异常表基址寄存器:用来存放异常表的起始地址
异常的类型:
- 中断:
- 原因:来自于I/O设备的信号
- 是异步发生的
- 返回行为:总是回到下一条指令
- 陷阱:
- 原因:有意的异常原因
- 是同步发生的
- 返回行为:返回到下一条指令
- 故障
- 原因:潜在可恢复的错误
- 是同步发生
- 返回行为:可能返回到当前指令
- 终止
- 原因:不可恢复的错误(通常是硬件错误)
- 是同步发生的
- 返回行为:不会返回
- 故障指令:
- 陷阱,故障,终止等同步发生的异常类型,是执行当前指令的结果,我们将这类型的指令叫做故障指令
linux/IA32系统中的异常举例
- 异常的总数达到256种,32~255的异常号对应的是操作系统定义的中断和陷阱
- 浮点异常:
- 除法错误:当应用试图除以0的时候,或者当一个除法指令的结果对于目标操作数来说太大了
- Unix会选择中止程序,不会试图从除法错误中恢复
- 段故障:
- 一般故障保护:异常号13.通常是因为一个程序引用了一个未定义的虚拟存储区域,或者因为程序试图写一个只读的文本段
- linux不会试图恢复该类故障
- 缺页:
- 处理程序将磁盘上虚拟存储器相应的页面映射到物理存储器的一个页面,然后重新开始执行这条故障的指令
- 补充:
- 所有到linux的系统调用的参数都是通过通用寄存器而非栈来传递
进程
- 进程:一个执行中的程序的实例
- 上下文:
- 系统中的每个程序都是运行在某个进程的上下文中的
- 程序正确运行所需的状态所组成,包括存放在存储器中的代码和数据、它的栈、通用目的寄存器的内容、程序计数器、环境变量,打开文件描述符的集合
- 关键抽象:
- 独立的逻辑控制流,好像程序独占使用处理器
- 私有地址空间,好像程序独占使用存储器系统
- 逻辑控制流:
- 一系列唯一地对应于包含在程序的可执行目标文件中的指令,或者是包含在运行时动态链接到程序的共享对象中的指令的PC值的序列
- 并发流:
- 一个逻辑流的执行在时间上与另一个流重叠
- 并发:多个流并发的执行
- 多任务:一个进程和其他进程轮流进行的概念
- 时间片:一个进程执行它的控制流的一部分的每一时间段
- 私有地址空间:
- 一个进程为程序提供它自己的私有地址空间,和地址空间中某个地址相关联的那个存储器字节是不能被其他进程读或者写的
- 用户模式和内核模式:
- 内核模式:该模式中的进程可以执行指令集中的任何指令,并且可以访问系统中的任何存储器位置
- 用户模式:用户模式进程必须通过系统调用接口间接访问内核代码和数据
/proc文件系统
:允许用户模式进程访问内核数据结构的内容/sys文件系统
:输出关于系统总线和设备的额外的底层信息
进程控制
- 获取进程ID:
- 每个进程都有一个唯一的进程ID(唯一的正数)
getpid函数
获取进程的PIDgetppid
获取创建调用进程的进程(即它的父进程)的PID
- 创建和终止进程:
fork函数
:在父进程中,返回子进程的PID,在子进程中返回0,发生错误时返回-1- 调用一次,返回两次
- 父进程和子进程并发执行
- 相同的但是独立的地址空间
- 共享文件
- 回收子进程:
- 当一个进程由于某种原因终止的时候,内核并不是把它从系统中清除,而是保持在已经终止的状态中,直到被它的父进程回收
- 僵死进程:已经终止但是尚未被回收的进程
- 特例:如果父进程没有回收它的子进程就终止了,那么内核就会安排init函数来回收它们,init函数的返回值是1
- 让进程休眠:
- sleep函数将一个进程挂起一段指定的时间
- 如果请求的时间量已经到了,sleep返回0,否则返回还剩下的要休眠的秒数
- pause函数让调用函数休眠,直到该进程收到一个信号
利用fork和execve函数运行程序
- 上述两个函数被大量使用在unix外壳中,外壳是一个交互型的应用级程序,它代表用户运行其他程序。外壳执行一系列读/求值步骤,然后终止。读是读取来自用户的一个命令行,求值是解析命令行然后运行程序
非本地跳转
- 定义:C语言提供了一种用户级异常控制流形式,称为非本地跳转;它将一个函数转移到一个当前正在执行的函数,而省略了调用-返回序列这一步
setjmp函数
:- 在env缓冲区中保存当前调用环境(包括PC,栈指针,通用寄存器),以供后面的longjmp使用,并返回0
longjmp函数
:- 从env缓冲区中回复调用环境,然后触发一个从最近一次初始化env开始的setjmp函数调用的返回
- ongjmp函数从env缓冲区中恢复调用环境,然后触发一个从最近一次初始化env的setjmp调用的返回
- 非本地跳转的一个重要应用就是允许从一个深层嵌套的函数调用中立即返回,通常由检测到某个错误情况引起
二 课后代码分析
-
非本地跳转的示例分析
#include "csapp.h" jmp_buf buf; int error1 = 0; int error2 = 1; void foo(void), bar(void); int main() { int rc; switch (setjmp(buf)); if (rc == 0) foo(); else if (rc == 1) printf("detected an error1 condition in foo\n"); else if (rc == 2) printf("detected an error2 condition in foo\n"); else printf("unknown error condition in foo\n"); exit(0); } void foo(void){ if (error1) longjmp(buf, 1); bar(); } void bar(void){ if (error2) longjmp(buf, 2); }
-
main函数先调用setjmp保存以前的调用环境,然后调用函数foo;foo调用bar;如果这两个函数中一个遇到错误,就立即通过longjmp调用从setjmp返回;setjmp非零返回值指明了错误类型
-
允许从一个深层嵌套的函数调用之中立即返回,而不是费力地解开栈
三 代码托管
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 0/0 | 1/1 | 20/20 | 学习常用linux命令 |
第二周 | 100/100 | 1/2 | 20/40 | 学习vim,gdb等用法 |
第三周 | 100/200 | 1/3 | 15/55 | |
第四周 | 0/300 | 0/3 | 10/65 | |
第五周 | 100/400 | 1/4 | 15/80 | 重温了汇编相关知识 |
第六周 | 0/400 | 1/5 | 15/95 | 学习了Y86 |
第七周 | 100/500 | 1/6 | 15/110 | 学习了存储器相关知识 |
第八周 | 0/500 | 2/8 | 20/130 | 复习 |
第九周 | 150/650 | 2/10 | 15/145 | 学习了I/O相关知识 |
第十周 | 300/950 | 2/12 | 20/165 | 学习了linux命令代码 |
第十一周 | 200/1150 | 3/15 | 20/185 | 学习了异常流相关知识 |
posted on 2016-11-27 22:07 20145319钟轲 阅读(145) 评论(0) 编辑 收藏 举报