懂C++和汇编的朋友进
参数传递的过程不是很明白
我们还没学到汇编语言,看的不是很明白
麻烦大家解释下汇编代码,谢谢大家!
//C++代码:#include<iostream>using namespace std;class A{public: A(int x = 0) : a(x){cout<<"normal"<<endl;} A(const A &ref) : a(ref.a){cout<<"copy"<<endl;} int a;};void test(A x){}int main(){ A a; test(a); system("pause"); return 0;}//汇编代码:17: int main()18: {004011B0 push ebp004011B1 mov ebp,esp004011B3 sub esp,48h004011B6 push ebx004011B7 push esi004011B8 push edi004011B9 lea edi,[ebp-48h]004011BC mov ecx,12h004011C1 mov eax,0CCCCCCCCh004011C6 rep stos dword ptr [edi]19: A a;004011C8 push 0004011CA lea ecx,[ebp-4] //ecx传递this指针?004011CD call @ILT+10(A::A) (0040100f) //构造局部对象a20:21: test(a);004011D2 push ecx //传递拷贝构造函数的引用参数 即对象a的地址004011D3 mov ecx,esp //这条语句是干嘛的? 为形参分配空间?004011D5 lea eax,[ebp-4]004011D8 push eax //这条语句的作用是什么? 构造形参的话this指针有了,参数也有了,怎么此处又将a的地址入栈? 004011D9 call @ILT+150(A::A) (0040109b) //在ecx指向的空间以已经压栈的a的地址做引用参数拷贝构造形参?004011DE call @ILT+180(test) (004010b9) //004011E3 add esp,422: system("pause");004011E6 push offset string "pause" (0043101c)004011EB call system (00409140)004011F0 add esp,423: return 0;004011F3 xor eax,eax24: }13: void test(A x)14: {00401180 push ebp00401181 mov ebp,esp00401183 sub esp,40h00401186 push ebx00401187 push esi00401188 push edi00401189 lea edi,[ebp-40h]0040118C mov ecx,10h00401191 mov eax,0CCCCCCCCh00401196 rep stos dword ptr [edi]15: }00401198 pop edi00401199 pop esi0040119A pop ebx0040119B mov esp,ebp0040119D pop ebp0040119E ret
19: A a;
004011C8 push 0 ;实际要调用A(int x = 0)这个构造函数,
;这个是默认参数入栈
004011CA lea ecx,[ebp-4] ;将a对象的地址存入ecx,vc一般this存入ecx
;gcc中this作为最后一参数入栈的,显然ebp-4 ~ebp这段空间就是a的存储空间
004011CD call @ILT+10(A::A) (0040100f) //构造局部对象a
20:
21: test(a);
004011D2 push ecx ;将ecx入栈保存
004011D3 mov ecx,esp ;将esp保存到ecx,说明编译器打算将esp-4~esp
;作为test函数中参数a对应的内存,test传参时要调用A的拷贝构造函数生成一个临时对象
004011D5 lea eax,[ebp-4];将a的地址保存eax
004011D8 push eax ;a作为参数入栈,调用A的拷贝构造函数,
;在esp-4~esp处生成一个临时对象
004011D9 call @ILT+150(A::A) (0040109b)
004011DE call @ILT+180(test) (004010b9) ;由于在上个栈帧顶端esp-4~esp已经生成了一个
;一个临时对象a,所以省去了push操作,直接调用test函数
004011E3 add esp,4
22: system("pause");
004011E6 push offset string "pause" (0043101c)
004011EB call system (00409140)
004011F0 add esp,4
23: return 0;
004011F3 xor eax,eax
24: }
13: void test(A x)14: {00401180 push ebp00401181 mov ebp,esp00401183 sub esp,40h00401186 push ebx00401187 push esi00401188 push edi00401189 lea edi,[ebp-40h]0040118C mov ecx,10h00401191 mov eax,0CCCCCCCCh00401196 rep stos dword ptr [edi]15: }00401198 pop edi00401199 pop esi0040119A pop ebx0040119B mov esp,ebp0040119D pop ebp0040119E ret19: A a;004011C8 push 0 ;实际要调用A(int x = 0)这个构造函数, ;这个是默认参数入栈004011CA lea ecx,[ebp-4] ;将a对象的地址存入ecx,vc一般this存入ecx ;gcc中this作为最后一个参数入栈,显然ebp-4 ~ebp-1这段空间就是a的存储空间004011CD call @ILT+10(A::A) (0040100f) ;构造局部变量a20:21: test(a);004011D2 push ecx ;将ecx入栈保存004011D3 mov ecx,esp ;将esp保存到ecx,调用构造函数隐式传入的this的值保存在ecx里,此时this=esp,说明编译器打算将esp~esp+3, ;作为test传参时调用A的拷贝构造函数生成一个临时对象的存储空间, ;也就是说esp~esp+3保存由于test函数调用产生的临时对象004011D5 lea eax,[ebp-4] ;将a的地址保存eax,由于生成临时对象调用的A(const A &ref)是传的引用, ;所以把a的对象地址压入栈中,作为A(const A &ref)参数,从这也可以看出引用在底层实现和指针差不多004011D8 push eax 004011D9 call @ILT+150(A::A) (0040109b) ;用来生成临时对象,调用A(const A &ref)在esp~esp+3处生成临时对象。004011DE call @ILT+180(test) (004010b9) ;由于类成员函数是thiscall调用约定,自己清理栈,所以A(const A &ref)调用完毕, ;上面eax会出栈,此时栈顶就是临时对象的存在空间。 ;调用test函数时,保证是从test对应的栈帧的ebp+4位置访问临时变量的,此时访问的应该是生成的临时对象的空间的004011E3 add esp,422: system("pause");004011E6 push offset string "pause" (0043101c)004011EB call system (00409140)004011F0 add esp,423: return 0;004011F3 xor eax,eax24: }
[解决办法]
004011D2 push ecx ;将ecx入栈保存
这条指令跟拷贝构造函数调用没啥关系,因为下面ecx被修改了,这条指令只是保存修改之前的ecx的值。
在vc下,成员函数调用参数从右到左入栈,this存入ecx。
push eax;才是参数入栈, mov ecx,esp 则是保存this指针
[解决办法]
注释那么多,应该全懂了吧
[解决办法]
是有错误
[解决办法]
回复有风险,接分须谨慎!
[解决办法]