1. 程式人生 > >push、pop及函式呼叫約定

push、pop及函式呼叫約定

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