汇编调用C函数时的堆栈变化

先分析《自己动手写操作系统》中的部分程序

 

//初始化中断向量表(见protect.c文件)

init_idt_desc(INT_VECTOR_COPROC_ERR,DA_386IGate, copr_error, PRIVILEGE_KRNL);

//INT_VECTOR_COPROC_ERR =16

 

//中断处理函数的定义

copr_error:

       push 0xFFFFFFFF

       push 16

       jmp exception

 

//exception函数定义

exception:

       call exception_handler

       add esp, 4*2  //让栈顶指向EIP,堆栈中从顶向下依次是:EIP、CS、EFLAGS

 

//exception_handler函数定义

void  exception_handler(int vec_no, int err_code,int eip, int cs, int eflags)

{

 

}

核心问题:汇编语句call  exception_handler发生前后堆栈的变化情况

背景知识:如果中断或异常发生时没有特权级变换,那么eflags,cs,eip将依次被压入堆栈,如果有出错码的话,出错码将在最后被压栈。有特权级变换的情况下同样会发生堆栈切换,此时,ss和esp将被压入内层堆栈,然后是eflags,cs,eip,出错码(如果有的话)。对于不同中断号,不总会有出错码,可以参考《自己动手写操作系统》P89的表3.8

分析堆栈过程:

    当CPU捕获到16号中断后,首先将eflags,cs,eip压入堆栈

    随后程序来到中断处理函数copr_error处,又将出错码和16依次压入堆栈

    然后程序跳转到exception函数处,执行call  exception_handler函数,此时CPU自动将call exception_handler语句的下一条语句(add esp, 4*2)的地址压栈,此时堆栈情况如下:

 

 

Addr of (add esp, 4*2)

16

出错码(如果有的话)

Eip

Cs

Eflags

 

程序跳转到exception_handler处,虽然是C函数,但是底层汇编实现代码的头两句一定是:

    push ebp//将调用exception_handler的点处堆栈基址保存,方便返回

    mov ebp, esp//将栈顶指针保存到ebp,方便索引栈中的参数

exception_handler函数虽然有5个参数,都会根据ebp加减偏移量在堆栈中找到,但是并不会有出栈的操作,这点谨记!

    call exception_handler执行过程中,堆栈中会存在Addr of (add esp, 4*2)这一项,而当call  exception_handler执行结束后,开始执行add esp, 4*2之前,堆栈中的Addr of (add esp, 4*2)这一项会自动弹出。

    所以add esp,4*2执行结束后,会将esp指针指到eip地址处

你可能感兴趣的:(汇编call指令)