C语言调规则浅析

函数调用中参数是通过堆栈或/和寄存器来传递的,根据调用时由调用函数或被调用函数来恢复堆栈,分为Standard和C两种调用规则,FASTCALL可以看作是Standard的特殊形式。

 

32  位 C语言编译器支持的调用规则 有 __stdcall (Standard), __cdecl (C)  和 __fastcall  (FASTCALL), __cdecl为缺省值。

 

三种调用规则的特点如下:

C语言调用规则
调用规测 函数命名 进栈顺序 堆栈清理 特点
__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;
}

 

 

    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

你可能感兴趣的:(C语言调规则浅析)