c语言函数调用约定与汇编实现

279 阅读3分钟

1.调用约定分类

当结合之前提供的信息和 fastcall 调用约定时,更新后的表格如下所示:

平台/架构WindowsLinuxmacOS其他
x86 (32位)_stdcall, _cdecl, _fastcall_cdecl, _stdcall_cdecl
x86-64 (64位)Microsoft x64System V AMD64 ABISystem V AMD64 ABI
ARMMicrosoft ARMAAPCSAAPCS
PowerPCMicrosoft PowerPCSystem 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. 参数1,2,3,4。其中后两个采用栈传参,从右开始的。前两个参数采用寄存器传参的方式。寄存器ecx和edx是第一个和第二个参数。
  2. 参数入栈,这里没有平栈,那么是使用的内平栈方式。

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进行平栈。