flat7th

+ 呼び出し規約

created 2005-12-22 modified 2005-12-22 

無料で入手できるWindowsのデバッガがある。これのドキュメントが結構よい。
前の現場で調べ物をしていたとき、x86アーキテクチャでの関数呼び出しの規約が書いてあるのを見つけて読んだ。とても勉強になった。

ちょっと引用。場所は

Debugging Tools for Windows
 |__Debugging Techniques
     |__Processor Architecture
         |__The x86 Architecture
のCalling Conventions。

Calling Conventions


The x86 architecture has several different calling conventions. Fortunately, they all follow the same register preservation and function return rules:

  • Functions must preserve all registers, except for eax, ecx, and edx, which can be changed across a function call, and esp, which must be updated according to the calling convention.
  • The eax register receives function return values if the result is 32 bits or smaller. If the result is 64 bits, then the result is stored in the edx:eax pair.

The following is a list of calling conventions used on the x86 architecture:

  • Win32 (__stdcall)
    • Function parameters are passed on the stack, pushed right to left, and the callee cleans the stack.
  • Native C++ method call (also known as thiscall)
    • Function parameters are passed on the stack, pushed right to left, the "this" pointer is passed in the ecx register, and the callee cleans the stack.
  • COM (__stdcall for C++ method calls)
    • Function parameters are passed on the stack, pushed right to left, then the "this" pointer is pushed on the stack, and then the function is called. The callee cleans the stack.
  • __fastcall
    • The first two DWORD-or-smaller arguments are passed in the ecx and edx registers. The remaining parameters are passed on the stack, pushed right to left. The callee cleans the stack.
  • __cdecl
    • Function parameters are passed on the stack, pushed right to left, and the caller cleans the stack. The __cdecl calling convention is used for all functions with variable-length parameters.

えーとつまり、

読むまでは呼び出し側と呼ばれる側でどっちがスタックから降ろすなんて意識していなかった。

普通の関数では、呼び側がパラメータを積んで、呼び出された側がreturnするときにスタックから降ろす(__stdcall)。スタックから降ろす操作は共通だもんね。
でも、可変引数の関数では、いくつ積むかは呼び側次第なので、共通処理でスタックから降ろすのはムリ。呼び側がスタックから降ろす(__cdecl)。
わかれば当たり前なんですけどね。

お客様から提供されたcoreファイルを解析するときには、こういう知識も必要になるとです。