タイトル/名前 | 更新者 | 更新日 |
---|---|---|
C言語系/呼び出し規約/x86/thiscall | msakamoto-sf | 2010-03-27 13:00:27 |
C言語系/呼び出し規約/x86/naked | msakamoto-sf | 2010-03-25 10:36:23 |
C言語系/呼び出し規約/x86/"WINAPI"他 | msakamoto-sf | 2010-03-19 20:32:19 |
C言語系/呼び出し規約/x86/"PASCAL" | msakamoto-sf | 2010-03-19 20:13:04 |
C言語系/呼び出し規約/x86/watcall | msakamoto-sf | 2010-03-19 18:06:27 |
C言語系/呼び出し規約/x86/stdcall | msakamoto-sf | 2010-03-19 17:43:15 |
C言語系/呼び出し規約/x86/cdecl | msakamoto-sf | 2010-03-19 17:30:32 |
C言語系/呼び出し規約/x86/pascal | msakamoto-sf | 2010-03-19 17:17:18 |
C言語系/呼び出し規約/x86/register | msakamoto-sf | 2010-03-19 17:07:24 |
C言語系/呼び出し規約/x86/fastcall | msakamoto-sf | 2010-03-19 17:07:07 |
thiscall呼び出し規約:
"__declspec(naked)"を関数に指定すると、コンパイラはその関数のprolog, epilogを省略する。これがNaked FunctionあるいはNaked Function Callと呼ばれる呼び出し規約である。
"naked"属性は関数の「型」とは異なり、関数本体にのみ作用する。関数プロトタイプや変数に"__declspec(naked)"を指定するとコンパイルエラーになる。"naked"属性はx86アーキテクチャでのみ有効で、x86_64(x64)やItaniumアーキテクチャでは無効。
"naked"属性を指定しない場合の典型的なprolog/epilogとは以下のような機械語のことである。
prolog:
push ebp ; Save ebp mov ebp, esp ; Set stack frame pointer sub esp, localbytes ; Allocate space for locals push <registers> ; Save registers
EBPをスタックに保存した後、ESPに合わせる(スタックフレームの生成)。ローカル変数用の領域をESPをずらすことで確保し、必要であればレジスタをスタックに保存する。これが、コンパイラが自動的に生成して関数本体の前に追加するprologコードになる。
epilog:
pop <registers> ; Restore registers mov esp, ebp ; Restore stack pointer pop ebp ; Restore ebp ret ; Return from function
必要であればレジスタをスタックから復元し、ESPとEBPを復元し(スタックフレームの破棄)、RET命令を呼ぶ。これが、コンパイラが自動的に生成して関数本体の後ろに追加するepilogコードになる。
"naked"属性を指定された関数では、これらprolog/epilogコードが追加されない。代わりに、インラインアセンブラ(inline assembler)を用いてprolog/epilog相当のコードを手動で実装する。仮想デバイスドライバや割り込みハンドラなど、CPUに近い処理を実装する場合に活用できる。
"naked"属性の関数内ではスタックフレームの生成が開発者に委ねられるため、コンパイラの生成するスタックフレームに依存する機能が使えなくなる。
参考MSDN:(Visual C++ のリファレンス以下)
"WINAPI", "CALLBACK", "APIENTRY"はヘッダーファイルで定義された呼び出し規約で、実際にどの呼び出し規約("__stdcall", "__cdecl", "__pascal", ...)になるかは OS/コンパイラによって異なってくるので、使用する場合は注意が必要。
ただし、2010年現在の Win32 APIプラットフォームにおいては基本的にどれも "__stdcall" と考えて良い。
VC++2008, Borland C++ Compiler, OpenWatcom(32bit), MinGW-gcc 共に、この3つは"__stdcall"にdefineされている。
"PASCAL"はヘッダーファイルで定義された呼び出し規約で、"__pascal"呼び出し規約のことではない。
実際にどの呼び出し規約("__stdcall", "__cdecl", "__pascal", ...)になるかは、OS/コンパイラによって異なってくるので、使用する場合は注意が必要。
ただし、2010年現在の Win32 APIプラットフォームにおいては基本的に PASCAL == "__stdcall" と考えて良い。
VC++2008, Borland C++ Compiler, OpenWatcom(32bit), MinGW-gcc 共に、PASCALは"__stdcall"にdefineされている。
OpenWatcom で特に呼び出し規約を指定しない場合のデフォルトの呼び出し規約。
OpenWatcomでは、main()関数は強制的に __watcall 呼び出し規約になる(他の呼び出し規約を指定しても、無視される)。(ただし実験した結果であって、マニュアル・ドキュメント上でこの点について記載されているかは未確認)
__stdcall呼び出し規約:
__cdecl呼び出し規約:
example: PUSH arg3 ; 4byte PUSH arg2 ; 2byte PUSH arg1 ; 1byte CALL _foobar ADD ESP, 7 ; スタックポインタを7バイト戻す(全て表示する)
__pascal呼び出し規約:
Borlandのfastcallの別名。Delphiではこちらの名前を使っている。
なおあくまでも "Delphi用の" 名前で、Borland C++ Compiler(Borland C++ 5.5.1)の方では対応していない。Borland C++ Compilerでは代わりに "__fastcall" を指定する。
__fastcall呼び出し規約: