<form id="hz9zz"></form>
  • <form id="hz9zz"></form>

      <nobr id="hz9zz"></nobr>

      <form id="hz9zz"></form>

    1. 明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

      Win32程序函數調用時堆棧變化情況區分

      [摘要]在經典的匯編語言教程中,函數調用時堆棧的使用都是著重講解的問題。如今隨著高級語言的越來越完善,單純使用匯編開發的程序已經不多了。但對函數調用時堆棧動向的了解仍有助于我們明晰程序的執行流程,從而在程序...
          在經典的匯編語言教程中,函數調用時堆棧的使用都是著重講解的問題。如今隨著高級語言的越來越完善,單純使用匯編開發的程序已經不多了。但對函數調用時堆棧動向的了解仍有助于我們明晰程序的執行流程,從而在程序編寫和調試的過程中有一個清晰的思路。

      一.調用約定
      在Win32中,有關函數的調用主要有兩種約定。
      1._stdcall
              以__stdcall方式調用的函數有以下特征:
          &#8226;  參數由右至左壓棧
          &#8226; 調用返回時,堆棧由被調函數調整
      2.__cdecl
      __cdecl約定是C/C++函數的默認調用約定。它有以下特征:
          &#8226; 參數由右至左壓棧
          &#8226; 調用返回時,堆棧由調用者調整

      二.Win32函數調用過程

      1.    壓入參數
      這里依據以上的調用方式將調用者給出的參數一一壓入堆棧。

      2.    壓入斷點
      當程序執行到Call指令的時候,當前語句的地址作為斷點地址壓入堆棧。

      3.    跳轉
      eip的值被重新設置為被調函數的起始地址。

      4.    mov ebp, esp
      這里ebp被用來在堆棧中尋找調用者壓入的參數,同時作為調用者堆棧指針的一個備份。在此前還應該執行一條:
      push ebp
      把ebp中原來的數值保存。

      5.    sub esp,N
      這里N是函數內局部變量的總字節數加上一個整數,一般為40。此后esp即為被調函數的堆棧指針了。

      6.    初始化esp ~ esp-N之間的N字節空間
      這是對堆棧中已分配給局部變量使用的內存空間的初始化,一般全部設置為0xcc。

      7.    順序執行函數內語句。
      此時函數的堆棧位于所有局部變量的內存空間之后,二者之間一般有40字節的隔離帶。

      8.返回
      為保障調用的正常返回,函數內應當保證規范使用堆棧,使即將返回的時候esp的值恢復為執行第一條語句前的狀態。說明白點,就是每一條push都要有相應的pop。
      調用返回的過程如下:
      mov esp, ebp
      執行后,esp恢復為調用者的堆棧指針,棧頂除斷點地址外,還存有原ebp的值和調用時壓入的參數。
      然后依次彈出ebp的值和斷點地址。如果是__cdecl約定則直接返回調用者,調用者將負責調整堆棧,丟棄調先前壓入的參數。如果是__stdcall則這個工作由被調函數來執行。

      程序樣例如下:
      ……
      0040B8E8   push        1            ;壓入參數
      0040B8EA   call        00401028        ;調用函數
      ……
      00401028   jmp         0040b7c0        ;跳轉到函數入口
      ……
      0040B7C0   push        ebp            ;保存ebp
      0040B7C1   mov         ebp,esp        
      0040B7C3   sub         esp,44h        ;設置函數的堆棧指針,此函數中有4
      ;字節的局部變量
      0040B7C6   push        ebx
      0040B7C7   push        esi        
      0040B7C8   push        edi
      0040B7C9   lea         edi,[ebp-44h]    
      0040B7CC   mov         ecx,11h
      0040B7D1   mov         eax,0CCCCCCCCh
      0040B7D6   rep stos    dword ptr [edi]    ;初始化局部變量空間
      0040B7D8   mov         eax,dword ptr [ebp+8]
      0040B7DB   mov         dword ptr [ebp-4],eax
      ……
      0040B7DE   pop         edi            ;彈出曾壓棧的數據
      0040B7DF   pop         esi
      0040B7E0   pop         ebx
      0040B7E1   mov         esp,ebp        ;恢復調用者的堆棧
      0040B7E3   pop         ebp            ;彈出原ebp值
      0040B7E4   ret         4            ;返回并將堆棧向上調整4字節。
      ;此處為__stdcall約定,所以由函數調
      ;整堆棧

      相應的C代碼如下:

      void __stdcall fun(int);

      int main(void)
      {
          ……    
      fun(1);
      ……
          return 0;
      }

      void __stdcall fun(int para)
      {
          int localpara = para;
          ……
      }


      日韩精品一区二区三区高清