stack frame 栈帧 (激活记录)
1.先要保护现场
2.将参数按照调用约定放在被运行栈帧上,这样这个栈帧的栈顶指针就会发生改变
3.如果有必要,调用函数会配置一个栈指针,保存调用方希望保持不变的内容(寄存器值)
4.被调用函数为它可能需要的任何局部变量分配空间,需要栈帧栈顶向上(-操作)开辟地方
5.被调用函数返回值存放在EAX或者存放在可以立即被调用到的地方
6.一旦函数完成其他操作,任何局部变量都释放了
7.调用地方如果重新获得控制权,删除再栈中开辟的空间(+操作)
8.完成“序言(3,4)”“过程(5,6)”“尾声(6,7)”
C的调用约定_cdecl(参数从右向左依次入栈),清理方式:调用者清理
对于参数可变化的:printf("XXXXX");
VOID demo_cdecl(int w,int x,int y,int z)
asm
push z
push y
push w
push x
call demo(进入了函数,开始执行了。。。。。。)
add esp,16 4*sizeof(int)
汇编测试代码:
ret = cdeclAdd(a, b);
00F51939 mov eax,dword ptr [ebp-24h] ;cdecl
00F5193C push eax ;push b
00F5193D mov ecx,dword ptr [ebp-18h] ;a
00F51940 push ecx ;push a
00F51941 call cdeclAdd (0F5135Ch)
00F51946 add esp,8 ;调用者清理堆栈
00F51949 mov dword ptr [ebp-30h],eax
//cdecl
int __cdecl cdeclAdd(int a, int b)
{
00F51800 push ebp
00F51801 mov ebp,esp
00F51803 sub esp,0C0h
00F51809 push ebx
00F5180A push esi
00F5180B push edi
00F5180C lea edi,[ebp-0C0h]
00F51812 mov ecx,30h
00F51817 mov eax,0CCCCCCCCh
00F5181C rep stos dword ptr es:[edi]
return a + b;
00F5181E mov eax,dword ptr [a]
00F51821 add eax,dword ptr [b]
}
00F51824 pop edi
00F51825 pop esi
00F51826 pop ebx
00F51827 mov esp,ebp
00F51829 pop ebp
00F5182A ret
标准调用_stdcall
VOID demo_stdcall(int w,int x,int y,int z)
push z
push y
push x
push w
call demo(进入了函数,开始执行了。。。。。。)
ret 16
ret = stdAdd(a, b); ;stdcall
00F51929 mov eax,dword ptr [ebp-24h] ;b
00F5192C push eax ;push b
00F5192D mov ecx,dword ptr [ebp-18h] ;a
00F51930 push ecx ;push a
00F51931 call stdAdd (0F5124Eh)
00F51936 mov dword ptr [ebp-30h],eax
// stdcall
int __stdcall stdAdd(int a, int b)
{
00F51880 push ebp
00F51881 mov ebp,esp
00F51883 sub esp,0C0h
00F51889 push ebx
00F5188A push esi
00F5188B push edi
00F5188C lea edi,[ebp-0C0h]
00F51892 mov ecx,30h
00F51897 mov eax,0CCCCCCCCh
00F5189C rep stos dword ptr es:[edi]
return a + b;
00F5189E mov eax,dword ptr [a]
00F518A1 add eax,dword ptr [b]
}
00F518A4 pop edi
00F518A5 pop esi
00F518A6 pop ebx
00F518A7 mov esp,ebp
00F518A9 pop ebp
00F518AA ret 8
快速调用_fastcall
VOID demo_fastcall(int w,int x,int y,int z)
前两个(ECX=W,edx=x)参数将被分配给ECX,EDX
剩下的都被按照_stdcall调用约定
ret 8
ret = fastAdd(a, b);
00F5194C mov edx,dword ptr [ebp-24h] ;mov edx,b
00F5194F mov ecx,dword ptr [ebp-18h] ;mov ecx,a
00F51952 call fastAdd (0F511EAh)
00F51957 mov dword ptr [ebp-30h],eax
//fastcall
int __fastcall fastAdd(int a, int b)
{
00F51840 push ebp
00F51841 mov ebp,esp
00F51843 sub esp,0D8h
00F51849 push ebx
00F5184A push esi
00F5184B push edi
00F5184C push ecx
00F5184D lea edi,[ebp-0D8h]
00F51853 mov ecx,36h
00F51858 mov eax,0CCCCCCCCh
00F5185D rep stos dword ptr es:[edi]
00F5185F pop ecx
00F51860 mov dword ptr [ebp-14h],edx
00F51863 mov dword ptr [ebp-8],ecx
return a + b;
00F51866 mov eax,dword ptr [a]
00F51869 add eax,dword ptr [b]
}
00F5186C pop edi
00F5186D pop esi
00F5186E pop ebx
00F5186F mov esp,ebp
00F51871 pop ebp
00F51872 ret
C++调用约定
使用this指针
VC提供了 thiscall调用,将this传递给而ecx
GC++中被当做静态,存放在栈顶
ret =tt.add(a, b);
00F5195A mov eax,dword ptr [ebp-24h]
00F5195D push eax ;push b
00F5195E mov ecx,dword ptr [ebp-18h]
00F51961 push ecx ;push a
00F51962 lea ecx,[ebp-39h]
00F51965 call thiscallTest::add (0F511E5h)
00F5196A mov dword ptr [ebp-30h],eax
int __thiscall add(int a, int b) {
00F517C0 push ebp
00F517C1 mov ebp,esp
00F517C3 sub esp,0CCh
00F517C9 push ebx
00F517CA push esi
00F517CB push edi
00F517CC push ecx
00F517CD lea edi,[ebp-0CCh]
00F517D3 mov ecx,33h
00F517D8 mov eax,0CCCCCCCCh
00F517DD rep stos dword ptr es:[edi]
00F517DF pop ecx
00F517E0 mov dword ptr [ebp-8],ecx
return a + b;
00F517E3 mov eax,dword ptr [a]
00F517E6 add eax,dword ptr [b]
}
00F517E9 pop edi
00F517EA pop esi
00F517EB pop ebx
00F517EC mov esp,ebp
00F517EE pop ebp
00F517EF ret 8
测试代码:
// InvokeRules.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
// stdcall
int __stdcall stdAdd(int a, int b)
{
return a + b;
}
//cdecl
int __cdecl cdeclAdd(int a, int b)
{
return a + b;
}
//fastcall
int __fastcall fastAdd(int a, int b)
{
return a + b;
}
//thiscall
class thiscallTest
{
public:
thiscallTest() {}
~thiscallTest() {}
int __thiscall add(int a, int b) {
return a + b;
}
};
int main()
{
int a = 10, b = 20;
int ret{ 0 };
thiscallTest tt;
__asm {
mov eax,0x11111
}
ret = stdAdd(a, b);
ret = cdeclAdd(a, b);
ret = fastAdd(a, b);
ret =tt.add(a, b);
__asm {
mov eax,0x11111
}
return 0;
}