MSVC、clang-cl、MinGW-w64 でビルドされた Windows 向けの 32 ビットプログラムは、データとレジスターについて 1 組の規則を共有していますが、関数は 5 つの呼び出し規約のどれかで宣言できます。C と C++ のデフォルトである __cdecl、Windows API の規約である __stdcall、__fastcall、C++ のメンバー関数のデフォルトである __thiscall、そして __vectorcall です。これらは Microsoft の規約ですが、MinGW-w64 GCC と Clang も実装しています。Linux の 32 ビット ABI である System V i386 は __cdecl に相当しますが、構造体の返し方とスタックのアラインメントが異なります。64 ビット Windows の規約は Microsoft x64 の 1 つだけです。

このページのリストは、MSVC の ABI に従う i686-pc-windows-msvc 向けの Clang と MinGW-w64 GCC を、どちらも -O2 で使ったものです。MSVC はデフォルトで SSE2 のコードを生成するので、どちらも Pentium 4 向け (-march=pentium4) にコンパイルしています。この指定がなければ MinGW-w64 GCC は Pentium Pro をターゲットにします。また Pentium 4 向けでも、別に指定しない限り x87 ユニットで計算します。各リストの横のボタンで AT&T 構文と Intel 構文を切り替えられます。

すべての規約に共通すること

  • EAX、ECX、EDX はスクラッチ (scratch) で、EBX、ESI、EDI、EBP は System V と同じく呼び出し先保存です。
  • 結果は EAX で、64 ビットの値は EDX:EAX で、float と double は x87 スタックの ST0 で返ります。Linux と異なり、1、2、4 または 8 バイトの構造体も EAX または EDX:EAX で返ります。
  • レジスターに入らない引数は、それぞれ 4 バイトの倍数に広げられ、右から左へプッシュされます。
  • スタックは 4 バイトにしかアラインされません。

5 つの規約

32 ビット Windows の呼び出し規約。装飾名は C の関数 f(int, int) のもので、数値は引数のバイト単位のサイズです。
規約レジスター引数スタック引数を取り除く側装飾名採用先
__cdeclなし呼び出し元_fデフォルトの C と C++ の関数、すべての可変長引数関数
__stdcallなし呼び出された関数_f@8Windows API (WINAPI、CALLBACK)
__fastcall4 バイト以下の最初の 2 つの整数を ECX と EDX で呼び出された関数@f@8これを指定したコード
__thiscallECX で this呼び出された関数なし (C++ のみ)デフォルトの C++ メンバー関数
__vectorcall整数は __fastcall と同じ。浮動小数点値とベクトル値は XMM0 から XMM5呼び出された関数f@@8ベクトルコード

最も重要な違いは、誰が引数を取り除くかです。__cdecl では呼び出し元が呼び出しの後で ESP に加算します。ほかの規約では、関数は ret n で戻り、戻りアドレスとともに n バイトの引数をポップします。誤った規約で呼び出された関数は ESP を引数のサイズ分ずらしたままにし、呼び出し元は後でクラッシュします。装飾名のおかげで、この誤りは代わりにリンクエラーになります。_f@8 は _f とはリンクされません。

可変長引数関数は自分が知らない引数を取り除くことができないので、宣言が何であっても常に __cdecl です。

3 つの規約での 1 つの関数。__cdecl 版は単純な ret で戻り、__stdcall 版は 12 バイトの引数を ret $12 で取り除き、__fastcall 版は a と b を ECX と EDX で受け取って c だけを取り除きます。call_both では、Clang は __cdecl の呼び出しの後では ESP に 12 を加えますが、__stdcall の呼び出しの後では加えません。一度だけ確保した領域に引数を格納する MinGW-w64 GCC は、呼び出し先のポップを subl $12 で埋め合わせます。

win32-conventions.c

/* The same function in three 32-bit Windows conventions: who removes
   the arguments, which go in registers, and how the name is decorated. */
int __cdecl add_cdecl(int a, int b, int c)
{
	return a + b + c;
}

int __stdcall add_stdcall(int a, int b, int c)
{
	return a + b + c;
}

int __fastcall add_fastcall(int a, int b, int c)
{
	return a + b + c;
}

extern int __cdecl ext_cdecl(int, int, int);
extern int __stdcall ext_stdcall(int, int, int);

