Day5:函数调用约定
函数调用约定
函数调用约定
主要有三种:cdecl、stdcall、fastcall。以求和函数为例
1
2
3
4
5
6
7
8
9
10//求和
#include<stdio.h>
int sum(int a,int b,int c){
return a+b+c;
}
int main(){
int res=sum(1,2,3);
printf("%d\n",res);
return 0;
}cdecl:完全栈传参,参数从右往左入栈,由调用者清理参数占用的栈空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83; int __cdecl main()
_main proc near ; CODE XREF: j__main↑j
var_C = byte ptr -0Ch
res = dword ptr -8
push ebp
mov ebp, esp
sub esp, 0CCh
push ebx
push esi
push edi
__$EncStackInitStart_2:
lea edi, [ebp+var_C]
mov ecx, 3
mov eax, 0CCCCCCCCh
rep stosd
__$EncStackInitEnd_2: ; JMC_flag
mov ecx, offset _6005466B_entry@cpp
call j_@__CheckForDebuggerJustMyCode@4 ; __CheckForDebuggerJustMyCode(x)
nop
push 3 ; 参数c入栈
push 2 ; 参数b入栈
push 1 ; 参数a入栈
call j_?sum@@YAHHHH@Z ; sum(int,int,int)
add esp, 0Ch ;这里调用者进行了清理参数占用的栈空间的操作(3个参数×4字节),被调用者不负责
mov [ebp+res], eax
mov eax, [ebp+res]
push eax
push offset _Format ; "%d\n"
call j__printf
add esp, 8
xor eax, eax
pop edi
pop esi
pop ebx
add esp, 0CCh
cmp ebp, esp
call j___RTC_CheckEsp
mov esp, ebp
pop ebp
retn
_main endp
; int __cdecl sum(int a, int b, int c)
?sum@@YAHHHH@Z proc near ; CODE XREF: sum(int,int,int)↑j
a = dword ptr 8
b = dword ptr 0Ch
c = dword ptr 10h
push ebp
mov ebp, esp
sub esp, 0C0h ;sum函数自身的栈空间
push ebx
push esi
push edi
__$EncStackInitStart:
mov edi, ebp
xor ecx, ecx
mov eax, 0CCCCCCCCh
rep stosd
__$EncStackInitEnd: ; JMC_flag
mov ecx, offset _6005466B_entry@cpp
call j_@__CheckForDebuggerJustMyCode@4 ; __CheckForDebuggerJustMyCode(x)
nop
mov eax, [ebp+a]
add eax, [ebp+b]
add eax, [ebp+c]
pop edi
pop esi
pop ebx
add esp, 0C0h ;清理自身栈空间
cmp ebp, esp
call j___RTC_CheckEsp
mov esp, ebp
pop ebp
retn
?sum@@YAHHHH@Z endpstdcall:完全栈传参,参数从右往左入栈,由被调用者清理参数占用的栈空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82; int __cdecl main()
_main proc near ; CODE XREF: j__main↑j
var_C = byte ptr -0Ch
res = dword ptr -8
push ebp
mov ebp, esp
sub esp, 0CCh
push ebx
push esi
push edi
__$EncStackInitStart_2:
lea edi, [ebp+var_C]
mov ecx, 3
mov eax, 0CCCCCCCCh
rep stosd
__$EncStackInitEnd_2: ; JMC_flag
mov ecx, offset _6005466B_entry@cpp
call j_@__CheckForDebuggerJustMyCode@4 ; __CheckForDebuggerJustMyCode(x)
nop
push 3 ; 参数c入栈
push 2 ; 参数b入栈
push 1 ; 参数a入栈
call j_?sum@@YGHHHH@Z ; sum(int,int,int)
mov [ebp+res], eax ;这里直接到把返回值给res了,调用者不负责清理参数占用的栈空间
mov eax, [ebp+res]
push eax
push offset _Format ; "%d\n"
call j__printf
add esp, 8
xor eax, eax
pop edi
pop esi
pop ebx
add esp, 0CCh
cmp ebp, esp
call j___RTC_CheckEsp
mov esp, ebp
pop ebp
retn
_main endp
; int __stdcall sum(int a, int b, int c)
?sum@@YGHHHH@Z proc near ; CODE XREF: sum(int,int,int)↑j
a = dword ptr 8
b = dword ptr 0Ch
c = dword ptr 10h
push ebp
mov ebp, esp
sub esp, 0C0h ;sum的栈空间
push ebx
push esi
push edi
__$EncStackInitStart:
mov edi, ebp
xor ecx, ecx
mov eax, 0CCCCCCCCh
rep stosd
__$EncStackInitEnd: ; JMC_flag
mov ecx, offset _6005466B_entry@cpp
call j_@__CheckForDebuggerJustMyCode@4 ; __CheckForDebuggerJustMyCode(x)
nop
mov eax, [ebp+a]
add eax, [ebp+b]
add eax, [ebp+c]
pop edi
pop esi
pop ebx
add esp, 0C0h ;清理自身栈空间
cmp ebp, esp
call j___RTC_CheckEsp
mov esp, ebp
pop ebp
retn 0Ch ;被调用者通过返回指令给esp增加0Ch,清理参数占用的栈空间
?sum@@YGHHHH@Z endpfastcall:寄存器+栈传参,优先使用寄存器,剩余参数从右往左入栈,由被调用者清理参数占用的栈空间
寄存器传参优先级:
x86:ecx edx 栈
x64:rcx rdx r8 r9 栈
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87; int __cdecl main()
_main proc near ; CODE XREF: j__main↑j
var_C = byte ptr -0Ch
res = dword ptr -8
push ebp
mov ebp, esp
sub esp, 0CCh
push ebx
push esi
push edi
__$EncStackInitStart_2:
lea edi, [ebp+var_C]
mov ecx, 3
mov eax, 0CCCCCCCCh
rep stosd
__$EncStackInitEnd_2: ; JMC_flag
mov ecx, offset _6005466B_entry@cpp
call j_@__CheckForDebuggerJustMyCode@4 ; __CheckForDebuggerJustMyCode(x)
nop
push 3 ; 参数c入栈
mov edx, 2 ; 参数b存入寄存器
mov ecx, 1 ; 参数a存入寄存器
call j_?sum@@YIHHHH@Z ; sum(int,int,int)
mov [ebp+res], eax ;这里也是没有调用者对参数占用的栈空间的清理
mov eax, [ebp+res]
push eax
push offset _Format ; "%d\n"
call j__printf
add esp, 8
xor eax, eax
pop edi
pop esi
pop ebx
add esp, 0CCh
cmp ebp, esp
call j___RTC_CheckEsp
mov esp, ebp
pop ebp
retn
_main endp
; int __fastcall sum(int a, int b, int c)
?sum@@YIHHHH@Z proc near ; CODE XREF: sum(int,int,int)↑j
var_18 = byte ptr -18h
b = dword ptr -14h
a = dword ptr -8
c = dword ptr 8
push ebp
mov ebp, esp
sub esp, 0D8h ;sum开辟栈空间
push ebx
push esi
push edi
push ecx
__$EncStackInitStart:
lea edi, [ebp+var_18]
mov ecx, 6
mov eax, 0CCCCCCCCh
rep stosd
__$EncStackInitEnd:
pop ecx
mov [ebp+b], edx
mov [ebp+a], ecx
mov ecx, offset _6005466B_entry@cpp ; JMC_flag
call j_@__CheckForDebuggerJustMyCode@4 ; __CheckForDebuggerJustMyCode(x)
nop
mov eax, [ebp+a]
add eax, [ebp+b]
add eax, [ebp+c]
pop edi
pop esi
pop ebx
add esp, 0D8h ;sum清理栈空间
cmp ebp, esp
call j___RTC_CheckEsp
mov esp, ebp
pop ebp
retn 4 ;由于只有一个参数被push到栈上,所以被调用者返回4,清理参数占用的栈空间
?sum@@YIHHHH@Z endp