使うのが最難関に近い呼び出し規約の__fastcallであった
C言語にはアセンブリコードに落とす際に、サブルーチンどうしでどうやって引数を受け渡してもらうかというのがあって、これを呼び出し規約と呼ぶ。一番使っていて簡単なのは__cdeclである。引数は一番目がesp+4で二番目がesp+8と連続していてとても扱いやすい。スタックをpushするたびにesp-=4されるのでespの値が変化することを考慮しなくてはならない。
その一方でどうやって使っていいかわからないものがある。それが__fastcallである。高速化に向かってまっしぐらな身としてはこんなネーミングはすごいと思う。なにせ速い呼び出しそのままなのですから。
で、いくつかの少ない情報を回った後、自分でアセンブリコードをアセンブラにかけてみて、C言語からどうやって使えばいいのかわかったのでここに書いておく。
- fastcall.asm
;; /* __fastcall呼び出しアセンブラ使用 */ ;; /* 2005/May/13 */ ;; アセンブルのしかた ;; $ nasmw -f win32 fastcall.asm ;; extern "C" int __fastcall foo( int a, int b, int c ); [bits 32] [section .text] global @foo@12 ; @function name@decimal num bytes in parameters ;; __fastcall でも返り値はeaxに返すらしい @foo@12: mov eax, 0 push ebp mov ebp,esp ; a = ecx ; b = edx ; c = [ebp+8] ; eax = return value add eax, ecx add eax, edx add eax, [ebp+8] mov esp,ebp pop ebp ret 4 ; callee cleans up stack
- fastcall.c
/* __fastcall呼び出しアセンブラ使用 */ /* 2005/May/13 */ /* コンパイルのしかた $ gcc fastcall.obj fastcall.c */ /* extern するかしないかわからないけどとりあえず宣言 */ int __fastcall foo(int i, int j, int k); int main(void) { puts("__fastcall 使用例"); printf("foo(12, 34, 56) = %d\n", foo(12, 34, 56)); return 0; }