int call_both(void)
{
	return ext_cdecl(1, 2, 3) + ext_stdcall(4, 5, 6);
}

Clang 23.1.2 i686-pc-windows-msvc

AT&T 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S win32-conventions.c

_add_cdecl:
        movl    8(%esp), %eax
        addl    4(%esp), %eax
        addl    12(%esp), %eax
        retl

_add_stdcall@12:
        movl    8(%esp), %eax
        addl    4(%esp), %eax
        addl    12(%esp), %eax
        retl    $12

@add_fastcall@12:
        leal    (%ecx,%edx), %eax
        addl    4(%esp), %eax
        retl    $4

_call_both:
        pushl   %esi
        pushl   $3
        pushl   $2
        pushl   $1
        calll   _ext_cdecl
        addl    $12, %esp
        movl    %eax, %esi
        pushl   $6
        pushl   $5
        pushl   $4
        calll   _ext_stdcall@12
        addl    %esi, %eax
        popl    %esi
        retl

Intel 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S win32-conventions.c

_add_cdecl:
        mov     eax, dword ptr [esp + 8]
        add     eax, dword ptr [esp + 4]
        add     eax, dword ptr [esp + 12]
        ret

_add_stdcall@12:
        mov     eax, dword ptr [esp + 8]
        add     eax, dword ptr [esp + 4]
        add     eax, dword ptr [esp + 12]
        ret     12

@add_fastcall@12:
        lea     eax, [ecx + edx]
        add     eax, dword ptr [esp + 4]
        ret     4

_call_both:
        push    esi
        push    3
        push    2
        push    1
        call    _ext_cdecl
        add     esp, 12
        mov     esi, eax
        push    6
        push    5
        push    4
        call    _ext_stdcall@12
        add     eax, esi
        pop     esi
        ret

MinGW-w64 GCC 14.2.0 (Debian 14.2.0-19+27+b1) i686-w64-mingw32

AT&T 構文 i686-w64-mingw32-gcc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S win32-conventions.c

_add_cdecl:
        movl    8(%esp), %eax
        addl    4(%esp), %eax
        addl    12(%esp), %eax
        ret

_add_stdcall@12:
        movl    8(%esp), %eax
        addl    4(%esp), %eax
        addl    12(%esp), %eax
        ret     $12

@add_fastcall@12:
        leal    (%ecx,%edx), %eax
        addl    4(%esp), %eax
        ret     $4

_call_both:
        pushl   %ebx
        subl    $24, %esp
        movl    $3, 8(%esp)
        movl    $2, 4(%esp)
        movl    $1, (%esp)
        call    _ext_cdecl
        movl    $6, 8(%esp)
        movl    $5, 4(%esp)
        movl    %eax, %ebx
        movl    $4, (%esp)
        call    _ext_stdcall@12
        subl    $12, %esp
        addl    %ebx, %eax
        addl    $24, %esp
        popl    %ebx
        ret

Intel 構文 i686-w64-mingw32-gcc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S win32-conventions.c

_add_cdecl:
        mov     eax, DWORD PTR [esp+8]
        add     eax, DWORD PTR [esp+4]
        add     eax, DWORD PTR [esp+12]
        ret

_add_stdcall@12:
        mov     eax, DWORD PTR [esp+8]
        add     eax, DWORD PTR [esp+4]
        add     eax, DWORD PTR [esp+12]
        ret     12

@add_fastcall@12:
        lea     eax, [ecx+edx]
        add     eax, DWORD PTR [esp+4]
        ret     4

_call_both:
        push    ebx
        sub     esp, 24
        mov     DWORD PTR [esp+8], 3
        mov     DWORD PTR [esp+4], 2
        mov     DWORD PTR [esp], 1
        call    _ext_cdecl
        mov     DWORD PTR [esp+8], 6
        mov     DWORD PTR [esp+4], 5
        mov     ebx, eax
        mov     DWORD PTR [esp], 4
        call    _ext_stdcall@12
        sub     esp, 12
        add     eax, ebx
        add     esp, 24
        pop     ebx
        ret

Windows API は、自身の関数を __stdcall の別名である WINAPI で宣言し、ウィンドウプロシージャのように Windows が呼び出すコールバックを CALLBACK で宣言します。これも __stdcall です。デフォルトの __cdecl で宣言されたコールバックは、Windows が期待する関数ポインター型と一致しません。キャストで無理に渡すと、実行時に失敗します。

