函数调用中参数是通过堆栈或/和寄存器来传递的,根据调用时由调用函数或被调用函数来恢复堆栈,分为Standard和C两种调用规则,FASTCALL可以看作是Standard的特殊形式。
32 位 C语言编译器支持的调用规则 有 __stdcall (Standard), __cdecl (C) 和 __fastcall (FASTCALL), __cdecl为缺省值。
三种调用规则的特点如下:
调用规测 | 函数命名 | 进栈顺序 | 堆栈清理 | 特点 |
__stdcall | 函数名前加下划线"_",后加"@"和参数字节数 | 从右到左 | 被调用函数 | 堆栈清理代码只有一份,代码小,只能支持固定参数 |
__fastcall | 函数名前加下划线"_",后加"@"和参数字节数 | 右边两个能装入寄存器的参数进寄存器,其余参数从右到左进栈 | 被调用函数 | 通过寄存器传递参数,速度快 |
__cdecl | 函数名前加下划线"_" | 从右到左 | 调用函数 | 编译器为每次调用都生成堆栈清理代码,支持可变参数,如printf() |
以下简单的C程序和相应的汇编代码展示了三种调用规则的细节。
/**/
/*
* callconv - Calling Conventions
*/
int __stdcall stdcall_function( int p1, int p2)
... {
int n1;
int n2;
int ret;
n1 = p1;
n2 = p2;
ret = n1 + n2;
return 0;
}
int __cdecl cdecl_function( int p1, int p2)
... {
int n1, n2;
int ret;
n1 = p1;
n2 = p2;
ret = n1 + n2;
return ret;
}
int __cdecl cdecl_function_v( int p1, int p2, int v, ...)
... {
int n1, n2;
int ret;
n1 = p1;
n2 = p2;
ret = n1 + n2 + v;
return ret;
}
int __fastcall fastcall_function( int p1, double d1, int p2, double d2, int p3)
... {
int n1, n2;
double d;
int ret;
d = d1 + d2;
n1 = p1;
n2 = p2;
ret = n1 + n2 + p3;
return ret ;
}
int add( int p1, int p2)
... {
return (p1 + p2);
}
int main( void )
... {
int m, m1 = 1, m2 = 2, m3 = 3, m4 = 4;
double d1, d2;
d1 = 1.0;
d2 = 2.0;
m = stdcall_function(m1, m2);
m = cdecl_function(m1, m2);
m = cdecl_function_v(m1, m2, m3);
m = cdecl_function_v(m1, m2, m3, m4);
m = fastcall_function(m1, d1, m2, d2, m3);
return 0;
}
* callconv - Calling Conventions
*/
int __stdcall stdcall_function( int p1, int p2)
... {
int n1;
int n2;
int ret;
n1 = p1;
n2 = p2;
ret = n1 + n2;
return 0;
}
int __cdecl cdecl_function( int p1, int p2)
... {
int n1, n2;
int ret;
n1 = p1;
n2 = p2;
ret = n1 + n2;
return ret;
}
int __cdecl cdecl_function_v( int p1, int p2, int v, ...)
... {
int n1, n2;
int ret;
n1 = p1;
n2 = p2;
ret = n1 + n2 + v;
return ret;
}
int __fastcall fastcall_function( int p1, double d1, int p2, double d2, int p3)
... {
int n1, n2;
double d;
int ret;
d = d1 + d2;
n1 = p1;
n2 = p2;
ret = n1 + n2 + p3;
return ret ;
}
int add( int p1, int p2)
... {
return (p1 + p2);
}
int main( void )
... {
int m, m1 = 1, m2 = 2, m3 = 3, m4 = 4;
double d1, d2;
d1 = 1.0;
d2 = 2.0;
m = stdcall_function(m1, m2);
m = cdecl_function(m1, m2);
m = cdecl_function_v(m1, m2, m3);
m = cdecl_function_v(m1, m2, m3, m4);
m = fastcall_function(m1, d1, m2, d2, m3);
return 0;
}
TITLE C:Documents and Settings ootsrccallconvcallconv.c
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC ' CODE '
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC ' DATA '
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC ' CONST '
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC ' BSS '
_BSS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC ' TLS '
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC _stdcall_function@ 8
_TEXT SEGMENT
_p1$ = 8
_p2$ = 12
_n1$ = - 12
_n2$ = - 4
_ret$ = - 8
_stdcall_function@ 8 PROC NEAR
; 6 : ... {
push ebp
mov ebp, esp
sub esp, 12 ; 0000000cH
; 7 : int n1;
; 8 : int n2;
; 9 : int ret;
; 10 :
; 11 : n1 = p1;
mov eax, DWORD PTR _p1$[ebp]
mov DWORD PTR _n1$[ebp], eax
; 12 : n2 = p2;
mov ecx, DWORD PTR _p2$[ebp]
mov DWORD PTR _n2$[ebp], ecx
; 13 :
; 14 : ret = n1 + n2;
mov edx, DWORD PTR _n1$[ebp]
add edx, DWORD PTR _n2$[ebp]
mov DWORD PTR _ret$[ebp], edx
; 15 :
; 16 : return 0;
xor eax, eax
; 17 : }
mov esp, ebp
pop ebp
ret 8
_stdcall_function@ 8 ENDP
_TEXT ENDS
PUBLIC _cdecl_function
_TEXT SEGMENT
_p1$ = 8
_p2$ = 12
_n1$ = - 12
_n2$ = - 4
_ret$ = - 8
_cdecl_function PROC NEAR
; 20 : ... {
push ebp
mov ebp, esp
sub esp, 12 ; 0000000cH
; 21 : int n1, n2;
; 22 :
; 23 : int ret;
; 24 :
; 25 : n1 = p1;
mov eax, DWORD PTR _p1$[ebp]
mov DWORD PTR _n1$[ebp], eax
; 26 : n2 = p2;
mov ecx, DWORD PTR _p2$[ebp]
mov DWORD PTR _n2$[ebp], ecx
; 27 :
; 28 : ret = n1 + n2;
mov edx, DWORD PTR _n1$[ebp]
add edx, DWORD PTR _n2$[ebp]
mov DWORD PTR _ret$[ebp], edx
; 29 :
; 30 : return ret;
mov eax, DWORD PTR _ret$[ebp]
; 31 : }
mov esp, ebp
pop ebp
ret 0
_cdecl_function ENDP
_TEXT ENDS
PUBLIC _cdecl_function_v
_TEXT SEGMENT
_p1$ = 8
_p2$ = 12
_v$ = 16
_n1$ = - 12
_n2$ = - 4
_ret$ = - 8
_cdecl_function_v PROC NEAR
; 34 : ... {
push ebp
mov ebp, esp
sub esp, 12 ; 0000000cH
; 35 : int n1, n2;
; 36 :
; 37 : int ret;
; 38 :
; 39 : n1 = p1;
mov eax, DWORD PTR _p1$[ebp]
mov DWORD PTR _n1$[ebp], eax
; 40 : n2 = p2;
mov ecx, DWORD PTR _p2$[ebp]
mov DWORD PTR _n2$[ebp], ecx
; 41 :
; 42 : ret = n1 + n2 + v;
mov edx, DWORD PTR _n1$[ebp]
add edx, DWORD PTR _n2$[ebp]
add edx, DWORD PTR _v$[ebp]
mov DWORD PTR _ret$[ebp], edx
; 43 :
; 44 : return ret;
mov eax, DWORD PTR _ret$[ebp]
; 45 : }
mov esp, ebp
pop ebp
ret 0
_cdecl_function_v ENDP
_TEXT ENDS
PUBLIC @fastcall_function@ 28
EXTRN __fltused:NEAR
_TEXT SEGMENT
_p1$ = - 24
_d1$ = 8
_p2$ = - 28
_d2$ = 16
_p3$ = 24
_n1$ = - 20
_n2$ = - 4
_d$ = - 12
_ret$ = - 16
@fastcall_function@ 28 PROC NEAR
; 48 : ... {
push ebp
mov ebp, esp
sub esp, 28 ; 0000001cH
mov DWORD PTR _p2$[ebp], edx
mov DWORD PTR _p1$[ebp], ecx
; 49 : int n1, n2;
; 50 : double d;
; 51 :
; 52 : int ret;
; 53 :
; 54 : d = d1 + d2;
fld QWORD PTR _d1$[ebp]
fadd QWORD PTR _d2$[ebp]
fstp QWORD PTR _d$[ebp]
; 55 :
; 56 : n1 = p1;
mov eax, DWORD PTR _p1$[ebp]
mov DWORD PTR _n1$[ebp], eax
; 57 : n2 = p2;
mov ecx, DWORD PTR _p2$[ebp]
mov DWORD PTR _n2$[ebp], ecx
; 58 :
; 59 : ret = n1 + n2 + p3;
mov edx, DWORD PTR _n1$[ebp]
add edx, DWORD PTR _n2$[ebp]
add edx, DWORD PTR _p3$[ebp]
mov DWORD PTR _ret$[ebp], edx
; 60 :
; 61 : return ret ;
mov eax, DWORD PTR _ret$[ebp]
; 62 : }
mov esp, ebp
pop ebp
ret 20 ; 00000014H
@fastcall_function@ 28 ENDP
_TEXT ENDS
PUBLIC _add
_TEXT SEGMENT
_p1$ = 8
_p2$ = 12
_add PROC NEAR
; 65 : ... {
push ebp
mov ebp, esp
; 66 : return (p1 + p2);
mov eax, DWORD PTR _p1$[ebp]
add eax, DWORD PTR _p2$[ebp]
; 67 : }
pop ebp
ret 0
_add ENDP
_TEXT ENDS
PUBLIC _main
_TEXT SEGMENT
_m$ = - 32
_m1$ = - 20
_m2$ = - 24
_m3$ = - 28
_m4$ = - 36
_d1$ = - 8
_d2$ = - 16
_main PROC NEAR
; 70 : ... {
push ebp
mov ebp, esp
sub esp, 36 ; 00000024H
; 71 : int m, m1 = 1, m2 = 2, m3 = 3, m4 = 4;
mov DWORD PTR _m1$[ebp], 1
mov DWORD PTR _m2$[ebp], 2
mov DWORD PTR _m3$[ebp], 3
mov DWORD PTR _m4$[ebp], 4
; 72 :
; 73 : double d1, d2;
; 74 :
; 75 : d1 = 1.0;
mov DWORD PTR _d1$[ebp], 0
mov DWORD PTR _d1$[ebp+4], 1072693248 ; 3ff00000H
; 76 : d2 = 2.0;
mov DWORD PTR _d2$[ebp], 0
mov DWORD PTR _d2$[ebp+4], 1073741824 ; 40000000H
; 77 :
; 78 : m = stdcall_function(m1, m2);
mov eax, DWORD PTR _m2$[ebp]
push eax
mov ecx, DWORD PTR _m1$[ebp]
push ecx
call _stdcall_function@8
mov DWORD PTR _m$[ebp], eax
; 79 :
; 80 : m = cdecl_function(m1, m2);
mov edx, DWORD PTR _m2$[ebp]
push edx
mov eax, DWORD PTR _m1$[ebp]
push eax
call _cdecl_function
add esp, 8
mov DWORD PTR _m$[ebp], eax
; 81 :
; 82 : m = cdecl_function_v(m1, m2, m3);
mov ecx, DWORD PTR _m3$[ebp]
push ecx
mov edx, DWORD PTR _m2$[ebp]
push edx
mov eax, DWORD PTR _m1$[ebp]
push eax
call _cdecl_function_v
add esp, 12 ; 0000000cH
mov DWORD PTR _m$[ebp], eax
; 83 :
; 84 : m = cdecl_function_v(m1, m2, m3, m4);
mov ecx, DWORD PTR _m4$[ebp]
push ecx
mov edx, DWORD PTR _m3$[ebp]
push edx
mov eax, DWORD PTR _m2$[ebp]
push eax
mov ecx, DWORD PTR _m1$[ebp]
push ecx
call _cdecl_function_v
add esp, 16 ; 00000010H
mov DWORD PTR _m$[ebp], eax
; 85 :
; 86 : m = fastcall_function(m1, d1, m2, d2, m3);
mov edx, DWORD PTR _m3$[ebp]
push edx
mov eax, DWORD PTR _d2$[ebp+4]
push eax
mov ecx, DWORD PTR _d2$[ebp]
push ecx
mov edx, DWORD PTR _m2$[ebp]
mov eax, DWORD PTR _d1$[ebp+4]
push eax
mov ecx, DWORD PTR _d1$[ebp]
push ecx
mov ecx, DWORD PTR _m1$[ebp]
call @fastcall_function@28
mov DWORD PTR _m$[ebp], eax
; 87 :
; 88 : return 0;
xor eax, eax
; 89 : }
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC ' CODE '
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC ' DATA '
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC ' CONST '
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC ' BSS '
_BSS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC ' TLS '
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC _stdcall_function@ 8
_TEXT SEGMENT
_p1$ = 8
_p2$ = 12
_n1$ = - 12
_n2$ = - 4
_ret$ = - 8
_stdcall_function@ 8 PROC NEAR
; 6 : ... {
push ebp
mov ebp, esp
sub esp, 12 ; 0000000cH
; 7 : int n1;
; 8 : int n2;
; 9 : int ret;
; 10 :
; 11 : n1 = p1;
mov eax, DWORD PTR _p1$[ebp]
mov DWORD PTR _n1$[ebp], eax
; 12 : n2 = p2;
mov ecx, DWORD PTR _p2$[ebp]
mov DWORD PTR _n2$[ebp], ecx
; 13 :
; 14 : ret = n1 + n2;
mov edx, DWORD PTR _n1$[ebp]
add edx, DWORD PTR _n2$[ebp]
mov DWORD PTR _ret$[ebp], edx
; 15 :
; 16 : return 0;
xor eax, eax
; 17 : }
mov esp, ebp
pop ebp
ret 8
_stdcall_function@ 8 ENDP
_TEXT ENDS
PUBLIC _cdecl_function
_TEXT SEGMENT
_p1$ = 8
_p2$ = 12
_n1$ = - 12
_n2$ = - 4
_ret$ = - 8
_cdecl_function PROC NEAR
; 20 : ... {
push ebp
mov ebp, esp
sub esp, 12 ; 0000000cH
; 21 : int n1, n2;
; 22 :
; 23 : int ret;
; 24 :
; 25 : n1 = p1;
mov eax, DWORD PTR _p1$[ebp]
mov DWORD PTR _n1$[ebp], eax
; 26 : n2 = p2;
mov ecx, DWORD PTR _p2$[ebp]
mov DWORD PTR _n2$[ebp], ecx
; 27 :
; 28 : ret = n1 + n2;
mov edx, DWORD PTR _n1$[ebp]
add edx, DWORD PTR _n2$[ebp]
mov DWORD PTR _ret$[ebp], edx
; 29 :
; 30 : return ret;
mov eax, DWORD PTR _ret$[ebp]
; 31 : }
mov esp, ebp
pop ebp
ret 0
_cdecl_function ENDP
_TEXT ENDS
PUBLIC _cdecl_function_v
_TEXT SEGMENT
_p1$ = 8
_p2$ = 12
_v$ = 16
_n1$ = - 12
_n2$ = - 4
_ret$ = - 8
_cdecl_function_v PROC NEAR
; 34 : ... {
push ebp
mov ebp, esp
sub esp, 12 ; 0000000cH
; 35 : int n1, n2;
; 36 :
; 37 : int ret;
; 38 :
; 39 : n1 = p1;
mov eax, DWORD PTR _p1$[ebp]
mov DWORD PTR _n1$[ebp], eax
; 40 : n2 = p2;
mov ecx, DWORD PTR _p2$[ebp]
mov DWORD PTR _n2$[ebp], ecx
; 41 :
; 42 : ret = n1 + n2 + v;
mov edx, DWORD PTR _n1$[ebp]
add edx, DWORD PTR _n2$[ebp]
add edx, DWORD PTR _v$[ebp]
mov DWORD PTR _ret$[ebp], edx
; 43 :
; 44 : return ret;
mov eax, DWORD PTR _ret$[ebp]
; 45 : }
mov esp, ebp
pop ebp
ret 0
_cdecl_function_v ENDP
_TEXT ENDS
PUBLIC @fastcall_function@ 28
EXTRN __fltused:NEAR
_TEXT SEGMENT
_p1$ = - 24
_d1$ = 8
_p2$ = - 28
_d2$ = 16
_p3$ = 24
_n1$ = - 20
_n2$ = - 4
_d$ = - 12
_ret$ = - 16
@fastcall_function@ 28 PROC NEAR
; 48 : ... {
push ebp
mov ebp, esp
sub esp, 28 ; 0000001cH
mov DWORD PTR _p2$[ebp], edx
mov DWORD PTR _p1$[ebp], ecx
; 49 : int n1, n2;
; 50 : double d;
; 51 :
; 52 : int ret;
; 53 :
; 54 : d = d1 + d2;
fld QWORD PTR _d1$[ebp]
fadd QWORD PTR _d2$[ebp]
fstp QWORD PTR _d$[ebp]
; 55 :
; 56 : n1 = p1;
mov eax, DWORD PTR _p1$[ebp]
mov DWORD PTR _n1$[ebp], eax
; 57 : n2 = p2;
mov ecx, DWORD PTR _p2$[ebp]
mov DWORD PTR _n2$[ebp], ecx
; 58 :
; 59 : ret = n1 + n2 + p3;
mov edx, DWORD PTR _n1$[ebp]
add edx, DWORD PTR _n2$[ebp]
add edx, DWORD PTR _p3$[ebp]
mov DWORD PTR _ret$[ebp], edx
; 60 :
; 61 : return ret ;
mov eax, DWORD PTR _ret$[ebp]
; 62 : }
mov esp, ebp
pop ebp
ret 20 ; 00000014H
@fastcall_function@ 28 ENDP
_TEXT ENDS
PUBLIC _add
_TEXT SEGMENT
_p1$ = 8
_p2$ = 12
_add PROC NEAR
; 65 : ... {
push ebp
mov ebp, esp
; 66 : return (p1 + p2);
mov eax, DWORD PTR _p1$[ebp]
add eax, DWORD PTR _p2$[ebp]
; 67 : }
pop ebp
ret 0
_add ENDP
_TEXT ENDS
PUBLIC _main
_TEXT SEGMENT
_m$ = - 32
_m1$ = - 20
_m2$ = - 24
_m3$ = - 28
_m4$ = - 36
_d1$ = - 8
_d2$ = - 16
_main PROC NEAR
; 70 : ... {
push ebp
mov ebp, esp
sub esp, 36 ; 00000024H
; 71 : int m, m1 = 1, m2 = 2, m3 = 3, m4 = 4;
mov DWORD PTR _m1$[ebp], 1
mov DWORD PTR _m2$[ebp], 2
mov DWORD PTR _m3$[ebp], 3
mov DWORD PTR _m4$[ebp], 4
; 72 :
; 73 : double d1, d2;
; 74 :
; 75 : d1 = 1.0;
mov DWORD PTR _d1$[ebp], 0
mov DWORD PTR _d1$[ebp+4], 1072693248 ; 3ff00000H
; 76 : d2 = 2.0;
mov DWORD PTR _d2$[ebp], 0
mov DWORD PTR _d2$[ebp+4], 1073741824 ; 40000000H
; 77 :
; 78 : m = stdcall_function(m1, m2);
mov eax, DWORD PTR _m2$[ebp]
push eax
mov ecx, DWORD PTR _m1$[ebp]
push ecx
call _stdcall_function@8
mov DWORD PTR _m$[ebp], eax
; 79 :
; 80 : m = cdecl_function(m1, m2);
mov edx, DWORD PTR _m2$[ebp]
push edx
mov eax, DWORD PTR _m1$[ebp]
push eax
call _cdecl_function
add esp, 8
mov DWORD PTR _m$[ebp], eax
; 81 :
; 82 : m = cdecl_function_v(m1, m2, m3);
mov ecx, DWORD PTR _m3$[ebp]
push ecx
mov edx, DWORD PTR _m2$[ebp]
push edx
mov eax, DWORD PTR _m1$[ebp]
push eax
call _cdecl_function_v
add esp, 12 ; 0000000cH
mov DWORD PTR _m$[ebp], eax
; 83 :
; 84 : m = cdecl_function_v(m1, m2, m3, m4);
mov ecx, DWORD PTR _m4$[ebp]
push ecx
mov edx, DWORD PTR _m3$[ebp]
push edx
mov eax, DWORD PTR _m2$[ebp]
push eax
mov ecx, DWORD PTR _m1$[ebp]
push ecx
call _cdecl_function_v
add esp, 16 ; 00000010H
mov DWORD PTR _m$[ebp], eax
; 85 :
; 86 : m = fastcall_function(m1, d1, m2, d2, m3);
mov edx, DWORD PTR _m3$[ebp]
push edx
mov eax, DWORD PTR _d2$[ebp+4]
push eax
mov ecx, DWORD PTR _d2$[ebp]
push ecx
mov edx, DWORD PTR _m2$[ebp]
mov eax, DWORD PTR _d1$[ebp+4]
push eax
mov ecx, DWORD PTR _d1$[ebp]
push ecx
mov ecx, DWORD PTR _m1$[ebp]
call @fastcall_function@28
mov DWORD PTR _m$[ebp], eax
; 87 :
; 88 : return 0;
xor eax, eax
; 89 : }
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END