8.1 异常(Exceptions)

异常是一种部分由操作系统部分由硬件实现的异常控制流。 它本身是控制流的一次针对处理器(processor)某些状态改变后的改变。下图展示了异常发生时的流程,在图中我们可以看到处理器本身正在执行 I c u r r I_{curr} Icurr指令,这时突然处理器的某个状态发生了改变。这次状态的改变被称为事件(event)。事件可以和正在执行的指令直接相关,例如一次缺页异常(page fault),一次算术运算结果溢出。事件也可以和正在执行的指令完全无关,例如一次system timer goes off或者一次IO请求完成

在这里插入图片描述
在任何情况下,如果处理器检测到了事件的发生,那么它就会做出一次间接程序调用(也就是异常),这次程序调用通过一个被称为异常表(exception table)的跳转表(jump table)完成。调用的这个程序是一个操作系统子程序(exception handler),它被设计用来处理事件。

当异常处理程序(exception handler)完成处理后,取决于触发异常的事件,下面情况中的一个会发生:

  1. 处理程序会返回到执行之前正在执行的指令 I c u r r I_{curr} Icurr,这个指令就是处理器检测到异常时正在执行的指令
  2. 处理程序返回到 I n e x t I_{next} Inext,这个之林时处理器检测到异常时正在执行指令的下一条指令
  3. 处理程序直接放弃刚才被中断执行的程序

注:硬件异常和软件异常

C++和Java

在这里插入图片描述

一、Exception Handling

首先我们看下硬件和软件在异常处理中的分工。

每种可能的异常都被赋予了一个非负的异常码,一些异常码由处理器设计者定义的,而另一些异常码由操作系统内核设计者指定(存储在操作系统memory-resident部分中)。处理器设计者指定的异常可以是除0,缺页等;而操作系统内核指定的异常包括系统调用和外部IO设备发出的信号等。

当操作系统启动时,它会分配并初始化一个跳转表,这个跳转表称为异常表,所以表中存储的第k项就包含了异常k的处理程序地址。下图展示了跳转表的形式:
在这里插入图片描述

At run time (when the system is executing some program), the processor detects that an event has occurred and determines the corresponding exception number k. The processor then triggers the exception by making an indirect procedure call, through entry k of the exception table, to the corresponding handler. Figure 8.3 shows how the processor uses the exception table to form the address of the appropriate exception handler. The exception number is an index into the exception table, whose starting address is contained in a special CPU register called the exception table base register.

在这里插入图片描述

An exception is akin to a procedure call, but with some important differences:

  • As with a procedure call, the processor pushes a return address on the stack before branching to the handler. However, depending on the class of exception, the return address is either the current instruction (the instruction that was executing when the event occurred) or the next instruction (the instruction that would have executed after the current instruction had the event not occurred).
  • The processor also pushes some additional processor state onto the stack that will be necessary to restart the interrupted program when the handler returns. For example, an IA32 system pushes the EFLAGS register containing, among other things, the current condition codes, onto the stack.
  • If control is being transferred from a user program to the kernel, all of these items are pushed onto the kernel’s stack rather than onto the user’s stack.
  • Exception handlers run in kernel mode (Section 8.2.4), which means they have complete access to all system resources.

Once the hardware triggers the exception, the rest of the work is done in software by the exception handler. After the handler has processed the event, it optionally returns to the interrupted program by executing a special “return from interrupt” instruction, which pops the appropriate state back into the processor’s control and data registers, restores the state to user mode (Section 8.2.4) if the exception interrupted a user program, and then returns control to the interrupted program.

二、Classes of Exceptions

Exceptions can be divided into four classes: interrupts, traps, faults, and aborts. The table in Figure 8.4 summarizes the attributes of these classes.
在这里插入图片描述

2.1 Interrupts

Interrupts occur asynchronously as a result of signals from I/O devices that are external to the processor. Hardware interrupts are asynchronous in the sense that they are not caused by the execution of any particular instruction. Exception handlers for hardware interrupts are often called interrupt handlers.

