函数调用时的栈帧结构以及临时变量的深入研究
2011-12-17 17:41
399 查看
C++代码:
对应汇编代码:
栈帧结构图:
![](http://hi.csdn.net/attachment/201112/17/10181841_13241128483M3k.jpg)
这里只讨论了main函数和func函数的栈帧结构,构造函数调用时的栈帧结构没有讨论,函数调用完之后都会清栈,所以我们可以单独的研究这两个函数的栈帧,对于其中调用的构造函数可以不予理会。
#include<iostream> #include<string> using namespace std; class base { public: base():id(0){} base(int i):id(i){} base(const base &orig):id(orig.id){cout << "called copy constructor" << endl;} private: int id; }; base func(base a) { base tem(a); return tem; } int main() { base mb1(7),mb2; mb2 = func(mb1); return 0; }
对应汇编代码:
19: int main() 20: { 00401270 push ebp 00401271 mov ebp,esp 00401273 sub esp,50h 00401276 push ebx 00401277 push esi 00401278 push edi 00401279 lea edi,[ebp-50h] 0040127C mov ecx,14h 00401281 mov eax,0CCCCCCCCh 00401286 rep stos dword ptr [edi] 21: base mb1(7),mb2; 00401288 push 7 0040128A lea ecx,[ebp-4] //这里就是指定空间来装mb1,地址是0x0012ff7c,以ebp为基址向下偏移4个字节处
0040128D call @ILT+105(base::base) (0040106e)//指定了空间后就调用构造函数来填充 00401292 lea ecx,[ebp-8] //这里指定空间来装mb2,地址是0x0012ff78,同样以ebp为基址向下偏移8个字节处 00401295 call @ILT+85(base::base) (0040105a)//指定了空间后就调用构造函数来填充 22: mb2 = func(mb1); 0040129A push ecx 0040129B mov ecx,esp 0040129D lea eax,[ebp-4] 004012A0 push eax 004012A1 call @ILT+150(base::base) (0040109b) 004012A6 lea ecx,[ebp-10h]//将ebp-10h得到一个地址,也就是0x0012ff70赋给ecx 004012A9 push ecx //在栈上保存这个地址 004012AA call @ILT+30(func) (00401023) 004012AF add esp,8 004012B2 mov edx,dword ptr [eax] 004012B4 mov dword ptr [ebp-8],edx 23: return 0; 004012B7 xor eax,eax 24: } 004012B9 pop edi 004012BA pop esi 004012BB pop ebx 004012BC add esp,50h 004012BF cmp ebp,esp 004012C1 call __chkesp (00409190) 004012C6 mov esp,ebp 004012C8 pop ebp 004012C9 ret base func(base a) 15: { 00401190 push ebp 00401191 mov ebp,esp 00401193 sub esp,44h 00401196 push ebx 00401197 push esi 00401198 push edi 00401199 lea edi,[ebp-44h] 0040119C mov ecx,11h 004011A1 mov eax,0CCCCCCCCh 004011A6 rep stos dword ptr [edi] 16: base tem(a); 004011A8 lea eax,[ebp+0Ch]//这个地方,ebp+0ch后恰好是压入的实参地址 004011AB push eax //这里也是实参进栈为调用构造函数作准备 004011AC lea ecx,[ebp-4] //这里为局部变量tem找一个容纳地址,以ebp为基址向下偏移4个字节处 004011AF call @ILT+150(base::base) (0040109b)//调用构造函数进行填充 17: return tem; 004011B4 lea ecx,[ebp-4] //取地址放入ecx 004011B7 push ecx 004011B8 mov ecx,dword ptr [ebp+8]//取ebp向上偏移8个字节处的地址里面的地址值赋给ecx,这个地址是0x0012ff70 004011BB call @ILT+150(base::base) (0040109b)//调用构造函数进行填充,也就是填充0x0012ff70 004011C0 mov eax,dword ptr [ebp+8]//将临时变量地址放入到eax 18: } 004011C3 pop edi 004011C4 pop esi 004011C5 pop ebx 004011C6 add esp,44h 004011C9 cmp ebp,esp 004011CB call __chkesp (00409190) 004011D0 mov esp,ebp 004011D2 pop ebp 004011D3 ret
栈帧结构图:
![](http://hi.csdn.net/attachment/201112/17/10181841_13241128483M3k.jpg)
这里只讨论了main函数和func函数的栈帧结构,构造函数调用时的栈帧结构没有讨论,函数调用完之后都会清栈,所以我们可以单独的研究这两个函数的栈帧,对于其中调用的构造函数可以不予理会。
相关文章推荐
- Python、C++中编写函数以及不使用临时变量交换两变量值的比较
- 函数调用的具体过程以及栈帧的创建和销毁
- IA32的栈帧结构和函数调用过程
- 函数调用入栈基本步骤(感觉和进程的栈帧结构一块看会比较容易理解)
- 函数的调用过程、栈帧的创建以及销毁
- 函数调用时的参数传递和栈帧结构问题
- 【栈帧】深入理解函数的调用(栈帧)
- Javascript函数深入研究:函数中判断自己是以哪种形式被调用的,是A(),还是new A()或者其它?
- 函数调用入栈基本步骤(感觉和进程的栈帧结构一块看会比较容易理解)
- 深入理解函数的调用过程——栈帧
- 浅谈C语言中的函数调用方式-----栈帧结构
- Java 中的 int 与 Integer 用于 List<Integer> 时,以及通过打印变量检測程序执行和函数调用次数计数
- 关于javascript中变量是如何存储调用、以及函数的继承实现
- C#使用WinAPI 修改电源设置,临时禁止笔记本合上盖子时睡眠(使用PowerGetActiveScheme等函数,以及C#对WINAPI的调用)
- visual studio 小技巧 查看函数的调用层次结构 以及 部分常用快捷键
- 栈帧——函数调用,变量在内存中如何存取
- 函数调用入栈基本步骤(感觉和进程的栈帧结构一块看会比较容易理解)
- 浅谈函数的调用过程,栈帧的创建以及销毁
- 关于delphi 的函数调用和参数传递方式深入研究之疑惑
- 函数的调用过程(栈帧结构)—C语言版