鱼C论坛

 找回密码
 立即注册
查看: 1971|回复: 0

[技术交流] 对四种调用约定的一些理解和不解

[复制链接]
发表于 2018-8-24 15:50:42 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 代号3 于 2018-8-24 15:48 编辑


本贴中依次测验不加关键字的VS编译器默认C++调用  __cdecl调用 __stdcall调用 __fastcall调用 __thiscall调用 共4种函数调用约定 6次实验
首先测验不加关键词情况下的默认函数调用
  1. #include "stdafx.h"
  2. int  fun(int num1, int num2)
  3. {
  4.         return printf("%d\n", num1 + num2);
  5. }

  6. int main()
  7. {
  8.         fun(3, 4);
  9.     return 0;
  10. }
复制代码

        在main函数出设置断点 修改VS链接器设置 如下图
QQ截图20180823144543.png
        F10单步调试 ALT+8调出反汇编窗口记录mian函数基址如下图
QQ截图20180823144851.png
然后进入OD中 Ctrl+G输入main函数基址 在入口处右键设置新的EIP F8单步开始测试函数调用堆栈 在CALL出F7步入函数观察堆栈变化
aaa4d31b-8904-41e8-9913-501daa4b3731.png
可以观察到默认调用中main函数通过ADD ESP的方式对函数进行堆栈平衡 并可以推测函数中调用参数为2个  同样在__cdcel调用中依然如此
  1. #include "stdafx.h"
  2. int __cdecl fun(int num1, int num2)
  3. {
  4.         return num1 + num2;
  5. }

  6. int main()
  7. {
  8.         fun(3, 4);
  9.     return 0;
  10. }
复制代码

cdcel.png
继续对stdcall调用进行实验,代码如下
  1. #include "stdafx.h"
  2. int __stdcall fun(int num1, int num2)
  3. {
  4.         return num1 + num2;
  5. }

  6. int main()
  7. {
  8.         fun(3, 5);
  9.     return 0;
  10. }
复制代码

进入OD进行观察 如下
stdcall.png
可以观察到此时main函数不在使用ADD ESP的方式对函数调用后的堆栈进行平衡
在进入fun函数前的堆栈指针如下

std进入fun

std进入fun

fun函数结束的时候如下

stdfun结束

stdfun结束

可以观察到 进入前和进入后的ESP相差4 原因是因为在进入CALL的时候经过了一次JMP

JMP

JMP

同理可以推知 在进行RETN的时候也是默认进行了一次JMP
所以main函数结束的时候堆栈仍然平衡 如图

std main结束

std main结束

小结:stdcall调用函数的时候 参数入栈顺序从右往左依次入栈 函数堆栈由函数自身通过RET平衡 mian函数调用者不对其进行平衡

        对fastcall函数的实验
  1. #include "stdafx.h"
  2. int __fastcall fun(int num1, int num2)
  3. {
  4.         return num1 + num2;
  5. }

  6. int main()
  7. {
  8.         fun(100, 12);
  9.     return 0;
  10. }
复制代码

[attachimg]
只有2个参数的时候
fast2参1.png
可以观察到在main函数中仍然不对函数进行堆栈平衡,由函数自行平衡。且在函数参数存储的时候使用了EDX 和ECX寄存器进行存储参数
fast2参2.png
        在fun函数运算的时候 将ECX的值入栈,然后和EDX存入的值一起置入局部变量区存储使用

  1. #include "stdafx.h"

  2. int __fastcall fun(int num1, int num2, int num3, int num4)
  3. {
  4.         return num1 + num2 + num3 + num4;
  5. }

  6. int main()
  7. {
  8.         fun(100, 12, 10, 11);
  9.         return 0;
  10. }
复制代码


        在进行超过2个参数传入的时候 如下图



        顺序仍然是从右往左传参 但默认保留第一个和第二个参数传入ECX EDX中

        小结:fastcall调用约定特征 参数从右往左入栈 默认保留前2个存入EDX和ECX中  函数堆栈由自身平衡

对thiscall调用的一些疑问
  1. #include "stdafx.h"
  2. class ThisCall
  3. {
  4. public:
  5.         int Thiscall(int num1, int num3, int num4)
  6.         {
  7.                 return num1 + num4 + num3;
  8.         }
  9. };

  10. int main()
  11. {
  12.         ThisCall A;
  13.         A.Thiscall(3, 4, 5);
  14.    
复制代码

Thiscall的一些理解.png thiscall fun函数.png
在汇编中 类的封装性是如何被实现或者破坏的?
汇编中ECX对类中this指针是如何使用的? 与C++中的相同之处有哪些?

fast多参存值堆栈展示.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-1 19:25

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表