int goo(int a, int b){return a + b;}void foo(){int a[] = {1, 2, 3};int result = goo(a[1], a[2]);printf("result: %d", result);}
VS2010下編譯
foo函數部分彙編:
00EB3890 push ebp 00EB3891 mov ebp,esp 00EB3893 sub esp,0E4h 00EB3899 push ebx 00EB389A push esi 00EB389B push edi 00EB389C lea edi,[ebp-0E4h] 00EB38A2 mov ecx,39h 00EB38A7 mov eax,0CCCCCCCCh 00EB38AC rep stos dword ptr es:[edi] 00EB38AE mov eax,dword ptr [___security_cookie (0EB7000h)] 00EB38B3 xor eax,ebp 00EB38B5 mov dword ptr [ebp-4],eax int a[] = {1, 2, 3};00EB38B8 mov dword ptr [ebp-14h],1 00EB38BF mov dword ptr [ebp-10h],2 00EB38C6 mov dword ptr [ebp-0Ch],3 int result = goo(a[1], a[2]);00EB38CD mov eax,dword ptr [ebp-0Ch] 00EB38D0 push eax 00EB38D1 mov ecx,dword ptr [ebp-10h] 00EB38D4 push ecx 00EB38D5 call goo (0EB11E5h) 00EB38DA add esp,8
goo函數完整彙編:
00EB1580 push ebp 00EB1581 mov ebp,esp 00EB1583 sub esp,0C0h 00EB1589 push ebx 00EB158A push esi 00EB158B push edi 00EB158C lea edi,[ebp-0C0h] 00EB1592 mov ecx,30h 00EB1597 mov eax,0CCCCCCCCh 00EB159C rep stos dword ptr es:[edi] return a + b;00EB159E mov eax,dword ptr [a] 00EB15A1 add eax,dword ptr [b] }00EB15A4 pop edi 00EB15A5 pop esi 00EB15A6 pop ebx 00EB15A7 mov esp,ebp 00EB15A9 pop ebp 00EB15AA ret
foo函數push ebp, mov ebp, esp後
儲存原ebp,設定新的ebp為當前esp位置
sub esp, 0E4h
給局部變數分配足夠大的棧空間
儲存原先的一些寄存器值,每次push,esp繼續向下移
為局部變數a數組賦值
調用goo前Push兩個參數,esp繼續下移
call goo函數時,cpu自動push下一條指令地址,esp繼續下移
在goo函數中,同樣儲存foo函數中的ebp值,設定新的ebp,esp等
在執行玩goo函數最後幾句指令時,edi, esi, ebx恢複,esp同時也編程goo中ebp的位置,ebp恢複至foo函數原來的位置(pop ebp)
下一條指令也裝入IP(ret指令),esp繼續向上一步
foo函數中的add esp, 8將esp值繼續往上(清除函數參數)
清除函數參數的工作也可通過ret X在goo函數返回時設定(這樣的話不必在每次調用點上加上add esp, X指令縮短了編譯出來的檔案大小,但在子函數中清除將不能做到printf等的可變參數個數功能,因為子函數不知道具體有多少要參數進入了,只有調用處才知道)