呼出規約と引数の格納されるレジスタについて

覚書き。
Delphiインラインアセンブラを使うときの呼出規約と引数のレジスタへの格納について。
試したのはDelphi2009。
デフォルトがfastcallなのは知ってたけど、それ以外をよく知らなかったので調べてた。

calling_convention.dpr

program calling_convention;

{$APPTYPE CONSOLE}

(*
fastcall(register)
Delphiの場合は最初の3つの引数はEAX, EDX, ECXレジスタに格納される
戻り値はEAX
*)
function Sub1(a, b: Integer): Integer;
asm
  SUB EAX, EDX
end;

(*
cdecl
スタックに引数は右から順に格納される
戻り値はEAX
*)
function Sub2(a, b: Integer): Integer; cdecl;
asm
  PUSH EBP
  MOV EBP, ESP
  MOV EAX, DWORD PTR [EBP + 12]
  SUB EAX, DWORD PTR [EBP + 16]
  POP EBP
end;

(*
stdcall
呼び出し側がスタックに引数を格納する
戻り値はEAX
*)
function Sub3(a, b: Integer): Integer; stdcall;
asm
  MOV EAX, DWORD PTR [EBP + 8]
  SUB EAX, DWORD PTR [EBP + 12]
end;

(*
7 - 3の計算
*)
begin
  WriteLn(Sub1(7, 3));
  WriteLn(Sub2(7, 3));
  WriteLn(Sub3(7, 3));
end.

実行結果

C:\work\_sandbox\calling_convention>dcc32 calling_convention.dpr
CodeGear Delphi for Win32 コンパイラ version 20.0
Copyright (c) 1983,2008 CodeGear
calling_convention.dpr(39)
40 行, 0.03 秒, コード 13216 バイト, データ 13036 バイト
C:\work\_sandbox\calling_convention>calling_convention
4
4
4