🗒️函数调用约定
type
status
date
slug
summary
tags
category
icon
password
BG
高级语言的函数编译成机器码的时候,存在一个潜在问题:CPU没办法知道一个函数调用需要多少个、什么样的参数。为此,计算机提供了栈来支持参数的传递。这样,在函数调用的时候,先将参数压栈,然后CALL,函数里在从堆栈获取数据。
而在参数传递的时候,有两个问题需要明确说明:
- 当参数个数大于1的时候,按照什么顺序压入堆栈
- 函数调用后,由谁恢复堆栈
- 函数的返回值放在哪
因此,引入函数调用规范。
Calling Conventions
stdcall
cdecl
fastcall
thiscall
nakedcall
stdcall
- 参数从右向左压入堆栈
- 函数自身修改堆栈
- 函数的装饰名(decoration name/mangling name)为函数名自动加前导的下划线, 后面紧跟一个@符号, 其后紧跟着参数的尺寸
cdecl
cdecl调用约定又称为C调用约定, 是C语言缺省的调用约定, 它的定义语法是:
cdecl调用约定的特点如下:
- 参数从右向左压入堆栈
- 由调用者恢复堆栈,这使得cdecl调用约定可以支持变参函数
- 函数的装饰名以下划线开头,后面紧跟着函数名
fastcall
fastcall调用约定是为了提高函数调用效率而设计的,它的定义语法是:
fastcall调用约定的特点如下:
- 前两个DWORD类型或者更小的参数放入寄存器ECX和EDX中,其他参数从右向左压入堆栈
- 函数自身修改堆栈
- 函数的装饰名以@开头,后面紧跟着函数名,然后是@和参数的尺寸
thiscall
thiscall调用约定是C++成员函数缺省的调用约定,它的定义语法是:
thiscall调用约定的特点如下:
- ECX寄存器存放着this指针
- 参数从右向左压入堆栈
- 函数自身清理堆栈
nakedcall
nakedcall调用约定是一种特殊的调用约定,它允许程序员完全控制函数的序言和结尾代码。它的定义语法是:
nakedcall调用约定的特点如下:
- 编译器不会生成任何函数的序言和结尾代码
- 程序员必须自己编写所有的汇编代码,包括参数的获取和堆栈的维护
- 通常用于编写底层的系统代码或驱动程序
总结
- 函数调用约定定义了参数传递顺序、堆栈恢复方式和返回值位置等规则
stdcall
:参数从右向左入栈,函数自身清理堆栈
cdecl
:参数从右向左入栈,调用者清理堆栈,支持变参
fastcall
:首两个参数使用寄存器传递,提高效率
thiscall
:C++成员函数默认约定,ECX存放this指针
nakedcall
:完全由程序员控制函数代码生成,用于底层编程