win32-C++调用约定
1. __cdecl调用约定
c++代码:
int __cdecl Function(int x, int y) { return x + y; } int main() { Function(2, 3); }
汇编代码:
00251881 push 3 00251883 push 2 00251885 call Function (02513DEh) 0025188A add esp,8
通过汇编代码可以看到__cdecl调用约定是通过从右向左压栈将参数压入堆栈中,最后进行外平栈,将堆栈平衡。
2.__stdcall调用约定
c++代码:
int __stdcall Function(int x, int y) { return x + y; } int main() { Function(2, 3); }
汇编代码:
00F01881 push 3 00F01883 push 2 00F01885 call Function (0F013E3h)
int __stdcall Function(int x, int y) { 00F01790 push ebp 00F01791 mov ebp,esp 00F01793 sub esp,0C0h 00F01799 push ebx 00F0179A push esi 00F0179B push edi 00F0179C mov edi,ebp 00F0179E xor ecx,ecx 00F017A0 mov eax,0CCCCCCCCh 00F017A5 rep stos dword ptr es:[edi] 00F017A7 mov ecx,offset _6235DE03_Practice@cpp (0F0C068h) 00F017AC call @__CheckForDebuggerJustMyCode@4 (0F0132Ah) return x + y; 00F017B1 mov eax,dword ptr [x] 00F017B4 add eax,dword ptr [y] } 00F017B7 pop edi 00F017B8 pop esi 00F017B9 pop ebx 00F017BA add esp,0C0h 00F017C0 cmp ebp,esp 00F017C2 call __RTC_CheckEsp (0F01249h) 00F017C7 mov esp,ebp 00F017C9 pop ebp 00F017CA ret 8
通过汇编代码我们可以看到stdcall调用约定和cdecl调用约定的入参方式是相同的,都是从右到左将参数压栈,但是在最后进行堆栈平衡的时候,stdcall是通过内平衡的方式。
3.__fastcall调用约定
c++代码:
int __fastcall Function(int x, int y) { return x + y; } int main() { Function(2, 3); }
汇编代码:
00531881 mov edx,3 00531886 mov ecx,2 0053188B call Function (05313E8h)
通过汇编代码我们可以看到__fastcall传递参数的方式是通过edx和ecx寄存器进行传递,从而不需要进行堆栈平衡,那如果我们的参数超过两个呢,再来看看,这次我们传递四个参数
c++代码:
int __fastcall Function(int x, int y, int z, int k) { return x + y + z + k; } int main() { Function(2, 3,4,5); }
汇编代码:
00D41881 push 5 00D41883 push 4 00D41885 mov edx,3 00D4188A mov ecx,2 00D4188F call Function (0D413EDh)
int __fastcall Function(int x, int y, int z, int k) { 00D41790 push ebp 00D41791 mov ebp,esp 00D41793 sub esp,0D8h 00D41799 push ebx 00D4179A push esi 00D4179B push edi 00D4179C push ecx 00D4179D lea edi,[ebp-18h] 00D417A0 mov ecx,6 00D417A5 mov eax,0CCCCCCCCh 00D417AA rep stos dword ptr es:[edi] 00D417AC pop ecx 00D417AD mov dword ptr [y],edx 00D417B0 mov dword ptr [x],ecx 00D417B3 mov ecx,offset _6235DE03_Practice@cpp (0D4C068h) 00D417B8 call @__CheckForDebuggerJustMyCode@4 (0D4132Ah) return x + y + z + k; 00D417BD mov eax,dword ptr [x] 00D417C0 add eax,dword ptr [y] 00D417C3 add eax,dword ptr [z] 00D417C6 add eax,dword ptr [k] } 00D417C9 pop edi 00D417CA pop esi 00D417CB pop ebx 00D417CC add esp,0D8h 00D417D2 cmp ebp,esp 00D417D4 call __RTC_CheckEsp (0D41249h) 00D417D9 mov esp,ebp 00D417DB pop ebp 00D417DC ret 8
我们可以看到参数是从左到右的方式进行压栈,最后两个参数的时候是通过寄存器进行传递,平衡堆栈的方式是通过内平栈的方式。
以上就是__cdecl,__stdcall,__fastcall三种不同调用约定的区别。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