常见的函数调用约定

常见的几种函数调用约定

C语言代码示例

1
2
3
4
int test(int x, int y, int z);
int a, b, c, ret;

ret = test(a, b, c);

cdecl

  • 常用场合:C/C++语言中的缺省函数调用约定

  • 由调用者维护栈

  • 支持不确定的参数个数

  • 代码示例:

    1
    2
    3
    4
    5
    6
    push c
    push b
    push a
    call test
    add esp, 12
    mov ret, eax
    • 在第5行,栈是由调用者清理的

stdcall

  • 常用场合:Windows给Win32平台定义的函数调用约定

  • 由被调用函数负责调用后栈的恢复,因为这些被调用函数是WinAPI,清理栈的责任由实现API函数代码的DLL程序承担

  • 参数个数必须确定

  • 比cdecl的调用方式效率稍微高一些

  • 代码示例:

    1
    2
    3
    4
    5
    push c
    push b
    push a
    call test
    mov ret, eax
    • 与上面不同,调用者不需要清理栈

fastcall

  • 常用场合:适用于性能要求较高的场合

  • 采用寄存器传参,运算速度更快

  • 如果参数过多,会有一部分参数通过栈传递

  • 被调用的函数在返回前清理传送参数的内存栈

  • Win32平台参数入栈方式:

    • 前2个参数从左到右采用ECX,EDX传递,其余参数从右到左使用栈传递
  • Win64平台参数入栈方式:

    • 前4个参数采用RCX、RDX、R8、R9传递,其余参数采用栈传递
    • 如果有this指针,则this指针通过RCX作为第一个参数传递
  • Linux-64bit平台参数入栈方式:

    • 前6个参数采用RDI、RSI、RDX、RCX、R8、R9传递,其余参数采用栈传递
  • Win32平台代码示例:

    1
    2
    3
    4
    5
    push c
    mov edx, b
    mov ecx, a
    call test
    mov ret, eax

参考