从汇编简要分析c语言函数调用栈

先写个简单的小demo, 分析一下c的函数调用过程。

void test(int a, int b) {
  a++;
  b+=2;
}

void haha() {
  test(3, 5);
}

int main() {
  haha();
  return 0;
}


下面是haha()的汇编代码:

Dump of assembler code for function haha:
   0x080483a1 <+0>:    push   %ebp
   0x080483a2 <+1>:    mov    %esp,%ebp
   0x080483a4 <+3>:    sub    $0x8,%esp
=> 0x080483a7 <+6>:    movl   $0x5,0x4(%esp)
   0x080483af <+14>:    movl   $0x3,(%esp)
   0x080483b6 <+21>:    call   0x8048394 <test>
   0x080483bb <+26>:    leave  
   0x080483bc <+27>:    ret    
End of assembler dump.

 此时程序暂停在test(3, 5) 这一行, 调用test时, 首先会把函数参数压栈。

  0x080483a4 <+3>:    sub    $0x8,%esp                              表示栈顶加8个字节, 可以保留两个int型参数。

  0x080483a7 <+6>:    movl   $0x5,0x4(%esp)                    第二个参数先入栈

  0x080483af <+14>:    movl   $0x3,(%esp)                          第一个参数后如栈

  0x080483b6 <+21>:    call   0x8048394 <test>                call会调用test函数, 这里隐含的操作是eip寄存器内容入栈,用来保存函数调用结束后应该执行的命令地址。

 

下面是test的汇编代码:

Dump of assembler code for function test:
   0x08048394 <+0>:    push   %ebp
   0x08048395 <+1>:    mov    %esp,%ebp
=> 0x08048397 <+3>:    addl   $0x1,0x8(%ebp)
   0x0804839b <+7>:    addl   $0x2,0xc(%ebp)
   0x0804839f <+11>:    pop    %ebp
   0x080483a0 <+12>:    ret    
End of assembler dump.


0x08048394 <+0>:    push   %ebp                       首先保存调用函数(haha)的栈底地址

0x08048395 <+1>:    mov    %esp,%ebp            然后把esp 内容赋给ebp寄存器, ebp保存新栈帧 (test)的栈底地址。 此时esp ebp指向栈的同一个位置。


此时ebp的内容保存着调用函数的栈底地址, 以此为基准, %ebp + 4 地址保存返回地址, %ebp + 8 保存 第一个参数,  &ebp + 12 保存第二个参数, 而比%ebp -  x  (x 为正数) 保存test函数的局部变量(这个例子没有用到局部变量)。


0x08048397 <+3>:    addl   $0x1,0x8(%ebp)  第一个参数+1

0x0804839b <+7>:    addl   $0x2,0xc(%ebp)   第二个参数+2

0x080483a0 <+12>:    ret   返回。


ebp 具有十分的意义, 它总是保存上层调用时的ebp值, 而且在没层调用中都可一通过ebp (向栈底方向)找到返回地址, 参数, (向栈顶方向) 找到局部变量。 这是一个递归的过程。


如上所示, 当程序执行到 0x08048397 <+3>:    addl   $0x1,0x8(%ebp)  的时候, 打印ebp 内容:

(gdb) p $ebp
$1 = (void *) 0xbffff310

表示test的栈底地址为0xbffff310


0xbffff310 + 8 为第一参数3
(gdb) x /1uw 0xbffff318
0xbffff318:    3


0xbffff310 + 12 为第一参数5
(gdb) x /1uw 0xbffff31c
0xbffff31c:    5


0xbffff310 + 4 为 返回地址

(gdb) x /1aw 0xbffff314 
0xbffff314:    0x80483bb <haha+26>

而 0x80483bb <haha+26> 对应函数haha中的 0x080483bb <+26>:    leave 



                                   

你可能感兴趣的:(c,汇编,function,语言)