浅谈C++中函数调用的底层机制

先来简单说一说栈指针和帧指针。

栈指针就是用来存储栈顶的地址,帧指针是用来存储函数刚被调用时候的地址。

举个例子:

int add(int a,int b){

  int c=a+b;

  return c;

}

这是被调函数。

int x=add( 5,7);

这是主调函数的一个语句。

接下来是主调函数的反汇编代码:

8048459:  movl   $0x7,0x4(%esp)

8048461:  movl   $0x5,(%esp)

8048468:  call   8048434

804846d:  mov   %eax,-0x8(%ebp)

再看被调函数的反汇编代码:

8048434:  push   %ebp

8048435:  mov   %esp,%ebp

8048437:  sub   $0x4,%esp

804843a:  mov   0xc(%ebp),%eax

804843d:  add   0x8(%ebp),%eax

8048440:  mov   %eax,-0x4(%ebp)

8048443:  mov   -0x4(%ebp),%eax

8048446:  leave

8048447:  ret

前边的十六进制就是代码所在的内存地址,首先执行第一条指令,将7装入esp+4地址中,再将5装入esp地址中,接下来执行call指令,call指令后的地址是被调函数的入口地址,call的作用是将下一条指令的地址压入运行栈,这个地址就是函数返回时的地址,接下来调用被调函数的代码,第一条指令是将ebp的原值压入运行栈,然后将esp的值赋给ebp,同时将esp减4,这是为了给被调函数的局部变量c留空间,然后将ebp+12的值装入eax寄存器,再将ebp+8的值与eax中的值相加保存在eax寄存器中,然后将eax寄存器中的值放入ebp-4地址中,至此,函数中的int c=a+b;指令就执行完了,接下来执行将ebp-4中的值装入eax寄存器中,接下来的指令是将ebp的值赋给esp,同时将栈顶元素弹出并赋给ebp,这样ebp和esp就回到了函数调用之初的状态,接下来的指令是将返回地址弹出并跳转至该地址,这样就回到了主调函数中,然后将eax的值装入ebp-8地址内,就是将c的值赋给x,这样整个函数调用就完成了。

以上就是我对函数调用的一些理解。

你可能感兴趣的:(c++,博客,语言,内存,面向对象,C++)