函数栈的调用

分析如下的文件:(文件名是hi.c)
int g(int x, int y)
{
  return x + y + 3;
}

int f(int x, int y)
{
  return g(x,y);
}

int main(void)
{
  return f(3,4) + 1;
}

通过反汇编后得到如下的内容:

使用反汇编的命令:gcc -S hi.c -m32

生成如下代码:

  .file "hi.c"
 .text
 .globl g
 .type g, @function
g:
.LFB0:
.cfi_startproc
 pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
 movl %esp, %ebp
.cfi_def_cfa_register 5
movl 12(%ebp), %eax
movl 8(%ebp), %edx
addl %edx, %eax
addl $3, %eax
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size g, .-g
.globl  f
.type f, @function
f:
.LFB1:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $8, %esp
movl 12(%ebp), %eax
movl %eax, 4(%esp)
movl 8(%ebp), %eax
movl %eax, (%esp)
call g
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE1:
.size f, .-f
.globl main
.type main, @function
main:
.LFB2:
 .cfi_startproc
 pushl %ebp
 .cfi_def_cfa_offset 8
 .cfi_offset 5, -8
 movl %esp, %ebp
 .cfi_def_cfa_register 5
 subl $8, %esp
 movl $4, 4(%esp)
 movl $3, (%esp)
 call f
 addl $1, %eax
 leave
 .cfi_restore 5
 .cfi_def_cfa 4, 4
 ret
 .cfi_endproc
.LFE2:
 .size main, .-main
 .ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
 .section .note.GNU-stack,"",@progbits
在这个代码中,核心的汇编代码与前面带有'.'符号的语句是无关的所有去掉带有'.'符号的语句就得到了如下更好分析的语句:

g:
 pushl %ebp
 movl %esp, %ebp
 movl 12(%ebp), %eax
 movl 8(%ebp), %edx
 addl %edx, %eax
 addl $3, %eax
 popl %ebp
 ret
f:
 pushl %ebp           
 movl %esp, %ebp     
 subl $8, %esp        ;栈中申请8个字节
 movl 12(%ebp), %eax  ;相当于4;中间经过了 栈如下: ebp|eip|3|4:
 movl %eax, 4(%esp)   ;把4入栈
 movl 8(%ebp), %eax   ;相当于3赋值给eax;
 movl %eax, (%esp)    ;
 call g               ;调用g
 leave
 ret
main:
 pushl %ebp       ;ebp入栈
 movl  %esp, %ebp ;将esp的值赋值给ebp
 subl  $8, %esp   ;将esp的值减8
 movl  $4, 4(%esp);相当与esp+4的位置的内存值赋值为4;我们看到函数调用的时候4在3的右边所以是从右到左入栈
 movl  $3, (%esp) ;把3入栈   [这两句相当于pushl $4;push $3]
 call  f          ;调用函数f:call会将eip入栈
 addl  $1, %eax   ;将返回值与函数的返回值加一
 leave              ;相当于;movl %ebp, %esp; popl %ebp
 ret                ;返回给loader
分析:

1:咱们c语言的入口函数是main;

2:函数之间的调用遵从c语言的调用约定;

 a)调用参数从右到左入栈

 b)调用者负责清理堆栈

 c)eax是函数的返回值


燕涛: 原创作品转载请注明出处 :《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值