linux 0.11 源码学习(七)

trap.c & Asm.s

trap.c和Asm.s主要完成的是系统中断和陷阱的初始化定义。

注:在80386体系的CPU中中断描述符表替代了中断向量表,IDT的描述符可以是中断门、陷阱门或者任务门。IDT中的中断门和陷阱门的定义如下:BYTE0/1(偏移底字节),BYTE2/3(选择子)、BYTE4/5(属性)、BYTE6/7 (偏移高字节)。通过两个字节的段描述符合四个字节的偏移就可以找到相应的目标代码地址。

因此在看trap.c和Asm.s的代码前,首先要分析下一部分system.h中的代码,如下:

#define _set_gate(gate_addr,type,dpl,addr) \
__asm__ ("movw %%dx,%%ax\n\t" \ //下面四行汇编就是完成IDT描述符的填充
    "movw %0,%%dx\n\t" \
    "movl %%eax,%1\n\t" \
    "movl %%edx,%2" \
    : \ //无输出
    : "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \//%0参数为IDT的BYTE4,5
    "o" (*((char *) (gate_addr))), \//%1变量为内存gate_addr,即门描述符的低四字节
    "o" (*(4+(char *) (gate_addr))), \ //%2变量为内存gate_addr+4
    "d" ((char *) (addr)),"a" (0x00080000))//edx = addr, eax = 0x00080000; 0x0008为选择字,即对应GDT中的第二个描述符,代码段

#define set_intr_gate(n,addr) \ //n为中断索引 _set_gate(&idt[n],
14,0,addr) // 14 0x0e属于中断门,DPL设置为0不允许用户态直接访问 #define set_trap_gate(n,addr) \ _set_gate(&idt[n],15,0,addr) // 15 0x0f属于属于陷阱门,DPL设置为0不允许用户态直接访问 #define set_system_gate(n,addr) \ _set_gate(&idt[n],15,3,addr) //调用门,DPL为3允许用户态访问

在trap.c和Asm.s中具体设置陷阱比较类似,以除零出错为例:

在trap.c的init函数中 set_trap_gate(0, &divide_error)。divider_error函数定义在Asm.s中如下:

divide_error:
    pushl $do_divide_error //do_divide_error陷阱处理函数入栈

do_divide_error定义在trap.c中,如下:

void do_divide_error(long esp, long error_code)
{
    die("divide error",esp,error_code);//打印当前出错进程的信息
}

 

其他代码类似,诸如int 3中断或堆栈段错误。

int3:
    pushl $do_int3
    jmp no_error_code

stack_segment:
    pushl $do_stack_segment
    jmp error_code

注:这里要值得注意的是do_XX函数的调用,是通过在no_error_code或者error_code中利用iret和堆栈实现的。其中no_error_code要比error_code少入栈一个参数error_code,即我们看到的do_divide_error中的第二个参数。如下:

error_code:
    xchgl %eax,4(%esp)       # error code <-> %eax
    xchgl %ebx,(%esp)        # &function <-> %ebx
    pushl %ecx
    pushl %edx
    pushl %edi
    pushl %esi
    pushl %ebp
    push %ds
    push %es
    push %fs
    pushl %eax            # error code
    lea 44(%esp),%eax     # offset //地址esp+44 赋值给eax,44是堆栈中寄存器长度和,参考赵博的书
    pushl %eax
    movl $0x10,%eax
    mov %ax,%ds
    mov %ax,%es
    mov %ax,%fs
    call *%ebx //调用具体的函数,C语言的入参是放在堆栈里的;
    addl $8,%esp //跳过error code和function这8字节
    pop %fs
    pop %es
    pop %ds
    popl %ebp
    popl %esi
    popl %edi
    popl %edx
    popl %ecx
    popl %ebx
    popl %eax
    iret
posted @ 2013-05-04 13:37  Fredric_2013  阅读(436)  评论(0编辑  收藏  举报