參數傳遞方法(用Delphi的彙編代碼解釋)

李緯的InsideVCL《第一章》中提到Windows定義的回調函數程序員

typedef LRESULT (CALLBACK*WNDPROC)(HWND,UNIT,WPARAM,LPARAM)ide

爲了加快回調函數執行的效率,Microsoft使用了CALLBACK修飾關鍵詞來定義WNDPROC,而CALLBACK則是定義成FAR PASCAL.函數

那麼爲何FARPASCAL就會更快執行呢?如下爲個人解釋測試

(1)cdecl:

     一般是C/C++所使用缺省的參數傳遞方式,它的傳遞方式是由右到左,並且當被調用的函數結束以後,將會由調用函數自己來清除堆棧上的參數數據。每個調用它的函數都包含清空堆棧的代碼,因此產生的可執行文件大小會比調用_stdcall函數的大。this

(2)stdcall:

     參數傳遞方式,也是由右到左,可是當被調用的函數結束以後,則是由被調用函數來清除堆棧上的參數數據,Win32API全部的輸出函數都是採用此中參數傳遞方式指針

(3)pascal:

     是Delphi1.0與win16API所使用的參數傳遞方式,它的傳遞方式是由左到右,並且由被調用函數來清除堆棧上的參數數據.code

(4)fastcall:(delphi下關鍵字爲register)

     是Delphi默認所使用的參數傳遞方式, 主要特色就是快,由於它是經過寄存器來傳送參數的(實際上,它用ECX和EDX傳送前兩個雙字(DWORD)或更小的參數,剩下的參數仍舊自右向左壓棧傳送,被調用的函數在返回前清理傳送參數的內存棧)orm

   注:因此在引用C++動態庫中的函數時,要注意參數的傳遞方式,通常使用stdcall.還要注意字符串類型,C++在傳遞字符串時,都是採用字符指針的類型(Char *),因此你在Delphi的程序中就必須使用PCHAR類型,而不是string類型.內存

(5)thiscall

僅僅應用於「C++」成員函數。this指針存放於CX/ECX寄存器中,參數從右到左壓。thiscall不是關鍵詞,所以不能被程序員指定。字符串

(6)naked call。

當採用1-4的調用約定時,若是必要的話,進入函數時編譯器會產生代碼來保存ESI,EDI,EBX,EBP寄存器,退出函數時則產生代碼恢復這些寄存器的內容。(這些代碼稱做 prologand epilog code,通常,ebp,esp的保存是必須的).可是naked call不產生這樣的代碼。naked call不是類型修飾符,故必須和_declspec共同使用。

 

彙編測試

其實。你只要寫一段下去測試。看它的 asm 就知道了。

1.觸發代碼

TForm1.Test1Click(1,2, 3);

  begin

0044E298 6A03              push$03

0044E29A 6A02              push$02

0044E29C 6A01              push$01

0044E29E 50                 pusheax

0044E29F E8D4FFFFFF       call TForm1.Test1

end

0044E2A4 C3               ret

0044E2A5 8D4000           lea eax,[eax+$00]

 

TForm1.Test2Click(1,2, 3);

  begin

  0044E287 6A03            push $03

  0044E289 B902000000       mov ecx,$00000002

  0044E28E BA01000000      mov edx,$00000001

  0044E293 8BC3             mov eax,ebx

  0044E295 E8CEFFFFFF      call TForm1.Test2

end

0044E2B9 C3               ret

0044E2BA 8BC0            mov eax,eax

2.函數源碼 

FunctionTForm1.Test1(a, b, c: Integer): Integer; stdcall;

Begin

0044E268 55               push ebp

0044E269 8BEC            mov ebp,esp

Result := a + b + c;

0044E25B 8B450C          mov eax,[ebp+$0c]

0044E25E 034510           add eax,[ebp+$10]

0044E261 034514           add eax,[ebp+$14]

end

0044E264 5D               pop ebp

0044E265 C21000           ret $0010

 

FunctionTForm1.Test2(a, b, c: Integer): Integer; register;

Begin

0044E268 55               push ebp

0044E269 8BEC             mov ebp,esp

Result := a + b + c;

0044E26B 8D0411           lea eax,[ecx+edx]

0044E26E 034508           add eax,[ebp+$08]

end

0044E271 5D               pop ebp

0044E272 C20400           ret $0004

0044E275 8D4000           lea eax,[eax+$00]

 

這樣看起來。是否是就有所差別了?

相關文章
相關標籤/搜索