fastcall, thiscall, cdecl, stdcall 调用约定

调用约定规定了函数参数如何传递、栈如何管理以及函数调用后栈的清理方式。常见的调用约定包括fastcallthiscallcdeclstdcall,它们在不同平台和架构下的实现方式有所不同。
特别说明,不同cpu,编译器架构调用约定不一样,下面只适用 x86_64 CPU架构 和 MSVC编译器


fastcall

fastcall 是一种优化的调用约定,旨在减少栈操作,加快函数调用的速度。不同平台下的实现差异主要体现在寄存器的使用上。

符号名

  • C: @funcName@paramSize
  • C++: 较为复杂, 一般和C相比funcName变为_Z后面跟函数名长度和函数名, 遍历命名空间和类也是长度加名字, 再跟参数类型, 不需要特别记忆, 导出一般用extern C

32位系统(x86架构)

  • 参数传递: 前两个函数参数通过ECXEDX寄存器传递。
    • 第一个参数传递到ECX
    • 第二个参数传递到EDX
  • 栈传递: 第三个及后续参数通过栈从右到左依次传递。
  • 栈清理: 调用者负责清理栈。

这种方式减少了栈操作,提升了性能,特别适用于传递少量参数的函数调用。

64位系统(x64架构)

在x64架构下,fastcall已成为默认调用约定,优化寄存器的使用:

  • 整数和指针参数传递: 前四个参数分别通过RCXRDXR8R9寄存器传递。
  • 浮点参数传递: 浮点数类型参数通过XMM0XMM3寄存器传递。
  • 栈传递: 超过四个参数则通过栈传递。
  • 栈清理: 被调用者负责清理栈,栈帧必须保持16字节对齐,以支持SSE和AVX指令集。

区别总结

  • 32位: 使用ECXEDX传递前两个参数,栈清理由调用者完成。
  • 64位: 使用RCXRDX等寄存器传递前四个参数,栈清理由被调用者完成,且需要保持16字节对齐。

thiscall

thiscall 是 C++ 类的非静态成员函数的专用调用约定,它用于传递类的this指针。根据不同的系统架构,thiscall的实现有所不同。

符号名

  • C: _funcName
  • C++: 略…

32位系统

  • this传递: this指针通过ECX寄存器传递。
  • 其余参数: 通过栈传递,类似于其他调用约定。

64位系统

  • 标准调用约定: 在64位系统中,不再有单独的thiscall调用约定。this指针会使用标准的寄存器传递,通常是RCX,根据默认的64位调用规则处理。

特性总结

thiscall 是用于非静态成员函数的调用约定,this指针被隐式传递给成员函数。32位系统中使用ECX寄存器传递,而64位系统中则采用统一的调用规则,不再单独定义thiscall


cdecl

cdecl 是C语言和C++中最常见的调用约定,几乎所有函数默认都会使用此约定。

符号名

  • C: _funcName
  • C++: 略…

特性

  • 参数传递: 所有参数通过栈从右到左依次入栈。
  • 栈清理: 调用者负责清理栈。

这是最常见的调用约定,适用于大多数平台和编译器。调用者清理栈使得它在支持可变参数函数(如printf)时表现良好。

示例

1
int __cdecl python_rocks(int one, int two, int three);

对应的汇编代码:
1
2
3
4
5
push three
push two
push one
call python_rocks
add esp, 12

stdcall

stdcall 是 Windows API 的默认调用约定,专为减少函数调用的复杂性设计。

符号名

  • C: _funcName@paramSize
  • C++: 略…

特性

  • 参数传递: 所有参数通过栈从右到左传递。
  • 栈清理: 由被调用者负责清理栈,而非调用者。

stdcall 在 Windows 平台上广泛使用,简化了调用者的责任,使代码更加简洁。

示例

1
int __stdcall python_rocks(int one, int two, int three);

对应的汇编代码:
1
2
3
4
5
6
push three
push two
push one
call python_rocks
;; 被调用者清理栈
ret 12

MSDN x64 ABI 约定概述

具体可以参考MSDN:
在64位系统上,MSDN ABI 调用约定规定了参数通过寄存器传递的方式和栈帧对齐规则。遵循这些规则可提高代码的跨平台兼容性和性能。


总结

调用约定定义了函数调用过程中参数传递和栈管理的方式。在32位和64位系统之间,这些约定存在显著差异。fastcallthiscall在不同平台下的寄存器利用有所不同,cdeclstdcall 则在栈清理方式上有所差异。了解这些约定对编写高效、跨平台的代码至关重要。

You need to set install_url to use ShareThis. Please set it in _config.yml.