函数调用协议

_stdcall、_cdecl、_fastcall 三种函数调用协议区别

调用协议的常用场合如下:

  • _stdcall: Windows API 默认的函数调用协议
  • _cdecl: C/C++ 默认的函数调用协议
  • _fastcall: 适用于对性能要求较高的场合

函数参数的入栈方式包含如下几种:

  • _stdcall: 函数参数从右向左入栈
  • _cdecl: 函数参数从右向左入栈
  • _fastcall: 从左开始将不大于4字节的参数放入CPU的ecx和edx寄存器,其余参数从右向左入栈。

栈平衡的修复方式包含以下几种:

  • _stdcall: 函数调用结束后由被调用函数来平衡栈。
  • _cdecl: 函数调用结束后由函数调用者来平衡栈。
  • _fastcall: 函数调用结束后由被调用函数来平衡栈

对于Linux 程序来说,通常采用_cdecl的调用方式

对于 x86 程序:

  • 普通函数传参:参数基本都压在栈上
  • syscall 传参:eax 对应系统调用号,ebx、ecx、edx、esi、edi、ebp 分别对应前6个参数。多余的参数压在栈上

对于 x64 程序:

  • 普通函数传参:先使用rdi、rsi、rdx、rcx、r8、r9 寄存器作为函数参数的前6个参数,多余的参数会依次压在栈上。
  • syscall传参:rax 对应系统调用号,传参规则与函数传参一致。

说明:

  • 调用者 ------- 调用函数的一方
  • 被调用者 ------- 被调用的函数
  • 比如在main函数中调用 printf()函数时,调用者为main(),被调用者为 printf()。

例子
cdecl是主要在C语言中使用的方式,调用者负责处理栈。

#include "stdio.h"
int add(int a,int b)
{
	return (a+b);
}

int main(int argc,char* argv[])
{
	return add(1,2);
}

在这里插入图片描述
add() 函数的参数1、2以逆序方式入栈,调用add()函数后,使用ADD ESP,8 命令整理栈。调用者main()函数直接清理其压入栈的函数参数。

stdcall方式常用于Win 32API,该方式由被调用者清理栈。前面讲解过C语言默认的函数调用方式为cdecl。若想使用stdcall方式编译源码,只要使用_stdcall关键字即可。

#include "stdio.h"
int _stdcall add(int a,int b)
{
	return (a+b);
}

int main(int argc,char* argv[])
{
	return add(1,2);
}

在这里插入图片描述

在main()函数中调用add()函数后,省略了清理栈的代码(ADD ESP,8)
栈的清理工作由add()函数中最后的RETN 8命令来执行。RETN 8命令的含义为RETN+POP8字节,即返回后使ESP增加到指定大小

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值