esp ebp eip 函数压栈

来源:互联网 发布:加拿大28预测软件 编辑:程序博客网 时间:2024/05/11 02:53

intel cpu的程序,关于函数调用压栈的过程,到底如何实现的? ESP,EBP,EIP都负责什么任务?

我们现在要调用函数A, 有三个参数,a,b,c.。执行A函数,需要两部,第一步, 在进入函数之前,要将c,b,a依次压入栈中,然后进入到函数A中。第二步,开始执行程序。

第一步具体的细节为:

mov c  0xC(esp)mov b 0x8(esp)mov a 0x4(esp)call A
(esp)代表堆栈寄存器esp所指向的内存地址。oxc(esp)代表了(esp所指向的内存地址+0xC)的地址。

执行call A指令时,会将EIP(下一步要执行的指令的地址)存入堆栈中,即好比执行了mov EIP (esp).

第二步的细节为:

push ebpmov esp ebp..........pop ebpret
第二步中,push ebp和mov esp ebp不是A函数中要处理的逻辑,是为了函数调用而实现的,任何一个函数调用都会有这两步。   ,.....代表函数A中的一些处理分为几种情况:

            (1) 如果要使用函数A的参数,则使用ebp+offset来获得;

             (2) 如果要进行函数调用,则像第一步一样;

             (3) 如果要使用栈stack, 则使用esp堆栈指针。但是在第二步的ret之前,要将esp恢复到原值。

intel中关于call操作的解释为,先将esp的值改变,然后压入栈中:

ELSE IF StackAddrSize = 32THENIF OperandSize = 32THENESP ← (ESP − 4);IF (SRC is FS or GS)THENTEMP = ZeroExtend32(SRELSE IF (SRC is IMMEDIATE) TEMP = SignExtend32(SRCELSETEMP = SRC;FI;SS:ESP ← TEMP; (* Push doubleworELSE (* OperandSize = 16*)ESP ← (ESP − 2);SS:ESP ← SRC; (* Push word *)

可以看到,第二步完成之后,ebp和esp的值都没有改变。

在进行第二步时,刚进入第二步,执行了push ebp和mov esp ebp, 但是还没有执行A自己代码时,(esp)的值为执行完A后要执行的代码的地址EIP的值。0x4(esp)的值为参数a, 0x8(esp)为参数b,0xc(esp)为参数c.

总结:
我写这篇文章所用的编译器为GCC, Intel x86平台。希望对于esp, ebp,eip作用和函数调用如何实现比较困惑的朋友有所帮助。