戻り値がstructまたはclassオブジェクトである場合【4】
12777 ワード
C++コード:
F 7コンパイル接続(debugモード).ブレークポイントを追加し、F 5でデバッグし、alt+8で逆アセンブリウィンドウが表示されます.アセンブリコードは次のとおりです.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
以上が構造関数がある場合,structはクラスとして解釈される.コンストラクション関数がない場合は、コピーが1回増えます.
基本的に3回のコピーがあります.サブ関数では、変数を一時的に戻り値ストレージにコピーし、呼び出し側で別の一時ストレージにコピーし、そのストレージから受け入れられた変数にコピーします.
関数呼び出しの手順を明確にします.
(1)パラメータを右から左に入力してスタックに入り、参照するとpush変数のアドレスになる.
(2)戻り値が大きいオブジェクト(64 bitより大きい)であり、直接戻りであり、戻り参照ではない場合(戻り参照であれば直接アドレスを返す)は、遠いメモリを探して、そのアドレスpushをスタックに入れ、将来的には到来時に戻り値を格納する
(3)call funcを指す.funcは関数名です.このときeipレジスタのコンテンツは自動的にスタックされます.
(4)ここから関数に入ります!Push ebp、callerのebpをスタックに入れます.
(5)mov ebp, esp.現在のスタックトップはスタックベースとして使用されます.calleeは自分のスタックスペースを持っています!
(6)sub esp,100.100は勝手に書いてあるので、別の数かもしれません.システムは一時変数の空間を割り当てます.
(7)ebx,esi,ediなどのレジスタがスタックに入る.
(8)上記申請のスペースを0 xCCで埋める.
(9)仕事をする...
(10)関数が返されます.戻り値は大きなオブジェクトです.オブジェクトをebp+8の場所の値が指す位置にコピーします.そうですね.(2)ステップ目で戻り値を一時的に格納する場所を指します.
(11)mov esp,ebp.スタックスペースをクリーンアップするのは簡単ですが、スタックの上部の位置を変更すればいいです.
(12)ret.このコマンドはスタック内のeipに対応する値をポップアップし、この関数を呼び出した後の次のコマンドが何であるかを知ることができます.
(13)add esp,XXX.入力パラメータと一時保存スペースポインタがあるので、ここでスタックバランスを作ります.
(14)先ほど述べた戻り値一時格納空間から戻り値を別の一時格納空間にコピーする.この戻り値を受け入れる変数がある場合は、新しい一時保存スペースからその変数にコピーします.変数が受け入れられない場合は、使用しません.
(15)呼び出しが終了し,何をすべきか.
注:スタックスペースは一般的にデフォルト1 Mで、再帰的に深すぎるとスタックがオーバーフローします.
ref:
http://wenku.baidu.com/view/bea115ccda38376baf1faec7.html
http://www.cnblogs.com/zplutor/archive/2011/09/25/2190315.html
struct AB
{
int ia;
int ib;
int ic;
AB(){}
};
AB su_4() //
{
AB c;
c.ia=100;
c.ib=150;
c.ic=200;
return c;
}
int main()
{
AB r;
r=su_4(); //
getchar();
return 0;
}
F 7コンパイル接続(debugモード).ブレークポイントを追加し、F 5でデバッグし、alt+8で逆アセンブリウィンドウが表示されます.アセンブリコードは次のとおりです.
51: int main()
52: {
004115F0 55 push ebp % 【1】 main
004115F1 8B EC mov ebp,esp
004115F3 81 EC E8 00 00 00 sub esp,0E8h
004115F9 53 push ebx
004115FA 56 push esi
004115FB 57 push edi
004115FC 8D BD 18 FF FF FF lea edi,[ebp-0E8h]
00411602 B9 3A 00 00 00 mov ecx,3Ah
00411607 B8 CC CC CC CC mov eax,0CCCCCCCCh
0041160C F3 AB rep stos dword ptr es:[edi] % end 【1】
60: AB r;
0041160E 8D 4D F0 lea ecx,[r] % 【2】 ,
00411611 E8 30 FA FF FF call AB::AB (411046h)
61: r=su_4();
00411616 8D 85 1C FF FF FF lea eax,[ebp-0E4h] % 【3】 su_4() 。 , ( 64bit), % 。 ebp-0E4h, , 。 eax, push
0041161C 50 push eax
0041161D E8 65 FA FF FF call su_4 (411087h) % 。eip 。
00411622 83 C4 04 add esp,4 % push eax, esp , 。
00411625 8B 08 mov ecx,dword ptr [eax] % eax 。 12 , mov 。 % r 。
00411627 89 4D F0 mov dword ptr [r],ecx
0041162A 8B 50 04 mov edx,dword ptr [eax+4]
0041162D 89 55 F4 mov dword ptr [ebp-0Ch],edx
00411630 8B 40 08 mov eax,dword ptr [eax+8]
00411633 89 45 F8 mov dword ptr [ebp-8],eax
105: getchar(); % 【4】 main , 。
00411636 8B F4 mov esi,esp
00411638 FF 15 B4 82 41 00 call dword ptr [__imp__getchar (4182B4h)]
0041163E 3B F4 cmp esi,esp
00411640 E8 FB FA FF FF call @ILT+315(__RTC_CheckEsp) (411140h)
106: return 0;
00411645 33 C0 xor eax,eax
107: }
00411647 52 push edx
00411648 8B CD mov ecx,ebp
0041164A 50 push eax
0041164B 8D 15 6C 16 41 00 lea edx,[ (41166Ch)]
00411651 E8 2C FA FF FF call @ILT+125(@_RTC_CheckStackVars@8) (411082h)
00411656 58 pop eax
00411657 5A pop edx
00411658 5F pop edi
00411659 5E pop esi
0041165A 5B pop ebx
0041165B 81 C4 E8 00 00 00 add esp,0E8h
00411661 3B EC cmp ebp,esp
00411663 E8 D8 FA FF FF call @ILT+315(__RTC_CheckEsp) (411140h)
00411668 8B E5 mov esp,ebp
0041166A 5D pop ebp
0041166B C3 ret
:
26: struct AB
27: {
28: int ia;
29: int ib;
30: int ic;
31: AB(){}
004115B0 55 push ebp
004115B1 8B EC mov ebp,esp
004115B3 81 EC CC 00 00 00 sub esp,0CCh
004115B9 53 push ebx
004115BA 56 push esi
004115BB 57 push edi
004115BC 51 push ecx
004115BD 8D BD 34 FF FF FF lea edi,[ebp-0CCh]
004115C3 B9 33 00 00 00 mov ecx,33h
004115C8 B8 CC CC CC CC mov eax,0CCCCCCCCh
004115CD F3 AB rep stos dword ptr es:[edi]
004115CF 59 pop ecx
004115D0 89 4D F8 mov dword ptr [ebp-8],ecx
004115D3 8B 45 F8 mov eax,dword ptr [this]
004115D6 5F pop edi
004115D7 5E pop esi
004115D8 5B pop ebx
004115D9 8B E5 mov esp,ebp
004115DB 5D pop ebp
004115DC C3 ret
};
:
35: AB su_4()
36: {
004114F0 55 push ebp %【1】 。
004114F1 8B EC mov ebp,esp
004114F3 81 EC D4 00 00 00 sub esp,0D4h
004114F9 53 push ebx
004114FA 56 push esi
004114FB 57 push edi
004114FC 8D BD 2C FF FF FF lea edi,[ebp-0D4h]
00411502 B9 35 00 00 00 mov ecx,35h
00411507 B8 CC CC CC CC mov eax,0CCCCCCCCh
0041150C F3 AB rep stos dword ptr es:[edi]
37: AB c;
0041150E 8D 4D F0 lea ecx,[c] %【2】 , 。
00411511 E8 30 FB FF FF call AB::AB (411046h)
38: c.ia=100;
00411516 C7 45 F0 64 00 00 00 mov dword ptr [c],64h % 【3】 。
39: c.ib=150;
0041151D C7 45 F4 96 00 00 00 mov dword ptr [ebp-0Ch],96h
40: c.ic=200;
00411524 C7 45 F8 C8 00 00 00 mov dword ptr [ebp-8],0C8h
41:
42: return c;
0041152B 8B 45 08 mov eax,dword ptr [ebp+8] %【4】 。 ebp ebp,ebp+4 eip,eip+8 % 。 eax。
0041152E 8B 4D F0 mov ecx,dword ptr [c] % [c] [ebp-4]。 c 。
00411531 89 08 mov dword ptr [eax],ecx
00411533 8B 55 F4 mov edx,dword ptr [ebp-0Ch]
00411536 89 50 04 mov dword ptr [eax+4],edx
00411539 8B 4D F8 mov ecx,dword ptr [ebp-8]
0041153C 89 48 08 mov dword ptr [eax+8],ecx
0041153F 8B 45 08 mov eax,dword ptr [ebp+8]
43: }
00411542 52 push edx % 【5】 。
00411543 8B CD mov ecx,ebp
00411545 50 push eax
00411546 8D 15 68 15 41 00 lea edx,[ (411568h)]
0041154C E8 31 FB FF FF call @ILT+125(@_RTC_CheckStackVars@8) (411082h)
00411551 58 pop eax
00411552 5A pop edx
00411553 5F pop edi
00411554 5E pop esi
00411555 5B pop ebx
00411556 81 C4 D4 00 00 00 add esp,0D4h
0041155C 3B EC cmp ebp,esp
0041155E E8 DD FB FF FF call @ILT+315(__RTC_CheckEsp) (411140h)
00411563 8B E5 mov esp,ebp
00411565 5D pop ebp
00411566 C3 ret
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
以上が構造関数がある場合,structはクラスとして解釈される.コンストラクション関数がない場合は、コピーが1回増えます.
51: int main()
52: {
004115A0 55 push ebp
004115A1 8B EC mov ebp,esp
004115A3 81 EC 00 01 00 00 sub esp,100h
004115A9 53 push ebx
004115AA 56 push esi
004115AB 57 push edi
004115AC 8D BD 00 FF FF FF lea edi,[ebp-100h]
004115B2 B9 40 00 00 00 mov ecx,40h
004115B7 B8 CC CC CC CC mov eax,0CCCCCCCCh
004115BC F3 AB rep stos dword ptr es:[edi]
004115BE A1 00 70 41 00 mov eax,dword ptr [___security_cookie (417000h)]
004115C3 33 C5 xor eax,ebp
004115C5 89 45 FC mov dword ptr [ebp-4],eax
60: AB r;
61: r=su_4();
004115C8 8D 85 18 FF FF FF lea eax,[ebp-0E8h]
004115CE 50 push eax
004115CF E8 AE FA FF FF call su_4 (411082h)
004115D4 83 C4 04 add esp,4
004115D7 8B 08 mov ecx,dword ptr [eax] %
004115D9 89 8D 04 FF FF FF mov dword ptr [ebp-0FCh],ecx
004115DF 8B 50 04 mov edx,dword ptr [eax+4]
004115E2 89 95 08 FF FF FF mov dword ptr [ebp-0F8h],edx
004115E8 8B 40 08 mov eax,dword ptr [eax+8]
004115EB 89 85 0C FF FF FF mov dword ptr [ebp-0F4h],eax
004115F1 8B 8D 04 FF FF FF mov ecx,dword ptr [ebp-0FCh]
004115F7 89 4D EC mov dword ptr [ebp-14h],ecx
004115FA 8B 95 08 FF FF FF mov edx,dword ptr [ebp-0F8h]
00411600 89 55 F0 mov dword ptr [ebp-10h],edx
00411603 8B 85 0C FF FF FF mov eax,dword ptr [ebp-0F4h]
00411609 89 45 F4 mov dword ptr [ebp-0Ch],eax
62:
104:
105: getchar();
0041160C 8B F4 mov esi,esp
0041160E FF 15 B4 82 41 00 call dword ptr [__imp__getchar (4182B4h)]
00411614 3B F4 cmp esi,esp
00411616 E8 20 FB FF FF call @ILT+310(__RTC_CheckEsp) (41113Bh)
106: return 0;
0041161B 33 C0 xor eax,eax
107: }
0041161D 52 push edx
0041161E 8B CD mov ecx,ebp
00411620 50 push eax
00411621 8D 15 4C 16 41 00 lea edx,[ (41164Ch)]
00411627 E8 51 FA FF FF call @ILT+120(@_RTC_CheckStackVars@8) (41107Dh)
0041162C 58 pop eax
0041162D 5A pop edx
0041162E 5F pop edi
0041162F 5E pop esi
00411630 5B pop ebx
00411631 8B 4D FC mov ecx,dword ptr [ebp-4]
00411634 33 CD xor ecx,ebp
00411636 E8 D9 F9 FF FF call @ILT+15(@__security_check_cookie@4) (411014h)
0041163B 81 C4 00 01 00 00 add esp,100h
00411641 3B EC cmp ebp,esp
00411643 E8 F3 FA FF FF call @ILT+310(__RTC_CheckEsp) (41113Bh)
00411648 8B E5 mov esp,ebp
0041164A 5D pop ebp
0041164B C3 ret
基本的に3回のコピーがあります.サブ関数では、変数を一時的に戻り値ストレージにコピーし、呼び出し側で別の一時ストレージにコピーし、そのストレージから受け入れられた変数にコピーします.
関数呼び出しの手順を明確にします.
(1)パラメータを右から左に入力してスタックに入り、参照するとpush変数のアドレスになる.
(2)戻り値が大きいオブジェクト(64 bitより大きい)であり、直接戻りであり、戻り参照ではない場合(戻り参照であれば直接アドレスを返す)は、遠いメモリを探して、そのアドレスpushをスタックに入れ、将来的には到来時に戻り値を格納する
(3)call funcを指す.funcは関数名です.このときeipレジスタのコンテンツは自動的にスタックされます.
(4)ここから関数に入ります!Push ebp、callerのebpをスタックに入れます.
(5)mov ebp, esp.現在のスタックトップはスタックベースとして使用されます.calleeは自分のスタックスペースを持っています!
(6)sub esp,100.100は勝手に書いてあるので、別の数かもしれません.システムは一時変数の空間を割り当てます.
(7)ebx,esi,ediなどのレジスタがスタックに入る.
(8)上記申請のスペースを0 xCCで埋める.
(9)仕事をする...
(10)関数が返されます.戻り値は大きなオブジェクトです.オブジェクトをebp+8の場所の値が指す位置にコピーします.そうですね.(2)ステップ目で戻り値を一時的に格納する場所を指します.
(11)mov esp,ebp.スタックスペースをクリーンアップするのは簡単ですが、スタックの上部の位置を変更すればいいです.
(12)ret.このコマンドはスタック内のeipに対応する値をポップアップし、この関数を呼び出した後の次のコマンドが何であるかを知ることができます.
(13)add esp,XXX.入力パラメータと一時保存スペースポインタがあるので、ここでスタックバランスを作ります.
(14)先ほど述べた戻り値一時格納空間から戻り値を別の一時格納空間にコピーする.この戻り値を受け入れる変数がある場合は、新しい一時保存スペースからその変数にコピーします.変数が受け入れられない場合は、使用しません.
(15)呼び出しが終了し,何をすべきか.
注:スタックスペースは一般的にデフォルト1 Mで、再帰的に深すぎるとスタックがオーバーフローします.
ref:
http://wenku.baidu.com/view/bea115ccda38376baf1faec7.html
http://www.cnblogs.com/zplutor/archive/2011/09/25/2190315.html