c语言的堆栈

来源:互联网 发布:淘宝店商品图片制作 编辑:程序博客网 时间:2024/04/23 20:12


int h(int x1, int x2)

{
        int h1 = 1;
        int h2 = x1+x2;
        return h2;
}


void f()
{
        int f1 = 1;
        int f2=f1+1;
        h(1, 2);
}


int main()
{
        int m = 5;
        f();
        return 0;
}

(gdb) disassemble h
Dump of assembler code for function h(int, int):
   0x08048404 <+0>:     push   %ebp                       #保存上层栈的ebp
   0x08048405 <+1>:     mov    %esp,%ebp            #上层栈的esp+8,eip和刚刚保存的ebp
   0x08048407 <+3>:     sub    $0x10,%esp            #本层栈的增长,想下增长,就是减了
   0x0804840a <+6>:     movl   $0x1,-0x8(%ebp)   #h1=1
   0x08048411 <+13>:    mov    0xc(%ebp),%eax  #x2, eax寄存器是不会压栈的,总是这个函数里给eax赋初始值后才使用.
   0x08048414 <+16>:    add    0x8(%ebp),%eax   #x1+x2      
   0x08048417 <+19>:    mov    %eax,-0x4(%ebp) #得到h2
   0x0804841a <+22>:    mov    -0x4(%ebp),%eax 
   0x0804841d <+25>:    leave  
   0x0804841e <+26>:    ret    
End of assembler dump.

(gdb) disassemble f
Dump of assembler code for function f():
   0x08048420 <+0>:     push   %ebp
   0x08048421 <+1>:     mov    %esp,%ebp
   0x08048423 <+3>:     sub    $0x18,%esp
   0x08048426 <+6>:     movl   $0x1,-0x8(%ebp)
   0x0804842d <+13>:    mov    -0x8(%ebp),%eax
   0x08048430 <+16>:    add    $0x1,%eax
   0x08048433 <+19>:    mov    %eax,-0x4(%ebp)
   0x08048436 <+22>:    movl   $0x2,0x4(%esp)
   0x0804843e <+30>:    movl   $0x1,(%esp)
   0x08048445 <+37>:    call   0x8048404 <h(int, int)>
   0x0804844a <+42>:    leave  
   0x0804844b <+43>:    ret    
End of assembler dump.

(gdb) disassemble main

Dump of assembler code for function main():
   0x0804844c <+0>:     lea    0x4(%esp),%ecx
   0x08048450 <+4>:     and    $0xfffffff0,%esp
   0x08048453 <+7>:     pushl  -0x4(%ecx)
   0x08048456 <+10>:    push   %ebp
   0x08048457 <+11>:    mov    %esp,%ebp
   0x08048459 <+13>:    push   %ecx
   0x0804845a <+14>:    sub    $0x10,%esp
   0x0804845d <+17>:    movl   $0x5,-0x8(%ebp)
   0x08048464 <+24>:    call   0x8048420 <f()>
   0x08048469 <+29>:    mov    $0x0,%eax
   0x0804846e <+34>:    add    $0x10,%esp
   0x08048471 <+37>:    pop    %ecx
   0x08048472 <+38>:    pop    %ebp
   0x08048473 <+39>:    lea    -0x4(%ecx),%esp
   0x08048476 <+42>:    ret    
End of assembler dump.

Linux汇编指令格式见http://www.ibm.com/developerworks/cn/linux/l-assembly/

LEAVE指令

相当于以下两条指令:

movl %ebp,%esp

popl %ebp

CALL指令:

调用一个函数,push %EIP

RET指令:

返回函数,pop %EIP

调用的参数保存在调用者的栈上,本层的ebp指向的地址内容依次是 上层的ebp, 上层的下个指令EIP, 本函数参数n,参数n-1,参数1..., 调用者的零时变量(先定义的地址大,后定义的接近栈顶)
用本层栈的ebp-4是保存的上层栈的下一次执行的指令地址.
本层的esp减去main函数的ebp就可以得到调用的栈空间