push、pop及函式呼叫約定
阿新 • • 發佈:2019-02-17
push:
把一個32位的運算元壓入堆疊中。這個操作導致esp被減4。esp被形象地稱為棧頂。我們認為頂部是地址小的區域,那麼,壓入堆疊中資料越多,這個堆疊也就越堆越高,esp也就越來越小。在32位平臺,esp每次減少4位元組。
pop:
相反,esp被加4,一個數據出棧。pop的引數一般是一個暫存器,棧頂的資料被彈出到這個暫存器中。
call 的本質相當於push+jmp ;ret 的本質相當於pop+jmp;
函式呼叫約定:
1)_cdecl C 呼叫 規則
引數從右到左進入堆疊
在函式返回後,呼叫 者要負責清除堆疊,所以這種呼叫常會生成較大的可執行程式。
2)_stdcall又稱為WINAPI,其呼叫 規則
引數從右到左進入堆疊
被呼叫的函式在返回前自行清理堆疊,所以生成的程式碼比cdecl小
3)pascal呼叫規則主要用在win16函式庫中,現在基本不用
引數從左到右進入堆疊
被呼叫的函式在返回前自行清理堆疊
不支援可變引數的函式呼叫 。
在Windows中,不管哪種呼叫 方式都是返回值放在eax中,然後返回。外部從eax中得到返回值。
#include "stdafx.h"
int main()
{
01371650 push ebp
01371651 mov ebp,esp
01371653 sub esp,0C0h
01371659 push ebx
0137165A push esi
0137165B push edi
0137165C lea edi,[ebp-0C0h]
01371662 mov ecx,30h
01371667 mov eax,0CCCCCCCCh
0137166C rep stos dword ptr es:[edi]
return 0;
0137166E xor eax,eax
}
void myfunction(int a, int b)
{
00CA1650 push ebp ;保護ebp,並把esp放入esp中。此時esp=ebp
00CA1651 mov ebp,esp ;
00CA1653 sub esp,0CCh ;把esp往上移動一個範圍,等於在堆疊中放出一片新的空間用來儲存區域性變數
00CA1659 push ebx ;儲存三個暫存器
00CA165A push esi
00CA165B push edi
00CA165C lea edi,[ebp-0CCh] ;lea把內容的地址,也就是ebp-0cch載入到edi中。目的是把儲存區域性變數的區域從ebp-0cch開始的區域,初始化成0cccccccch
00CA1662 mov ecx,33h
00CA1667 mov eax,0CCCCCCCCh ;
00CA166C rep stos dword ptr es:[edi] ;寫入0cch指令
int c = a + b;
00CA166E mov eax,dword ptr [a]
00CA1671 add eax,dword ptr [b]
00CA1674 mov dword ptr [c],eax
}
00CA1677 pop edi ;恢復edi、esi、ebx
00CA1678 pop esi
00CA1679 pop ebx
00CA167A mov esp,ebp ;恢復原來的ebp和esp,讓上一個呼叫的函式正常使用
00CA167C pop ebp
00CA167D ret