thiscall

C++ のメンバー関数は、可変長引数でない限り __thiscall を使います。this は ECX で、ほかの引数はスタックで渡され、メンバー関数がそれらを取り除きます。Clang の MinGW-w64 ターゲットもメンバー関数に同じ規約を使いますが、名前は MSVC の方式ではなく、GCC の Itanium 方式で修飾します。

引数が 1 つのメンバー関数。this は ECX に、k は 4(%esp) にあり、ret $4 で取り除かれます。drop_two は呼び出しの前にオブジェクトのアドレスを ECX に読み込みます。MSVC 向けと MinGW-w64 向けの Clang の違いは、修飾された名前だけです。

win32-thiscall.cpp

// A C++ member function: this in ECX, the other arguments on the
// stack, removed by the member function itself.
struct Counter {
	int n;
	int add(int k);
	int sub(int k);
};

int Counter::add(int k)
{
	return n += k;
}

int drop_two(Counter *c)
{
	return c->sub(2);
}

Clang 23.1.2 i686-pc-windows-msvc

AT&T 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S win32-thiscall.cpp

"?add@Counter@@QAEHH@Z":
        movl    (%ecx), %eax
        addl    4(%esp), %eax
        movl    %eax, (%ecx)
        retl    $4

"?drop_two@@YAHPAUCounter@@@Z":
        movl    4(%esp), %ecx
        pushl   $2
        calll   "?sub@Counter@@QAEHH@Z"
        retl

Intel 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S win32-thiscall.cpp

"?add@Counter@@QAEHH@Z":
        mov     eax, dword ptr [ecx]
        add     eax, dword ptr [esp + 4]
        mov     dword ptr [ecx], eax
        ret     4

"?drop_two@@YAHPAUCounter@@@Z":
        mov     ecx, dword ptr [esp + 4]
        push    2
        call    "?sub@Counter@@QAEHH@Z"
        ret

Clang 23.1.2 i686-w64-windows-gnu

AT&T 構文 clang --target=i686-w64-windows-gnu -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S win32-thiscall.cpp

__ZN7Counter3addEi:
        movl    (%ecx), %eax
        addl    4(%esp), %eax
        movl    %eax, (%ecx)
        retl    $4

__Z8drop_twoP7Counter:
        movl    4(%esp), %ecx
        pushl   $2
        calll   __ZN7Counter3subEi
        retl

Intel 構文 clang --target=i686-w64-windows-gnu -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S win32-thiscall.cpp

__ZN7Counter3addEi:
        mov     eax, dword ptr [ecx]
        add     eax, dword ptr [esp + 4]
        mov     dword ptr [ecx], eax
        ret     4

__Z8drop_twoP7Counter:
        mov     ecx, dword ptr [esp + 4]
        push    2
        call    __ZN7Counter3subEi
        ret

vectorcall

__vectorcall は、最初の 2 つの整数引数を __fastcall と同じく ECX と EDX で渡し、最初の 6 つの浮動小数点引数またはベクトル引数を、ベクトル引数の中での位置に従って XMM0 から XMM5 で渡します。関数は自分のスタック引数を取り除き、その名前には @@ と引数のサイズが付きます。double の値は ST0 ではなく XMM0 で返ります。

x と y は XMM0 と XMM1 で、n は ECX で渡され、結果は XMM0 で返ります。名前は scale@@20 です。2 つの double 値と 1 つの int の分です。

win32-vectorcall.c

/* __vectorcall: integers in ECX and EDX as with __fastcall, and
   floating-point and vector values in XMM0 to XMM5. */
double __vectorcall scale(double x, int n, double y)
{
	return x * n + y;
}

Clang 23.1.2 i686-pc-windows-msvc

AT&T 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S win32-vectorcall.c

scale@@20:
        cvtsi2sd        %ecx, %xmm2
        mulsd   %xmm2, %xmm0
        addsd   %xmm1, %xmm0
        retl

Intel 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S win32-vectorcall.c

scale@@20:
        cvtsi2sd        xmm2, ecx
        mulsd   xmm0, xmm2
        addsd   xmm0, xmm1
        ret

構造体の返し方

MSVC は、BSD 系と同じく 1、2、4 または 8 バイトの構造体を EAX または EDX:EAX で返し、それより大きい構造体はメモリを通して返します。呼び出し元はアドレスを最初の隠し引数としてスタックで渡し、関数はそれを EAX で返します。Linux と異なり、__cdecl 関数はその隠し引数の除去を呼び出し元に任せます。

