set_trap_gate(0,÷_error);
set_intr_gate(1,&debug);
set_intr_gate(2,&nmi);
set_system_intr_gate(3, &int3); /* int3-5 can be called from all */
set_system_gate(4,&overflow);
set_system_gate(5,&bounds);
set_trap_gate(6,&invalid_op);
set_trap_gate(7,&device_not_available);
set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS);
set_trap_gate(9,&coprocessor_segment_overrun);
set_trap_gate(10,&invalid_TSS);
set_trap_gate(11,&segment_not_present);
set_trap_gate(12,&stack_segment);
set_trap_gate(13,&general_protection);
set_intr_gate(14,&page_fault);
set_trap_gate(15,&spurious_interrupt_bug);
set_trap_gate(16,&coprocessor_error);
set_trap_gate(17,&alignment_check);
set_trap_gate(18,&machine_check);
set_trap_gate(19,&simd_coprocessor_error);
divide_error等20个中断处理函数的定义一直都搜索不到,让我郁闷了好几天,今天把所有的汇编文件全部加载进工程才发现原来是在arch目录下具体处理器中的entry.s文件中定义的
拿个具体的中断处理函数说下:
栈是由高地址到低地址负增长的
ENTRY(divide_error)
pushl $0 # no error code //错误码 在栈低 4byte
pushl $do_divide_error //异常处理函数地址 4byte
ALIGN
error_code:
pushl %ds //数据段寄存器 压入栈
pushl %eax
xorl %eax, %eax //eax清零
pushl %ebp
pushl %edi
pushl %esi
pushl %edx
decl %eax //eax = -1
pushl %ecx
pushl %ebx
cld //清除方向标志
movl %es, %ecx
movl ES(%esp), %edi //处理函数地址存入edi
movl ORIG_EAX(%esp), %edx //error code存入edx
movl %eax, ORIG_EAX(%esp) //原错误码位置写入-1,据ulk解释是区别于0x80异常
movl %ecx, ES(%esp) //es保存在距离栈顶0x20byte的位置 ES定义等于0x20
movl $(__USER_DS), %ecx
movl %ecx, %ds
movl %ecx, %es
movl %esp,%eax //栈顶位置保存在eax中, 源吗中注释的: # pt_regs pointer 不知道eax和函数调用有什么关系
call *%edi
jmp ret_from_exception
在TRap.c文件中用宏定义的 do_divide error、dp_int3等异常处理函数
#define DO_ERROR(trapnr, signr, str, name) \
fastcall void do_##name(struct pt_regs * regs, long error_code) \
{ \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return; \
do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
}#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
fastcall void do_##name(struct pt_regs * regs, long error_code) \
{ \
siginfo_t info; \
info.si_signo = signr; \
info.si_errno = 0; \
info.si_code = sicode; \
info.si_addr = (void __user *)siaddr; \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return; \
do_trap(trapnr, signr, str, 0, regs, error_code, &info); \
}#define DO_VM86_ERROR(trapnr, signr, str, name) \
fastcall void do_##name(struct pt_regs * regs, long error_code) \
{ \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return; \
do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
}#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
fastcall void do_##name(struct pt_regs * regs, long error_code) \
{ \
siginfo_t info; \
info.si_signo = signr; \
info.si_errno = 0; \
info.si_code = sicode; \
info.si_addr = (void __user *)siaddr; \
if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
== NOTIFY_STOP) \
return; \
do_trap(trapnr, signr, str, 1, regs, error_code, &info); \
}DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip)
#ifndef CONFIG_KPROBES
DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
#endif
DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
do_page_fault的函数定义:
fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
c的函数参数是通过压栈传递的,所以此时栈中原来压入的寄存器等就对应了函数的参数(参数从左到右 对应 栈顶到栈低)
此文章为自己继续学习、背忘用,欢迎留言指正或补充我未知的。