1.调用约定分类
当结合之前提供的信息和 fastcall 调用约定时,更新后的表格如下所示:
| 平台/架构 | Windows | Linux | macOS | 其他 |
|---|---|---|---|---|
| x86 (32位) | _stdcall, _cdecl, _fastcall | _cdecl, _stdcall | _cdecl | |
| x86-64 (64位) | Microsoft x64 | System V AMD64 ABI | System V AMD64 ABI | |
| ARM | Microsoft ARM | AAPCS | AAPCS | |
| PowerPC | Microsoft PowerPC | System V PowerPC |
需要注意的是,调用约定是与编译器和操作系统密切相关的,而不是与硬件架构直接相关的。因此,不同的编译器和操作系统可能对调用约定有所调整或扩展,以满足特定的需求。在编写跨平台的代码时,要特别注意调用约定的差异,避免因此导致的函数调用错误和栈不平衡问题。在使用特定的调用约定时,最好明确指定,并避免依赖默认的调用约定,以确保代码的正确性和可移植性。
2.举例
下面是在32位 windows下的一段c语言代码。
//cdecl
int _stdcall print1(int a,int b,int c,int d) {
return a + b + c+d;
}
int _fastcall get(int a, int b,int c,int d) {
return a & b & c & d;
}
int main()
{
int b = get(1,2,3,4);
return 0;
}
使用windows调试器转汇编运行起来看一看到。 main函数。
int b = get(1,2,3,4);
007517B5 push 4
007517B7 push 3
007517B9 mov edx,2
007517BE mov ecx,1
007517C3 call get (07513D4h)
007517C8 mov dword ptr [b],eax
return 0;
007517CB xor eax,eax
}
007517CD pop edi
007517CE pop esi
007517CF pop ebx
007517D0 add esp,0CCh
007517D6 cmp ebp,esp
007517D8 call __RTC_CheckEsp (075123Fh)
007517DD mov esp,ebp
007517DF pop ebp
007517E0 ret
可以看到。
- 参数1,2,3,4。其中后两个采用栈传参,从右开始的。前两个参数采用寄存器传参的方式。寄存器ecx和edx是第一个和第二个参数。
- 参数入栈,这里没有平栈,那么是使用的内平栈方式。
get函数。
int _fastcall get(int a, int b,int c,int d) {
00751E00 push ebp
00751E01 mov ebp,esp
00751E03 sub esp,0D8h
00751E09 push ebx
00751E0A push esi
00751E0B push edi
00751E0C push ecx
00751E0D lea edi,[ebp-18h]
00751E10 mov ecx,6
00751E15 mov eax,0CCCCCCCCh
00751E1A rep stos dword ptr es:[edi]
00751E1C pop ecx
00751E1D mov dword ptr [b],edx
00751E20 mov dword ptr [a],ecx
00751E23 mov ecx,offset _7535E707_ConsoleApplication3@cpp (075C000h)
00751E28 call @__CheckForDebuggerJustMyCode@4 (075131Bh)
return a & b & c & d;
00751E2D mov eax,dword ptr [a]
00751E30 and eax,dword ptr [b]
00751E33 and eax,dword ptr [c]
00751E36 and eax,dword ptr [d]
}
00751E39 pop edi
00751E3A pop esi
00751E3B pop ebx
00751E3C add esp,0D8h
00751E42 cmp ebp,esp
00751E44 call __RTC_CheckEsp (075123Fh)
00751E49 mov esp,ebp
00751E4B pop ebp
00751E4C ret 8
14.15行是取参数a,b。 最后ret 8进行平栈。