作用
asm.s汇编程序中包括大部分CPU探测到的异常故障处理的底层代码,也包括数学系处理器的异常处理
该程序的主要处理方式是在中断处理程序中调用traps.c中的C函数程序,显示出错位置和出错号,然后退出中断
说明
不带出错号的中断过程堆栈变化
带出错号的中断过程堆栈变化
补充
若对代码有疑惑,可结合上面展示的两幅图对代码进行解读
代码解析
# 全局符号定义,此处定义的是外部可调用的汇编函数
.globl divide_error,debug,nmi,int3,overflow,bounds,invalid_op
.globl double_fault,coprocessor_segment_overrun
.globl invalid_TSS,segment_not_present,stack_segment
.globl general_protection,coprocessor_error,irq13,reserved
# 除数为0引起的中断如下
divide_error:
# 压入函数入口点
pushl $do_divide_error
# 无出错号的通用处理过程
no_error_code:
# 交换ax与堆栈顶部的值
# 等价于将ax压入栈中,同时弹出顶部的值给ax
# 上述操作需要一个中间变量,所以使用xchgl直接交换
xchgl %eax,(%esp)
pushl %ebx
pushl %ecx
pushl %edx
pushl %edi
pushl %esi
pushl %ebp
push %ds
push %es
push %fs
# 寄存器保存完毕,调用ax所指向的函数
pushl $0 # "error code"
lea 44(%esp),%edx
pushl %edx
movl $0x10,%edx
mov %dx,%ds
mov %dx,%es
mov %dx,%fs
call *%eax
# 恢复堆栈指针
addl $8,%esp
# 恢复压入的寄存器值
pop %fs
pop %es
pop %ds
popl %ebp
popl %esi
popl %edi
popl %edx
popl %ecx
popl %ebx
popl %eax
# 中断返回
iret
# 调试中断入口
debug:
pushl $do_int3 # _do_debug
jmp no_error_code
# 非屏蔽中断调用入口点
nmi:
pushl $do_nmi
jmp no_error_code
# 断点指令引起中断的入口点
int3:
pushl $do_int3
jmp no_error_code
# 溢出出错处理中断的入口点
overflow:
pushl $do_overflow
jmp no_error_code
# 边界检查出错中断的入口点
bounds:
pushl $do_bounds
jmp no_error_code
# 无效操作指令出错中断的入口点
invalid_op:
pushl $do_invalid_op
jmp no_error_code
# 协处理器段超出出错中断的入口点
coprocessor_segment_overrun:
pushl $do_coprocessor_segment_overrun
jmp no_error_code
# Intel保留中断的入口点
reserved:
pushl $do_reserved
jmp no_error_code
# Linux设置的数学协处理器硬件中断
irq13:
pushl %eax
xorb %al,%al
outb %al,$0xF0
movb $0x20,%al
outb %al,$0x20
jmp 1f
1: jmp 1f
1: outb %al,$0xA0
popl %eax
jmp coprocessor_error
# 两处错出故障
double_fault:
# 压入函数入口地址
pushl $do_double_fault
# 有出错号的通用处理过程
error_code:
# 交换eax与esp+4
xchgl %eax,4(%esp) # error code <-> %eax
# 交换ebx与esp
xchgl %ebx,(%esp) # &function <-> %ebx
# 保存其余寄存器
pushl %ecx
pushl %edx
pushl %edi
pushl %esi
pushl %ebp
push %ds
push %es
push %fs
# 寄存器保存完毕,调用bx指向的函数
pushl %eax # error code
lea 44(%esp),%eax # offset
pushl %eax
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
call *%ebx
# 恢复堆栈指针
addl $8,%esp
# 恢复所有的寄存器
pop %fs
pop %es
pop %ds
popl %ebp
popl %esi
popl %edi
popl %edx
popl %ecx
popl %ebx
popl %eax
# 中断返回
iret
# 无效任务状态段
invalid_TSS:
pushl $do_invalid_TSS
jmp error_code
# 段不存在
segment_not_present:
pushl $do_segment_not_present
jmp error_code
# 堆栈段出错
stack_segment:
pushl $do_stack_segment
jmp error_code
# 一般性保护出错
general_protection:
pushl $do_general_protection
jmp error_code