【汇编与C之间的关系】 push bp(或 push %ebp)mov ebp esp的作用!!!

最近,读汇编与c的关系;读到将c源码反汇编时,有段代码不太了解----------------

此为c代码:

int bar(int c, int d)
{
	int e = c + d;
	return e;
}

int foo(int a, int b)
{
	return bar(a, b);
}

int main(void)
{
	foo(2, 3);
	return 0;
}
反汇编:

int main:

foo(2, 3);
 80483d5:	c7 44 24 04 03 00 00 	movl   $0x3,0x4(%esp)
 80483dc:	00 
 80483dd:	c7 04 24 02 00 00 00 	movl   $0x2,(%esp)
 80483e4:	e8 c1 ff ff ff       	call   80483aa 
	return 0;
 80483e9:	b8 00 00 00 00       	mov    $0x0,%eax
int foo(int a, int b)
{
 80483aa:	55                   	push   %ebp
80483ab:	89 e5                	mov    %esp,%ebp
 80483ad:	83 ec 08             	sub    $0x8,%esp
 
  
return bar(a, b);
 80483b0:	8b 45 0c             	mov    0xc(%ebp),%eax
 80483b3:	89 44 24 04          	mov    %eax,0x4(%esp)
 80483b7:	8b 45 08             	mov    0x8(%ebp),%eax
 80483ba:	89 04 24             	mov    %eax,(%esp)
 80483bd:	e8 d2 ff ff ff       	call   8048394 

int bar(int c, int d)
{
 8048394:	55                   	push   %ebp
 8048395:	89 e5                	mov    %esp,%ebp
 8048397:	83 ec 10             	sub    $0x10,%esp
	int e = c + d;
 804839a:	8b 55 0c             	mov    0xc(%ebp),%edx
 804839d:	8b 45 08             	mov    0x8(%ebp),%eax
 80483a0:	01 d0                	add    %edx,%eax
 80483a2:	89 45 fc             	mov    %eax,-0x4(%ebp)
一直看不懂调用开头的

push %bep

mov   %esp,   %ebp

是什么意思。


经过在网上查阅资料,终于在csdn上找到了答案:

http://bbs.csdn.net/topics/300013871

下面是我自己的总结:

ebp是基址指针寄存器;

esp是堆栈指针寄存器;

c语言在进行编译时,会将各个函数的局部变量压入堆栈中;

+| (栈底方向,高位地址) |
| ....................|
| ....................|
| 参数3                |
| 参数2                |
| 参数1                |
| 返回地址             |
-| 上一层[EBP]         |
| 局部变量1            |
| 局部变量2            |
|.....................|




栈一直随着函数调用的深入,一直想栈顶方向压下去。每次调用函数时候,先压函数参数(从右往左顺序压)

再压入函数调用下条指令的地址(由call完成)。

接着进入调用函数体中先执行PUSH EBP; MOV EBP ESP;(一般已经由编译器加入到函数头中了),

接着就是把函数体中的局部变量压入栈中。

再遇到函数的调用的嵌套则依此类推。

“PUSH EBP”“MOV EBP ESP”这两条指令实在大有深意:首先将EBP入栈,然后将栈顶指针ESP赋值给EBP。

“MOV EBP ESP”这条指令表面上看是用ESP把EBP原来的值覆盖了,

其实不然——因为给EBP赋值之前,原EBP值已被压栈(位于栈顶),而新的EBP又恰恰指向栈顶。
   此时EBP寄存器就已处于一个很重要的地位,该寄存器中存储着栈中的一个地址(原EBP入栈后的栈顶),

从该地址为基准,向上(栈底方向)能获取返回地址、参数值,向下(栈顶方向)能获取函数局部变量值,

而该地址处又存储着上一层函数调用时的EBP值!

这两条指令合起来是把原来ebp的值保存在栈上,

然后又给ebp赋了新值。

在每个函数的栈帧中,ebp指向栈底,而esp指向栈顶,

在函数执行过程中esp随着压栈和出栈操作随时变化,而ebp是不动的,

函数的参数和局部变量都是通过ebp的值加上一个偏移量来访问

C# code
?
1
2
3
4
int  main() 
   return  0; 

Assembly code
?
1
2
3
4
反汇编生成的汇编代码: 
     2 00411370 55               push     ebp ;保存ebp指针
     2 00411371 8bec             mov     ebp,esp ;将esp赋值给ebp,使ebp指向栈顶
     2 00411373 81ecc0000000     sub     esp,0C0h ;在堆栈中留出0ch字节的空间给局部变量使用 





你可能感兴趣的:(C,汇编,栈)