常见函数调用约定(x86、x64、arm、arm64)
我学习逆向,整理的一些常见的函数调用约定反汇编笔记。由于我是新手,肯定有一些疏漏不完善的,我遇到了会实时更新的。
更新时间:2018年3月7日
X86 函数调用约定
X86 有三种常用调用约定,cdecl(C规范)/stdcall(WinAPI默认)/fastcall 函数调用约定。
cdecl 函数调用约定
参数从右往左依次入栈,调用者实现栈平衡,返回值存放在 EAX 中。
|
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
|
20: int cdecl_sum = cdecl_add(1, 2, 3, 4, 5, 6, 7);00401138 push 70040113A push 60040113C push 50040113E push 400401140 push 300401142 push 200401144 push 100401146 call @ILT+5(_cdecl_add) (0040100a)0040114B add esp,1Ch # 栈平衡0040114E mov dword ptr [ebp-4],eax # 返回值3: int __cdecl cdecl_add(int a, int b, int c, int d, int e, int f, int g)4: {00401030 push ebp00401031 mov ebp,esp00401033 sub esp,44h00401036 push ebx00401037 push esi00401038 push edi00401039 lea edi,[ebp-44h]0040103C mov ecx,11h00401041 mov eax,0CCCCCCCCh00401046 rep stos dword ptr [edi]5: int sum = a+b+c+d+e+f+g;00401048 mov eax,dword ptr [ebp+8]0040104B add eax,dword ptr [ebp+0Ch]0040104E add eax,dword ptr [ebp+10h]00401051 add eax,dword ptr [ebp+14h]00401054 add eax,dword ptr [ebp+18h]00401057 add eax,dword ptr [ebp+1Ch]0040105A add eax,dword ptr [ebp+20h]0040105D mov dword ptr [ebp-4],eax6: return sum;00401060 mov eax,dword ptr [ebp-4] # 存放返回值7: }00401063 pop edi00401064 pop esi00401065 pop ebx00401066 mov esp,ebp00401068 pop ebp00401069 ret |
stdcall 函数调用约定
参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 EAX 中。
|
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
|
21: int stdcall_sum = stdcall_add(1, 2, 3, 4, 5, 6, 7);00401151 push 700401153 push 600401155 push 500401157 push 400401159 push 30040115B push 20040115D push 10040115F call @ILT+15(_stdcall_add@28) (00401014)00401164 mov dword ptr [ebp-8],eax # 返回值9: int __stdcall stdcall_add(int a, int b, int c, int d, int e, int f, int g)10: {00401080 push ebp00401081 mov ebp,esp00401083 sub esp,44h00401086 push ebx00401087 push esi00401088 push edi00401089 lea edi,[ebp-44h]0040108C mov ecx,11h00401091 mov eax,0CCCCCCCCh00401096 rep stos dword ptr [edi]11: int sum = a+b+c+d+e+f+g;00401098 mov eax,dword ptr [ebp+8]0040109B add eax,dword ptr [ebp+0Ch]0040109E add eax,dword ptr [ebp+10h]004010A1 add eax,dword ptr [ebp+14h]004010A4 add eax,dword ptr [ebp+18h]004010A7 add eax,dword ptr [ebp+1Ch]004010AA add eax,dword ptr [ebp+20h]004010AD mov dword ptr [ebp-4],eax12: return sum;004010B0 mov eax,dword ptr [ebp-4] # 存放返回值13: }004010B3 pop edi004010B4 pop esi004010B5 pop ebx004010B6 mov esp,ebp004010B8 pop ebp004010B9 ret 1Ch # 栈平衡(等价于先 add esp, 1Ch 再 ret) |
fastcall 函数调用约定
参数1、参数2分别保存在 ECX、EDX ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 EAX 中。
|
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
|
25: int fastcall_sum = fastcall_add(1, 2, 3, 4, 5, 6, 7);00401167 push 700401169 push 60040116B push 50040116D push 40040116F push 300401171 mov edx,200401176 mov ecx,10040117B call @ILT+0(@fastcall_add@28) (00401005)00401180 mov dword ptr [ebp-0Ch],eax # 返回值15: int __fastcall fastcall_add(int a, int b, int c, int d, int e, int f, int g)16: {004010D0 push ebp004010D1 mov ebp,esp004010D3 sub esp,4Ch004010D6 push ebx004010D7 push esi004010D8 push edi004010D9 push ecx004010DA lea edi,[ebp-4Ch]004010DD mov ecx,13h004010E2 mov eax,0CCCCCCCCh004010E7 rep stos dword ptr [edi]004010E9 pop ecx004010EA mov dword ptr [ebp-8],edx004010ED mov dword ptr [ebp-4],ecx17: int sum = a+b+c+d+e+f+g;004010F0 mov eax,dword ptr [ebp-4]004010F3 add eax,dword ptr [ebp-8]004010F6 add eax,dword ptr [ebp+8]004010F9 add eax,dword ptr [ebp+0Ch]004010FC add eax,dword ptr [ebp+10h]004010FF add eax,dword ptr [ebp+14h]00401102 add eax,dword ptr [ebp+18h]00401105 mov dword ptr [ebp-0Ch],eax18: return sum;00401108 mov eax,dword ptr [ebp-0Ch] # 存放返回值19: }0040110B pop edi0040110C pop esi0040110D pop ebx0040110E mov esp,ebp00401110 pop ebp00401111 ret 14h # 栈平衡(等价于先 add esp, 14h 再 ret) |
X64 函数调用约定
X64只有一种 fastcall 函数调用约定
fastcall 函数调用约定
参数1、参数2、参数3、参数4分别保存在 RCX、RDX、R8D、R9D ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 RAX 中。
|
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
|
# 该代码是 msvc 2017 x64 生成的汇编代码 int fastcall_sum = fastcall_add(1, 2, 3, 4, 5, 6, 7);00007FF6577A366E mov dword ptr [rsp+30h],700007FF6577A3676 mov dword ptr [rsp+28h],6 00007FF6577A367E mov dword ptr [rsp+20h],5 00007FF6577A3686 mov r9d,4 00007FF6577A368C mov r8d,3 00007FF6577A3692 mov edx,2 00007FF6577A3697 mov ecx,1 00007FF6577A369C call fastcall_add (07FF6577A11C2h) 00007FF6577A36A1 mov dword ptr [fastcall_sum],eax # 返回值int __fastcall fastcall_add(int a, int b, int c, int d, int e, int f, int g){00007FF6D22D1790 mov dword ptr [rsp+20h],r9d 00007FF6D22D1795 mov dword ptr [rsp+18h],r8d 00007FF6D22D179A mov dword ptr [rsp+10h],edx 00007FF6D22D179E mov dword ptr [rsp+8],ecx 00007FF6D22D17A2 push rbp 00007FF6D22D17A3 push rdi 00007FF6D22D17A4 sub rsp,0E8h 00007FF6D22D17AB mov rbp,rsp 00007FF6D22D17AE mov rdi,rsp 00007FF6D22D17B1 mov ecx,3Ah 00007FF6D22D17B6 mov eax,0CCCCCCCCh 00007FF6D22D17BB rep stos dword ptr [rdi] 00007FF6D22D17BD mov ecx,dword ptr [rsp+108h] int sum = a + b + c + d + e + f + g;00007FF6D22D17C4 mov eax,dword ptr [b] 00007FF6D22D17CA mov ecx,dword ptr [a] 00007FF6D22D17D0 add ecx,eax 00007FF6D22D17D2 mov eax,ecx 00007FF6D22D17D4 add eax,dword ptr [c] 00007FF6D22D17DA add eax,dword ptr [d] 00007FF6D22D17E0 add eax,dword ptr [e] 00007FF6D22D17E6 add eax,dword ptr [f] 00007FF6D22D17EC add eax,dword ptr [g] 00007FF6D22D17F2 mov dword ptr [sum],eax return sum;00007FF6D22D17F5 mov eax,dword ptr [sum] # 存放返回值}00007FF6D22D17F8 lea rsp,[rbp+0E8h] 00007FF6D22D17FF pop rdi 00007FF6D22D1800 pop rbp 00007FF6D22D1801 ret # 没做栈平衡 |
ARM/ARM64 函数调用约定
ARM和ARM64使用的是ATPCS(ARM-Thumb Procedure Call Standard/ARM-Thumb过程调用标准)的函数调用约定。
ATPCS 函数调用约定
ARM
参数1~参数4 分别保存到 R0~R3 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 R0 中。
|
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
|
; 该代码是 arm-linux-androideabi-gcc + IDA PRO 生成的反汇编代码.text:00008438 MOV R3, #5.text:0000843C STR R3, [SP].text:00008440 MOV R3, #6.text:00008444 STR R3, [SP,#4].text:00008448 MOV R3, #7.text:0000844C STR R3, [SP,#8].text:00008450 MOV R3, #8.text:00008454 STR R3, [SP,#12].text:00008458 MOV R3, #9.text:0000845C STR R3, [SP,#16].text:00008460 MOV R3, #10.text:00008464 STR R3, [SP,#20].text:00008468 MOV R0, #1.text:0000846C MOV R1, #2.text:00008470 MOV R2, #3.text:00008474 MOV R3, #4.text:00008478 BL add.text:0000847C STR R0, [R11,#-8].text:000083C4 EXPORT add.text:000083C4.text:000083C4 STR R11, [SP,#-4]!.text:000083C8 ADD R11, SP, #0.text:000083CC SUB SP, SP, #0x1C.text:000083D0 STR R0, [R11,#-16].text:000083D4 STR R1, [R11,#-20].text:000083D8 STR R2, [R11,#-24].text:000083DC STR R3, [R11,#-28].text:000083E0 LDR R2, [R11,#-16].text:000083E4 LDR R3, [R11,#-20].text:000083E8 ADD R2, R2, R3.text:000083EC LDR R3, [R11,#-24].text:000083F0 ADD R2, R2, R3.text:000083F4 LDR R3, [R11,#-28].text:000083F8 ADD R2, R2, R3.text:000083FC LDR R3, [R11,#4].text:00008400 ADD R2, R2, R3.text:00008404 LDR R3, [R11,#8].text:00008408 ADD R2, R2, R3.text:0000840C LDR R3, [R11,#12].text:00008410 ADD R3, R2, R3.text:00008414 STR R3, [R11,#-8].text:00008418 LDR R3, [R11,#-8].text:0000841C MOV R0, R3 # 返回值.text:00008420 SUB SP, R11, #0.text:00008424 LDR R11, [SP],#4.text:00008428 BX LR |
ARM64
参数1~参数8 分别保存到 X0~X7 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 X0 中。
|
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
|
; 该代码是 aarch64-linux-android-gcc + IDA PRO 生成的反汇编代码.text:000000000040065C MOV W0, #9.text:0000000000400660 STR W0, [SP].text:0000000000400664 MOV W0, #10.text:0000000000400668 STR W0, [SP,#8].text:000000000040066C MOV W0, #1.text:0000000000400670 MOV W1, #2.text:0000000000400674 MOV W2, #3.text:0000000000400678 MOV W3, #4.text:000000000040067C MOV W4, #5.text:0000000000400680 MOV W5, #6.text:0000000000400684 MOV W6, #7.text:0000000000400688 MOV W7, #8.text:000000000040068C BL add.text:0000000000400690 STR W0, [X29,#28].text:00000000004005E8 EXPORT add.text:00000000004005E8.text:00000000004005E8 SUB SP, SP, #0x30.text:00000000004005EC STR W0, [SP,#28].text:00000000004005F0 STR W1, [SP,#24].text:00000000004005F4 STR W2, [SP,#20].text:00000000004005F8 STR W3, [SP,#16].text:00000000004005FC STR W4, [SP,#12].text:0000000000400600 STR W5, [SP,#8].text:0000000000400604 STR W6, [SP,#4].text:0000000000400608 STR W7, [SP].text:000000000040060C LDR W1, [SP,#28].text:0000000000400610 LDR W0, [SP,#24].text:0000000000400614 ADD W1, W1, W0.text:0000000000400618 LDR W0, [SP,#20].text:000000000040061C ADD W1, W1, W0.text:0000000000400620 LDR W0, [SP,#16].text:0000000000400624 ADD W1, W1, W0.text:0000000000400628 LDR W0, [SP,#12].text:000000000040062C ADD W1, W1, W0.text:0000000000400630 LDR W0, [SP,#8].text:0000000000400634 ADD W1, W1, W0.text:0000000000400638 LDR W0, [SP,#4].text:000000000040063C ADD W0, W1, W0.text:0000000000400640 STR W0, [SP,#44].text:0000000000400644 LDR W0, [SP,#44] # 返回值.text:0000000000400648 ADD SP, SP, #0x30.text:000000000040064C RET |
C++ 函数调用约定
thiscall用于C++中类成员函数(方法)的调用
thiscall 函数调用约定
x86
参数从右往左依次入栈,this指针存放ECX中,被调用者实现栈平衡,返回值存放在 EAX 中。
|
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
|
16: int sum = calc.thiscall_add(1, 2, 3, 4, 5, 6, 7);00401098 push 70040109A push 60040109C push 50040109E push 4004010A0 push 3004010A2 push 2004010A4 push 1004010A6 lea ecx,[ebp-4] # this指针004010A9 call @ILT+0(Calc::thiscall_add) (00401005)004010AE mov dword ptr [ebp-8],eax # 返回值7: int Calc::thiscall_add(int a, int b, int c, int d, int e, int f, int g)8: {00401020 push ebp00401021 mov ebp,esp00401023 sub esp,48h00401026 push ebx00401027 push esi00401028 push edi00401029 push ecx0040102A lea edi,[ebp-48h]0040102D mov ecx,12h00401032 mov eax,0CCCCCCCCh00401037 rep stos dword ptr [edi]00401039 pop ecx0040103A mov dword ptr [ebp-4],ecx9: int sum = a + b + c + d + e + f + g;0040103D mov eax,dword ptr [ebp+8]00401040 add eax,dword ptr [ebp+0Ch]00401043 add eax,dword ptr [ebp+10h]00401046 add eax,dword ptr [ebp+14h]00401049 add eax,dword ptr [ebp+18h]0040104C add eax,dword ptr [ebp+1Ch]0040104F add eax,dword ptr [ebp+20h]00401052 mov dword ptr [ebp-8],eax10: return sum;00401055 mov eax,dword ptr [ebp-8] # 存放返回值11: }00401058 pop edi00401059 pop esi0040105A pop ebx0040105B mov esp,ebp0040105D pop ebp0040105E ret 1Ch # 栈平衡(等价于先 add esp, 1Ch 再 ret) |
X64
参数1、参数2、参数3分别保存在RDX、R8D、R9D中,this指针存放RCX中,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 RAX 中。
|
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
|
# 该代码是 msvc 2017 x64 生成的汇编代码 int sum = calc.thiscall_add(1, 2, 3, 4, 5, 6, 7);00007FF602E6190F mov dword ptr [rsp+38h],7 00007FF602E61917 mov dword ptr [rsp+30h],6 00007FF602E6191F mov dword ptr [rsp+28h],5 00007FF602E61927 mov dword ptr [rsp+20h],4 00007FF602E6192F mov r9d,3 00007FF602E61935 mov r8d,2 00007FF602E6193B mov edx,1 00007FF602E61940 lea rcx,[calc] # this指针00007FF602E61944 call Calc::thiscall_add (07FF602E610A0h) 00007FF602E61949 mov dword ptr [sum],eax # 返回值int Calc::thiscall_add(int a, int b, int c, int d, int e, int f, int g){00007FF602E61770 mov dword ptr [rsp+20h],r9d 00007FF602E61775 mov dword ptr [rsp+18h],r8d 00007FF602E6177A mov dword ptr [rsp+10h],edx 00007FF602E6177E mov qword ptr [rsp+8],rcx 00007FF602E61783 push rbp 00007FF602E61784 push rdi 00007FF602E61785 sub rsp,0E8h 00007FF602E6178C mov rbp,rsp 00007FF602E6178F mov rdi,rsp 00007FF602E61792 mov ecx,3Ah 00007FF602E61797 mov eax,0CCCCCCCCh 00007FF602E6179C rep stos dword ptr [rdi] 00007FF602E6179E mov rcx,qword ptr [rsp+108h] int sum = a + b + c + d + e + f + g;00007FF602E617A6 mov eax,dword ptr [b] 00007FF602E617AC mov ecx,dword ptr [a] 00007FF602E617B2 add ecx,eax 00007FF602E617B4 mov eax,ecx 00007FF602E617B6 add eax,dword ptr [c] 00007FF602E617BC add eax,dword ptr [d] 00007FF602E617C2 add eax,dword ptr [e] 00007FF602E617C8 add eax,dword ptr [f] 00007FF602E617CE add eax,dword ptr [g] 00007FF602E617D4 mov dword ptr [sum],eax return sum;00007FF602E617D7 mov eax,dword ptr [sum] # 存放返回值}00007FF602E617DA lea rsp,[rbp+0E8h] 00007FF602E617E1 pop rdi 00007FF602E617E2 pop rbp 00007FF602E617E3 ret # 没做栈平衡 |
ARM
参数1、参数2、参数3分别保存在R1、R2、R3中,this指针存放R0中,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 R0 中。
|
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
|
; 该代码是 arm-linux-androideabi-gcc + IDA PRO 生成的反汇编代码.text:000085BC MOV R3, #4.text:000085C0 STR R3, [SP] ; int.text:000085C4 MOV R3, #5.text:000085C8 STR R3, [SP,#4] ; int.text:000085CC MOV R3, #6.text:000085D0 STR R3, [SP,#8] ; int.text:000085D4 MOV R3, #7.text:000085D8 STR R3, [SP,#12] ; int.text:000085DC MOV R3, #8.text:000085E0 STR R3, [SP,#16] ; int.text:000085E4 MOV R3, #9.text:000085E8 STR R3, [SP,#20] ; int.text:000085EC MOV R3, #10.text:000085F0 STR R3, [SP,#24] ; int.text:000085F4 MOV R0, R2 ; this.text:000085F8 MOV R1, #1 ; int.text:000085FC MOV R2, #2 ; int.text:00008600 MOV R3, #3 ; int.text:00008604 BL _ZN4Calc12thiscall_addEiiiiiiiiii ; Calc::thiscall_add(int,int,int,int,int,int,int,int,int,int).text:00008608 MOV R3, R0.text:00008544 EXPORT _ZN4Calc12thiscall_addEiiiiiiiiii.text:00008544.text:00008544 STR R11, [SP,#-4]!.text:00008548 ADD R11, SP, #0.text:0000854C SUB SP, SP, #0x1C.text:00008550 STR R0, [R11,#-16].text:00008554 STR R1, [R11,#-20].text:00008558 STR R2, [R11,#-24].text:0000855C STR R3, [R11,#-28].text:00008560 LDR R2, [R11,#-20].text:00008564 LDR R3, [R11,#-24].text:00008568 ADD R2, R2, R3.text:0000856C LDR R3, [R11,#-28].text:00008570 ADD R2, R2, R3.text:00008574 LDR R3, [R11,#4].text:00008578 ADD R2, R2, R3.text:0000857C LDR R3, [R11,#8].text:00008580 ADD R2, R2, R3.text:00008584 LDR R3, [R11,#12].text:00008588 ADD R2, R2, R3.text:0000858C LDR R3, [R11,#16].text:00008590 ADD R3, R2, R3.text:00008594 STR R3, [R11,#-8].text:00008598 LDR R3, [R11,#-8].text:0000859C MOV R0, R3 # 返回值.text:000085A0 SUB SP, R11, #0.text:000085A4 LDR R11, [SP],#4.text:000085A8 BX LR |
ARM64
参数1~参数7 分别保存到 X1~X7 寄存器中,this指针存放X0中,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 X0 中。
|
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
|
; 该代码是 aarch64-linux-android-gcc + IDA PRO 生成的反汇编代码.text:00000000004006A0 MOV W0, #8.text:00000000004006A4 STR W0, [SP] ; int.text:00000000004006A8 MOV W0, #9.text:00000000004006AC STR W0, [SP,#8] ; int.text:00000000004006B0 MOV W0, #10.text:00000000004006B4 STR W0, [SP,#16] ; int.text:00000000004006B8 MOV X0, X1 ; this.text:00000000004006BC MOV W1, #1 ; int.text:00000000004006C0 MOV W2, #2 ; int.text:00000000004006C4 MOV W3, #3 ; int.text:00000000004006C8 MOV W4, #4 ; int.text:00000000004006CC MOV W5, #5 ; int.text:00000000004006D0 MOV W6, #6 ; int.text:00000000004006D4 MOV W7, #7 ; int.text:00000000004006D8 BL _ZN4Calc12thiscall_addEiiiiiiiiii ; Calc::thiscall_add(int,int,int,int,int,int,int,int,int,int).text:00000000004006DC STR W0, [X29,#0x1C].text:0000000000400628 EXPORT _ZN4Calc12thiscall_addEiiiiiiiiii.text:0000000000400628.text:0000000000400628 SUB SP, SP, #0x40.text:000000000040062C STR X0, [SP,#40].text:0000000000400630 STR W1, [SP,#36].text:0000000000400634 STR W2, [SP,#32].text:0000000000400638 STR W3, [SP,#28].text:000000000040063C STR W4, [SP,#24].text:0000000000400640 STR W5, [SP,#20].text:0000000000400644 STR W6, [SP,#16].text:0000000000400648 STR W7, [SP,#12].text:000000000040064C LDR W1, [SP,#36].text:0000000000400650 LDR W0, [SP,#32].text:0000000000400654 ADD W1, W1, W0.text:0000000000400658 LDR W0, [SP,#28].text:000000000040065C ADD W1, W1, W0.text:0000000000400660 LDR W0, [SP,#24].text:0000000000400664 ADD W1, W1, W0.text:0000000000400668 LDR W0, [SP,#20].text:000000000040066C ADD W1, W1, W0.text:0000000000400670 LDR W0, [SP,#16].text:0000000000400674 ADD W1, W1, W0.text:0000000000400678 LDR W0, [SP,#12].text:000000000040067C ADD W0, W1, W0.text:0000000000400680 STR W0, [SP,#60].text:0000000000400684 LDR W0, [SP,#60] # 返回值.text:0000000000400688 ADD SP, SP, #0x40.text:000000000040068C RET |
https://bbs.pediy.com/thread-224583.htm
一、概述
__stdcall、__cdecl和__fastcall是三种函数调用协议,函数调用协议会影响函数参数的入栈方式、栈内数据的清除方式、编译器函数名的修饰规则等。
二、调用协议常用场合
__stdcall:Windows API默认的函数调用协议。
__cdecl:C/C++默认的函数调用协议。
__fastcall:适用于对性能要求较高的场合。
三、 函数参数入栈方式
__stdcall:函数参数由右向左入栈。
__cdecl:函数参数由右向左入栈。
__fastcall:从左开始不大于4字节的参数放入CPU的ECX和EDX寄存器,其余参数从右向左入栈。
四、栈内数据清除方式
__stdcall:函数调用结束后由被调用函数清除栈内数据。
__cdecl:函数调用结束后由函数调用者清除栈内数据。
__fastcall:函数调用结束后由被调用函数清除栈内数据。
五、常见问题
-
__fastcall在寄存器中放入不大于4字节的参数,故性能较高,适用于需要高性能的场合。
-
不同编译器设定的栈结构不尽相同,跨开发平台时由函数调用者清除栈内数据不可行。
-
某些函数的参数是可变的,如printf函数,这样的函数只能由函数调用者清除栈内数据。
-
由调用者清除栈内数据时,每次调用都包含清除栈内数据的代码,故可执行文件较大。
六、C语言编译器函数名称修饰规则
__stdcall:编译后,函数名被修饰为"_functionname@number"。
__cdecl:编译后,函数名被修饰为"_functionname"。
__fastcall:编译后, 函数名给修饰为"@functionname@nmuber"。
注:"functionname"为函数名,"number"为参数字节数。
注:函数实现和函数定义时如果使用了不同的函数调用协议,则无法实现函数调用。
七、C++语言编译器函数名称修饰规则
__stdcall:编译后,函数名被修饰为"?functionname@@YG******@Z"。
__cdecl:编译后,函数名被修饰为"?functionname@@YA******@Z"。
__fastcall:编译后,函数名被修饰为"?functionname@@YI******@Z"。
注:"******"为函数返回值类型和参数类型表。
注:函数实现和函数定义时如果使用了不同的函数调用协议,则无法实现函数调用。 C语言和C++语言间如果不进行特殊处理,也无法实现函数的互相调用。
https://www.cnblogs.com/aspiration2016/p/6031734.html
可变参数
#define printf(FMT, arg...) user_printf(FMT, ##arg)
#include <stdio.h> #include <stdarg.h> void var_test(char *format, ...) { va_list list; va_start(list,format); char *ch; while(1) { ch = va_arg(list, char *); if(strcmp(ch,"") == 0) { printf(" "); break; } printf("%s ",ch); } va_end(list); } int main() { var_test("test","this","is","a","test",""); return 0; }