常见函数调用约定(x86、x64、arm、arm64)
常见函数调用约定(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 7 0040113A push 6 0040113C push 5 0040113E push 4 00401140 push 3 00401142 push 2 00401144 push 1 00401146 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 ebp 00401031 mov ebp,esp 00401033 sub esp, 44h 00401036 push ebx 00401037 push esi 00401038 push edi 00401039 lea edi,[ebp - 44h ] 0040103C mov ecx, 11h 00401041 mov eax, 0CCCCCCCCh 00401046 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 ],eax 6 : return sum ; 00401060 mov eax,dword ptr [ebp - 4 ] # 存放返回值 7 : } 00401063 pop edi 00401064 pop esi 00401065 pop ebx 00401066 mov esp,ebp 00401068 pop ebp 00401069 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 7 00401153 push 6 00401155 push 5 00401157 push 4 00401159 push 3 0040115B push 2 0040115D push 1 0040115F 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 ebp 00401081 mov ebp,esp 00401083 sub esp, 44h 00401086 push ebx 00401087 push esi 00401088 push edi 00401089 lea edi,[ebp - 44h ] 0040108C mov ecx, 11h 00401091 mov eax, 0CCCCCCCCh 00401096 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 ],eax 12 : return sum ; 004010B0 mov eax,dword ptr [ebp - 4 ] # 存放返回值 13 : } 004010B3 pop edi 004010B4 pop esi 004010B5 pop ebx 004010B6 mov esp,ebp 004010B8 pop ebp 004010B9 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 7 00401169 push 6 0040116B push 5 0040116D push 4 0040116F push 3 00401171 mov edx, 2 00401176 mov ecx, 1 0040117B 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 ebp 004010D1 mov ebp,esp 004010D3 sub esp, 4Ch 004010D6 push ebx 004010D7 push esi 004010D8 push edi 004010D9 push ecx 004010DA lea edi,[ebp - 4Ch ] 004010DD mov ecx, 13h 004010E2 mov eax, 0CCCCCCCCh 004010E7 rep stos dword ptr [edi] 004010E9 pop ecx 004010EA mov dword ptr [ebp - 8 ],edx 004010ED mov dword ptr [ebp - 4 ],ecx 17 : 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 ],eax 18 : return sum ; 00401108 mov eax,dword ptr [ebp - 0Ch ] # 存放返回值 19 : } 0040110B pop edi 0040110C pop esi 0040110D pop ebx 0040110E mov esp,ebp 00401110 pop ebp 00401111 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 ], 7 00007FF6577A3676 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 7 0040109A push 6 0040109C push 5 0040109E push 4 004010A0 push 3 004010A2 push 2 004010A4 push 1 004010A6 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 ebp 00401021 mov ebp,esp 00401023 sub esp, 48h 00401026 push ebx 00401027 push esi 00401028 push edi 00401029 push ecx 0040102A lea edi,[ebp - 48h ] 0040102D mov ecx, 12h 00401032 mov eax, 0CCCCCCCCh 00401037 rep stos dword ptr [edi] 00401039 pop ecx 0040103A mov dword ptr [ebp - 4 ],ecx 9 : 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 ],eax 10 : return sum ; 00401055 mov eax,dword ptr [ebp - 8 ] # 存放返回值 11 : } 00401058 pop edi 00401059 pop esi 0040105A pop ebx 0040105B mov esp,ebp 0040105D pop ebp 0040105E 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("\n"); break; } printf("%s ",ch); } va_end(list); } int main() { var_test("test","this","is","a","test",""); return 0; }
https://www.cnblogs.com/bettercoder/p/3488299.html