make_pair は 8 バイトの構造体を EDX:EAX で返します。make_triple は 4(%esp) のポインターを通して 12 バイトを書き込み、単純な ret で戻ります。

win32-struct-return.c

/* MSVC returns a struct of 8 bytes in EDX:EAX; a larger one through a
   hidden pointer, which the caller removes afterwards. */
struct pair { int a, b; };
struct triple { int a, b, c; };

struct pair make_pair(int a, int b)
{
	struct pair p = { a, b };
	return p;
}

struct triple make_triple(int x)
{
	struct triple t = { x, x, x };
	return t;
}

Clang 23.1.2 i686-pc-windows-msvc

AT&T 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S win32-struct-return.c

_make_pair:
        movl    4(%esp), %eax
        movl    8(%esp), %edx
        retl

_make_triple:
        movl    4(%esp), %eax
        movl    8(%esp), %ecx
        movl    %ecx, (%eax)
        movl    %ecx, 4(%eax)
        movl    %ecx, 8(%eax)
        retl

Intel 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S win32-struct-return.c

_make_pair:
        mov     eax, dword ptr [esp + 4]
        mov     edx, dword ptr [esp + 8]
        ret

_make_triple:
        mov     eax, dword ptr [esp + 4]
        mov     ecx, dword ptr [esp + 8]
        mov     dword ptr [eax], ecx
        mov     dword ptr [eax + 4], ecx
        mov     dword ptr [eax + 8], ecx
        ret

MinGW-w64 GCC 14.2.0 (Debian 14.2.0-19+27+b1) i686-w64-mingw32

AT&T 構文 i686-w64-mingw32-gcc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S win32-struct-return.c

_make_pair:
        movl    4(%esp), %eax
        movl    8(%esp), %edx
        ret

_make_triple:
        movd    8(%esp), %xmm0
        movl    4(%esp), %eax
        movdqu  %xmm0, %xmm1
        movd    %xmm0, 8(%eax)
        punpckldq       %xmm0, %xmm1
        movq    %xmm1, (%eax)
        ret

Intel 構文 i686-w64-mingw32-gcc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S win32-struct-return.c

_make_pair:
        mov     eax, DWORD PTR [esp+4]
        mov     edx, DWORD PTR [esp+8]
        ret

_make_triple:
        movd    xmm0, DWORD PTR [esp+8]
        mov     eax, DWORD PTR [esp+4]
        movdqu  xmm1, xmm0
        movd    DWORD PTR [eax+8], xmm0
        punpckldq       xmm1, xmm0
        movq    QWORD PTR [eax], xmm1
        ret

スタック

32 ビット Windows のコンパイラーは、元の i386 ABI と同じく、関数に入った時点で 4 バイトのアラインメントしか仮定しません。Linux は 16 バイトに移行しています。SSE のためにアラインされたローカル配列のように、自分のデータにより大きなアラインメントを必要とする関数は、フレームを自分でアラインします。EBP を保存し、ESP を切り下げ、引数には EBP を通してアクセスします。

16 バイトにアラインされたローカル配列。Windows のどちらのコンパイラーも andl $-16 で ESP を切り下げ、引数 x を 8(%ebp) から読みます。関数に入った時点で 16 バイトのアラインメントを当てにできる Linux 向けの GCC は、適切な量を引くだけで、配列を 12(%esp) に置きます。

win32-align.c

/* The stack is only 4-byte aligned on 32-bit Windows: a function that
   needs more for its own data aligns ESP itself. */
extern void use(double *d);

void aligned_local(double x)
{
	double d[2] __attribute__((aligned(16))) = { x, x };
	use(d);
}

Clang 23.1.2 i686-pc-windows-msvc

AT&T 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S win32-align.c

_aligned_local:
        pushl   %ebp
        movl    %esp, %ebp
        andl    $-16, %esp
        subl    $32, %esp
        movsd   8(%ebp), %xmm0
        movsd   %xmm0, (%esp)
        movsd   %xmm0, 8(%esp)
        movl    %esp, %eax
        pushl   %eax
        calll   _use
        addl    $4, %esp
        movl    %ebp, %esp
        popl    %ebp
        retl

