VC6.0++函数调用方式有三种:
分别为:
1._stdcall 方式
int _stdcall add1(int i,int j)
{
cout<<"_stdcall out"<<endl;
return i+j;
}
0040158F CC INT3 ; _stdcall 被调方平衡栈
00401590 > > 55 PUSH EBP
00401591 . 8BEC MOV EBP,ESP
00401593 . 83EC 40 SUB ESP,40
00401596 . 53 PUSH EBX
00401597 . 56 PUSH ESI
00401598 . 57 PUSH EDI
00401599 . 8D7D C0 LEA EDI,DWORD PTR SS:[EBP-40]
0040159C . B9 10000000 MOV ECX,10
004015A1 . B8 CCCCCCCC MOV EAX,CCCCCCCC
004015A6 . F3:AB REP STOS DWORD PTR ES:[EDI]
004015A8 . 68 CD104000 PUSH testcall.004010CD
004015AD . 68 1C004700 PUSH OFFSET testcall.??_C@_0N@HMEN@_stdc>; _stdcall out
004015B2 . 68 A0DE4700 PUSH OFFSET testcall.std::cout
004015B7 . E8 D8FCFFFF CALL testcall.00401294
004015BC . 83C4 08 ADD ESP,8
004015BF . 8BC8 MOV ECX,EAX
004015C1 . E8 24FCFFFF CALL testcall.004011EA
004015C6 . 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
004015C9 . 0345 0C ADD EAX,DWORD PTR SS:[EBP+C]
004015CC . 5F POP EDI
004015CD . 5E POP ESI
004015CE . 5B POP EBX
004015CF . 83C4 40 ADD ESP,40
004015D2 . 3BEC CMP EBP,ESP
004015D4 . E8 D7F50100 CALL testcall.__chkesp
004015D9 . 8BE5 MOV ESP,EBP
004015DB . 5D POP EBP
004015DC . C2 0800 RETN 8
004015DF CC INT3
以上为DEBUG反汇编源码:
2._fastcall 方式
int _fastcall add2(int i, int j)
{
cout<<"_fastcall out"<<endl;
return i+j;
}
004015FF CC INT3 ; _fastcall 被调方 平衡栈
00401600 > > 55 PUSH EBP
00401601 . 8BEC MOV EBP,ESP
00401603 . 83EC 48 SUB ESP,48
00401606 . 53 PUSH EBX
00401607 . 56 PUSH ESI
00401608 . 57 PUSH EDI
00401609 . 51 PUSH ECX
0040160A . 8D7D B8 LEA EDI,DWORD PTR SS:[EBP-48]
0040160D . B9 12000000 MOV ECX,12
00401612 . B8 CCCCCCCC MOV EAX,CCCCCCCC
00401617 . F3:AB REP STOS DWORD PTR ES:[EDI]
00401619 . 59 POP ECX
0040161A . 8955 F8 MOV DWORD PTR SS:[EBP-8],EDX
0040161D . 894D FC MOV DWORD PTR SS:[EBP-4],ECX
00401620 . 68 CD104000 PUSH testcall.004010CD
00401625 . 68 2C004700 PUSH OFFSET testcall.??_C@_0O@JLOO@_fast>; _fastcall out
0040162A . 68 A0DE4700 PUSH OFFSET testcall.std::cout
0040162F . E8 60FCFFFF CALL testcall.00401294
00401634 . 83C4 08 ADD ESP,8
00401637 . 8BC8 MOV ECX,EAX
00401639 . E8 ACFBFFFF CALL testcall.004011EA
0040163E . 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00401641 . 0345 F8 ADD EAX,DWORD PTR SS:[EBP-8]
00401644 . 5F POP EDI
00401645 . 5E POP ESI
00401646 . 5B POP EBX
00401647 . 83C4 48 ADD ESP,48
0040164A . 3BEC CMP EBP,ESP
0040164C . E8 5FF50100 CALL testcall.__chkesp
00401651 . 8BE5 MOV ESP,EBP
00401653 . 5D POP EBP
00401654 . C3 RETN
以上为对应的DEBUG反汇编源码
3.cdecl 方式
int _cdecl add3(int i,int j)
{
cout<<"_cdecl out"<<endl;
return i+j;
}
00401670 > > \55 PUSH EBP ; 保存栈底指针EBP
00401671 . 8BEC MOV EBP,ESP ; 调整当前栈底指针位置到栈顶
00401673 . 83EC 40 SUB ESP,40 ; 开辟栈空间 作为局部变量的存储空间
00401676 . 53 PUSH EBX ; 保存EBX寄存器
00401677 . 56 PUSH ESI ; 保存ESI寄存器
00401678 . 57 PUSH EDI ; 保存EDI寄存器
00401679 . 8D7D C0 LEA EDI,DWORD PTR SS:[EBP-40] ; 取出此函数 可用栈空间首地址
0040167C . B9 10000000 MOV ECX,10
00401681 . B8 CCCCCCCC MOV EAX,CCCCCCCC
00401686 . F3:AB REP STOS DWORD PTR ES:[EDI]
00401688 . 68 CD104000 PUSH testcall.004010CD
0040168D . 68 3C004700 PUSH OFFSET testcall.??_C@_0L@INPI@_cdec>; _cdecl out
00401692 . 68 A0DE4700 PUSH OFFSET testcall.std::cout
00401697 . E8 F8FBFFFF CALL testcall.00401294
0040169C . 83C4 08 ADD ESP,8
0040169F . 8BC8 MOV ECX,EAX
004016A1 . E8 44FBFFFF CALL testcall.004011EA
004016A6 . 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; 将EBP+8 处值 传送到EAX中
004016A9 . 0345 0C ADD EAX,DWORD PTR SS:[EBP+C] ; 将EBP+C 处值与EAX值 相加
004016AC . 5F POP EDI ; 还原EDI 寄存器
004016AD . 5E POP ESI ; 还原ESI寄存器
004016AE . 5B POP EBX ; 还原EBX寄存器
004016AF . 83C4 40 ADD ESP,40 ; 降低栈顶,此时局部变量空间被释放
004016B2 . 3BEC CMP EBP,ESP ; 检测栈平衡
004016B4 . E8 F7F40100 CALL testcall.__chkesp ; 进入栈平衡错误检测函数
004016B9 . 8BE5 MOV ESP,EBP ; 还原ESP
004016BB . 5D POP EBP
004016BC . C3 RETN
以上为对应的DEBUG反汇编源码解释。
小结:
1.默认采用_cdecl方式。
2._fastcall方式 只是前两个参数用寄存器传递,后面的都采用栈传参方式。