20135210程涵——信息安全系统设计基础第十一周学习总结
2015-11-22 23:48
218 查看
第8章异常控制流
8.1异常
异常是ECF的一种,一部分由硬件实现,一部分由操作系统实现。就是位于硬件和操作系统之间的ECF。异常可以分为四类:中断(interrupt),陷阱(trap),故障(fault),终止(abort)。
中断——来自处理器外部的I/O设备的信号的结果。 中断处理程序——异步异常——由处理器外部I/O设备中的事件产生的。同步异常是执行一条指令的直接产物。 中断通过向处理器芯片上的一个引脚发信号(高低电平),并将异常号放在系统总线上,以触发中断,很清楚。 其中断处理程序完成后直接返回给下一条指令。 陷阱——同步异常——完成处理后也返回到下一条指令。 陷阱最重要的用途是在用户程序和内核之间提供一个像过程一样的接口,叫做系统调用。 从程序员的角度来看,系统调用和普通的函数调用是一样的。 但是它们的实现是非常不同的。普通函数在用户模式,系统调用在内核模式。 syscalln指令,执行这条指令,会导致一个到异常处理程序的陷阱,就是跳到一个异常处理程序 这个程序会对参数解码,并调用适当的内核程序,比如read,fork,execve,exit。 故障——同步异常——对应的处理程序叫故障处理程序。 如果处理程序可以修正这个错误(缺页异常),那么就返回到引起故障的指令,如果不能修正,就返回到内核的abort例程。 终止——同步异常——对应的处理程序叫做终止处理程序,终止处理程序从不将控制返回,它会将控制返回给内核的abort例程。
Linux/A32系统调用
每个系统调用都对应着唯一的整数号,对应于一个到内核中跳转表的偏移量。IA32系统调用是通过一条称为intn的陷阱指令提供的。
C程序通过syscall函数可以直接调用任何系统调用。
所有Linux系统调用都是通过通用寄存器而不是栈传递的,%eax包含系统调用号,%ebx、%ecx、%edx、esi%、%edi和%ebp包含最多6个参数。栈指针%esp不能使用,因为当进入内核模式时,内核会覆盖它。
8.2进程
上下文是由程序正确运行所需的状态组成的。这个状态包括存放在存储器中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件描述符的集合。
上下文是一份集合,它的每个组成部分都真实存在,但这些组成部分不是放在一起的,这个集合的概念是概念上,将这些组成部分合在一起,我们称这个集合是上下文。
当我们说在上下文中执行一个程序,其实是说,这些组成部分都分配安排好了,放在那里了,然后开始执行这些组成部分中的存储器中的代码。
进程提供给应用程序的关键抽象:
一个独立的逻辑控制流,它提供了一个假象,好像我们的程序独占的使用处理器。 一个私有的地址空间,它提供了一个假象,好像我们的程序独占的使用存储器系统。 上下文是集合,进程其实是这个集合下实际一条一条执行代码的过程。进程包含上下文以及执行的过程。
PC值的序列称为逻辑控制流。
处理的实际的PC序列称为物理控制流,物理控制流总包含多个逻辑流。
进程是程序和内核之间的屏障,进程是应用程序的抽象,它将内核和硬件踢掉,给应用程序假象。内核和硬件提供了进程这种功能,应用程序都是一个一个的进程,应用程序不知道内核和硬件,只知道进程。
应用程序没有时间和空间的概念,它只知道进程,但进程自己知道,但进程不让应用程序知道。
异常处理程序、进程、信号处理程序、线程、java进程都是逻辑流的例子。
多个流并发的执行的一般现象称为并发。
一个进程和其他进程轮流运行的概念称为多任务。
一个进程执行它的控制流的一部分的每一个时间段叫做时间片。因此多任务也叫时间分片。
两个流并发的运行在不同的处理器核或者计算机上,我们称为并行流。
并行流一定是并发流,并发流是“老大”。
一个进程为每个程序提供它自己的私有地址空间,这个空间中的某个地址相关联的那个存储器字节,一般而言,是不能被其他进程读或者写的,从这个意义上说,这个地址空间是私有的。
x86linux地址空间顶部是保留给内核的。这部分也包含了
代码 数据 栈
但是,这部分是内核在代表进程执行指令时才会使用的,比如系统调用时,使用的就是这部分空间。
在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占的进程。这种决定就叫做调度,是由内核中称为调度器的代码处理的。
上下文切换:
保存当前进程的上下文。 恢复某个先前被抢占的进程被保存的上下文。 将控制传递给这个新恢复的进程。
8.3系统调用错误
当UNIX系统级函数遇到错误时,它们典型地会返回-1,并设置全局整数变量errno来表示什么出错了。
8.4进程控制
Unix提供了大量从c程序中操作进程的系统调用。从程序员的角度,我们可以认为进程总处于下面三种状态之一:
运行——在cpu上运行,或者,等待运行且最终会运行(会被内核调度) 停止——进程被挂起(也就是被其他的进程抢占了),且不会被调度,但可以被信号唤醒 终止——进程被永远的停止了,受到终止信号,或者从主程序返回,或者调用exit函数。
fork函数:
调用一次,返回两次。父进程和子进程是独立的进程,并发执行的。一般而言,作为程序员,我们决不能对不同的进程中指令的交替执行做任何假设。相同的但是独立的地址空间。共享文件。
当一个进程由于某种原因终止时,内核并不是立即把它从系统中清除。相反,进程被保持在一种已终止的状态中。直到被它的父进程回收。
当父进程回收已终止的子进程时,内核将子进程的退出状态传递给父进程。然后抛弃已终止的进程。
一个终止了但是还未被回收的进程称为僵死进程。
如果父进程没有回收它的僵死子进程就终止了,那么内核就会安排另外一个进程来回收它们,这个进程是init。其pid为1。其在系统初始化时由内核创建。
一个进程可以通过调用waitpid函数来等待它的子进程终止或者停止。
这个函数有三个参数:
pid status options。
options=0时,调用这个函数的进程挂起,也就是这个进程处于函数中什么也不做,等待着,等待什么呢,等待其子进程终止,如果终止了一个,那么函数就返回了,返回的,就是终止的子进程的pid,并且将这个子进程从系统中除去。
等待的子进程有哪些呢?这点由pid决定,pid=-1,那么就是所有的子进程,pid大于0,那么就是一个子进程,当前pid表示的那个子进程。
options=WNOHANG时,如果没有终止的子进程,那么函数立即返回,返回0。options=WUNTRACED时,和options=0类似,但这里还检测停止的子进程。options=0只检测终止的子进程。且,本options不会将子进程从系统中除去。options=WNOHANG|WNUNTRACED时,立即返回,返回值要么是停止或者终止的pid,要么是0。
如果调用进程没有子进程,那么waitpid返回-1,并设置errno为ECHLILD;如果waitpid函数被一个信号中断,那么它返回-1,并设置errno为EINTR。
status是一个指向int类型的指针,waitpid返回后,其会有相应的值,但这个值的编码貌似比较复杂,c标准库提供了一些宏来处理它。WIFEXITED(status)等。
wait函数等价于waitpid(-1,&status,0)。
execve函数在当前进程的上下文中加载并运行一个新程序。fork一次调用两次返回,execve调用一次,从不返回。
8.5信号
Unix信号是一种更高层次的软件形式的异常。linux支持30种不同类型的异常。
每种信号类型都对应于某种系统事件。底层的硬件异常是由内核异常处理程序处理的,正常情况下,对用户进程而言是不可见的。信号提供了一种机制,通知用户进程发生了这些异常。
发送信号——内核通过更新目的进程上下文中的某个状态,告诉目的进程,有一个信号来了。 接受信号——当目的进程被内核强迫以某种方式对信号的发送做出反应时,目的进程就接收了信号。 进程可以忽略、终止、捕获。
发送信号的方式
/bin/kill 键盘发送信号 kill函数 alarm函数。