[C/C++调用]之 _cdecl 调用约定

函数调用约定


函数调用约定是对函数调用时如何传递参数的一种约定。

内核接口

x86-32系统调用约定:

Linux操作系统使用寄存器传递参数。eax 为 syscall_number , ebx , ecx , edx , esi 和 ebp 用于将6个参数传递给系统调用。返回值保存在eax中。所有其它寄存器(包括FELAGS)都保留在 int 0x80中。

x86-64系统调用约定:

内核接口使用的寄存器有rdi,rsi ,rdx , r10 , r8 , r9 。系统调用通过syscall指令完成。除了rcx , r11 , rax , 其它的寄存器都被保留。系统调用的编号必须在寄存器rax中传递。系统调用的参数限制为6个。不直接从堆栈上传递任何参数。返回时,rax 中包含了系统调用的结果,而且只有INTERGER或者MEMORY类型的值才会被传递给内核。

用户接口

x86-32系统调用约定:

参数通过栈进行传递。最后一个参数入栈,直到所有的参数都被放置完毕,然后执行 call 指令。这也是 Linux 上 C 语言默认的方式。

x86-64系统调用约定:

通过寄存器传递参数,这样做比通过栈具有更高的效率。它避免了内存中参数的存取和额外的指令。根据参数类型的不同,会使用寄存器传参方式。如果参数的类型是 MEMORY,则在栈上传递参数。如果类型是INTERGER,则顺序使用 rdi , rsi , rdx , rcx , r8 , r9。多于 6 个的参数在栈上传递。