首先写好各类函数的c++程序
#include<iostream>
using namespace std;
int __stdcall __stdcall_add(int a,int b)
{
return a + b;
}
int _cdecl cdecl_add(int a, int b)
{
return a + b;
}
int __fastcall __fastcall_add(int a, int b, int c)
{
return a + b + c;
}
class MyClass
{
public:
MyClass();
MyClass(int a)
{
m = a;
}
~MyClass();
int thiscall_add(int a, int b)
{
return m + a + b;
}
int m;
};
MyClass::MyClass()
{
}
MyClass::~MyClass()
{
}
int result = 0;
int main()
{
MyClass *a = new MyClass(1);
while (true)
{
result = __stdcall_add(result, 2);
cout << result << endl;
system("pause");
result = cdecl_add(result, 2);
cout << result << endl;
system("pause");
result = __fastcall_add(result, 2, 3);
cout << result << endl;
system("pause");
result = a->thiscall_add(result, 2);
cout << result << endl;
system("pause");
}
}
编译生成好用CE逐帧分析。
__stdcall
result = __stdcall_add(result, 2);
对应的汇编代码为:
参数又右向左入栈。
int __stdcall __stdcall_add(int a,int b)
{
return a + b;
}
对应的汇编代码:
去除一些编译器生成的和咱写的程序无关的汇编代码:
其中ebp是栈底指针,ebp+8很明显是指向之前push进去的result的地址。ebp+0c就是之前push进去的2的地址。然后eax作为函数返回值。
最后ret 8表示由函数自身恢复栈平衡。
_cdecl
result = cdecl_add(result, 2);
对应的汇编代码:
这里可以看到比之前的__stdcall多了add esp 08,相当于__stdcall里的ret 08,这表明由调用者恢复栈平衡。esp是栈顶指针。其他的和__stdcall一致。
int _cdecl cdecl_add(int a, int b)
{
return a + b;
}
对应的汇编代码:
与__stdcall基本一致,ret 8 变ret.
__fastcall
result = __fastcall_add(result, 2, 3);
用edx,ecx传参。
int __fastcall __fastcall_add(int a, int b, int c)
{
return a + b + c;
}
先把参数放在edx,ecx里面,然后移入栈中操作。
最后是和stdcall一样由函数体恢复栈平衡。
thiscall
result = a->thiscall_add(result, 2);
result和2这两个参数和之前一样的方式入栈,然后this指针是传入ecx的。
int thiscall_add(int a, int b)
{
return m + a + b;
}
总结
- 传参都是由右向左入栈,其中fastcall前两个参数进入edx,ecx寄存器,thiscall的this指针入ecx寄存器。
- 只有_cdecl是由调用者恢复栈平衡,其他都是由函数体恢复栈平衡。