Intel 構文 clang --target=i686-pc-windows-msvc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S win32-align.c

_aligned_local:
        push    ebp
        mov     ebp, esp
        and     esp, -16
        sub     esp, 32
        movsd   xmm0, qword ptr [ebp + 8]
        movsd   qword ptr [esp], xmm0
        movsd   qword ptr [esp + 8], xmm0
        mov     eax, esp
        push    eax
        call    _use
        add     esp, 4
        mov     esp, ebp
        pop     ebp
        ret

MinGW-w64 GCC 14.2.0 (Debian 14.2.0-19+27+b1) i686-w64-mingw32

AT&T 構文 i686-w64-mingw32-gcc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S win32-align.c

_aligned_local:
        pushl   %ebp
        movl    %esp, %ebp
        andl    $-16, %esp
        subl    $32, %esp
        movsd   8(%ebp), %xmm0
        leal    16(%esp), %eax
        movl    %eax, (%esp)
        unpcklpd        %xmm0, %xmm0
        movups  %xmm0, 16(%esp)
        call    _use
        leave
        ret

Intel 構文 i686-w64-mingw32-gcc -march=pentium4 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S win32-align.c

_aligned_local:
        push    ebp
        mov     ebp, esp
        and     esp, -16
        sub     esp, 32
        movsd   xmm0, QWORD PTR [ebp+8]
        lea     eax, [esp+16]
        mov     DWORD PTR [esp], eax
        unpcklpd        xmm0, xmm0
        movups  XMMWORD PTR [esp+16], xmm0
        call    _use
        leave
        ret

GCC 14.2.0 (Debian 14.2.0-19) i386-linux-gnu

AT&T 構文 gcc-14 -m32 -march=i686 -mtune=generic -O2 -fno-asynchronous-unwind-tables -S win32-align.c

aligned_local:
        pushl   %ebx
        call    __x86.get_pc_thunk.bx
        addl    $_GLOBAL_OFFSET_TABLE_, %ebx
        subl    $36, %esp
        fldl    44(%esp)
        leal    12(%esp), %eax
        fstl    12(%esp)
        fstpl   20(%esp)
        pushl   %eax
        call    use@PLT
        addl    $40, %esp
        popl    %ebx
        ret

__x86.get_pc_thunk.bx:
        movl    (%esp), %ebx
        ret

Intel 構文 gcc-14 -m32 -march=i686 -mtune=generic -O2 -fno-asynchronous-unwind-tables -masm=intel -S win32-align.c

aligned_local:
        push    ebx
        call    __x86.get_pc_thunk.bx
        add     ebx, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
        sub     esp, 36
        fld     QWORD PTR 44[esp]
        lea     eax, 12[esp]
        fst     QWORD PTR 12[esp]
        fstp    QWORD PTR 20[esp]
        push    eax
        call    use@PLT
        add     esp, 40
        pop     ebx
        ret

__x86.get_pc_thunk.bx:
        mov     ebx, DWORD PTR [esp]
        ret

32 ビット Windows での C の型のサイズは ABI の概要にあります。double と long long は、Linux が 4 バイトにアラインするのに対し、構造体の中で 8 バイトにアラインされます。long double は、MSVC では double と同じですが、MinGW-w64 では 12 バイトの x87 の型です。

出典

  1. Microsoft Learn: Argument passing and naming conventions: コミット f70d88cd5da7、2026-09-24
  2. Microsoft Learn: __cdecl: コミット f70d88cd5da7、2026-09-24
  3. Microsoft Learn: __stdcall: コミット f70d88cd5da7、2026-09-24
  4. Microsoft Learn: __fastcall: コミット f70d88cd5da7、2026-09-24
  5. Microsoft Learn: __thiscall: コミット f70d88cd5da7、2026-09-24
  6. Microsoft Learn: __vectorcall: コミット f70d88cd5da7、2026-09-24
  7. Microsoft Learn: Decorated names: コミット f70d88cd5da7、2026-09-24
  8. Microsoft Learn: /arch (x86): コミット f70d88cd5da7、2026-09-24
  9. Microsoft Learn: Windows Data Types: コミット e103fa4e8810、2026-09-15
  10. GCC 14.2 manual: x86 Function Attributes: 2026-09-25 の公開版
  11. Clang 23.1.2: clang/lib/CodeGen/Targets/X86.cpp: コミット 85ac56026243、2026-09-20