Figure 8.5 summarizes the processing for an interrupt. I/O devices such as network adapters, disk controllers, and timer chips trigger interrupts by signaling a pin on the processor chip and placing onto the system bus the exception number that identifies the device that caused the interrupt.
在这里插入图片描述
After the current instruction finishes executing, the processor notices that the interrupt pin has gone high, reads the exception number from the system bus, and then calls the appropriate interrupt handler. When the handler returns, it returns control to the next instruction (i.e., the instruction that would have followed the current instruction in the control flow had the interrupt not occurred). The effect is that the program continues executing as though the interrupt had never happened.

t the program continues executing as though the interrupt had never happened. The remaining classes of exceptions (traps, faults, and aborts) occur synchronously as a result of executing the current instruction. We refer to this instruction as the faulting instruction.

2.2 Traps and System Calls

Traps are intentional exceptions that occur as a result of executing an instruction. Like interrupt handlers, trap handlers return control to the next instruction. The most important use of traps is to provide a procedure-like interface between user programs and the kernel known as a system call.

User programs often need to request services from the kernel such as reading a file (read), creating a new process (fork), loading a new program (execve), or terminating the current process (exit). To allow controlled access to such kernel services, processors provide a special “syscall n” instruction that user programs can execute when they want to request service n. Executing the syscall instruction causes a trap to an exception handler that decodes the argument and calls the appropriate kernel routine. Figure 8.6 summarizes the processing for a system call. From a programmer’s perspective, a system call is identical to a regular function call. However, their implementations are quite different. Regular functions run in user mode, which restricts the types of instructions they can execute, and they access the same stack as the calling function. A system call runs in kernel mode, which allows it to execute instructions, and accesses a stack defined in the kernel. Section 8.2.4 discusses user and kernel modes in more detail.

在这里插入图片描述
//待补充 743

三、Exceptions in Linux/IA32 Systems

To help make things more concrete, let’s look at some of the exceptions defined for IA32 systems. There are up to 256 different exception types [27]. Numbers in the range from 0 to 31 correspond to exceptions that are defined by the Intel architects, and thus are identical for any IA32 system. Numbers in the range from 32 to 255 correspond to interrupts and traps that are defined by the operating system. Figure 8.9 shows a few examples.
在这里插入图片描述

3.1 Linux/IA32 Faults and Aborts

3.2 Linux/IA32 System Calls

Linux provides hundreds of system calls that application programs use when they want to request services from the kernel, such as reading a file, writing a file, or creating a new process. Figure 8.10 shows some of the most popular Linux system calls. Each system call has a unique integer number that corresponds to an offset in a jump table in the kernel.

在这里插入图片描述
System calls are provided on IA32 systems via a trapping instruction called int n, where n can be the index of any of the 256 entries in the IA32 exception table. Historically, system calls are provided through exception 128 (0x80).

C programs can invoke any system call directly by using the syscall function. However, this is rarely necessary in practice. The standard C library provides a set of convenient wrapper functions for most system calls. The wrapper functions package up the arguments, trap to the kernel with the appropriate system call number, and then pass the return status of the system call back to the calling program. Throughout this text, we will refer to system calls and their associated wrapper functions interchangeably as system-level functions.

It is quite interesting to study how programs can use the int instruction to invoke Linux system calls directly. All parameters to Linux system calls are passed through general purpose registers rather than the stack. By convention, register %eax contains the syscall number, and registers %ebx, %ecx, %edx, %esi, %edi, and %ebp contain up to six arbitrary arguments. The stack pointer %esp cannot be used because it is overwritten by the kernel when it enters kernel mode.

For example, consider the following version of the familiar hello program, written using the write system-level function:

int main(){
	write(1,"hello world\n",13);
	exit(0);
}

The first argument to write sends the output to stdout. The second argument is the sequence of bytes to write, and the third argument gives the number of bytes to write.

Figure 8.11 shows an assembly language version of hello that uses the int instruction to invoke the write and exit system calls directly. Lines 9–13 invoke the write function. First, line 9 stores the number for the write system call in %eax, and lines 10–12 set up the argument list. Then line 13 uses the int instruction to invoke the system call. Similarly, lines 14–16 invoke the exit system call.
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值