概述
__cdecl约定
C/C++中缺省调用约定
int add(int a, int b)
{
00D91002 in al,dx
00D91003 push ecx
int c = a + b;
00D91004 mov eax,dword ptr [a]
00D91007 add eax,dword ptr [b]
00D9100A mov dword ptr [c],eax
return c;
00D9100D mov eax,dword ptr [c]
}
int main()
{
00D91020 push ebp
00D91021 mov ebp,esp
add(3, 4);
00D91023 push 4
00D91025 push 3
00D91027 call add (0D91000h)
00D9102C add esp,8 //恢复栈平衡
}
参数从右到左入栈,在函数外恢复栈平衡,返回值在EAX中
由于由调用者平衡栈,所以允许可变参数函数存在
__stdcall约定
常见于WINAPI中
int __stdcall add(int a, int b)
{
00641002 in al,dx
00641003 push ecx
int c = a + b;
00641004 mov eax,dword ptr [a]
00641007 add eax,dword ptr [b]
0064100A mov dword ptr [c],eax
return c;
0064100D mov eax,dword ptr [c]
}
00641010 mov esp,ebp
00641012 pop ebp
00641013 ret 8//恢复栈平衡
int main()
{
00641020 push ebp
00641021 mov ebp,esp
add(3, 4);
00641023 push 4
00641025 push 3
00641027 call add (0641000h)
}
参数入栈方式与__cdecl相同;不同于__cdecl,由函数恢复栈平衡;返回值在eax中
__thiscall约定
C++中用于调用成员函数
class Math
{
public:
int add(int a, int b)
{
002E1002 in al,dx
002E1003 sub esp,8
002E1006 mov dword ptr [ebp-8],ecx
int c = a + b;
002E1009 mov eax,dword ptr [ebp+8]
002E100C add eax,dword ptr [ebp+0Ch]
002E100F mov dword ptr [ebp-4],eax
return c;
002E1012 mov eax,dword ptr [ebp-4]
}
002E1015 mov esp,ebp
002E1017 pop ebp
002E1018 ret 8
int main()
{
002E1020 push ebp
002E1021 mov ebp,esp
002E1023 sub esp,8
002E1026 mov eax,dword ptr ds:[002E3000h]
002E102B xor eax,ebp
002E102D mov dword ptr [ebp-4],eax
Math math;
math.add(3, 4);
002E1030 push 4
002E1032 push 3
002E1034 lea ecx,[ebp-5]
002E1037 call 002E1000
}
与__stdcall相同,由函数自身恢复栈平衡;
从右向左将参数传入栈中,ecx保存类的指针
__fastcall约定
调用成员函数时
class Math
{
public:
int __fastcall add(int a, int b)
{
00501002 in al,dx
00501003 sub esp,0Ch
00501006 mov dword ptr [ebp-4],edx
00501009 mov dword ptr [ebp-0Ch],ecx
int c = a + b;
0050100C mov eax,dword ptr [ebp-4]
0050100F add eax,dword ptr [ebp+8]
00501012 mov dword ptr [ebp-8],eax
return c;
00501015 mov eax,dword ptr [ebp-8]
}
00501018 mov esp,ebp
0050101A pop ebp
0050101B ret 4
int main()
{
00501020 push ebp
00501021 mov ebp,esp
00501023 sub esp,8
00501026 mov eax,dword ptr ds:[00503000h]
0050102B xor eax,ebp
0050102D mov dword ptr [ebp-4],eax
Math math;
math.add(3, 4);
00501030 push 4
00501032 mov edx,3
00501037 lea ecx,[ebp-5]
0050103A call 00501000
}
调用普通函数时
int __fastcall add(int a, int b)
{
00391002 in al,dx
00391003 sub esp,0Ch
00391006 mov dword ptr [ebp-8],edx
00391009 mov dword ptr [ebp-4],ecx
int c = a + b;
0039100C mov eax,dword ptr [ebp-4]
0039100F add eax,dword ptr [ebp-8]
00391012 mov dword ptr [ebp-0Ch],eax
return c;
00391015 mov eax,dword ptr [ebp-0Ch]
}
00391018 mov esp,ebp
0039101A pop ebp
0039101B ret
int main()
{
00391020 push ebp
00391021 mov ebp,esp
add(3, 4);
00391023 mov edx,4
00391028 mov ecx,3
0039102D call 00391000
}
优先使用寄存器ECX和EDX传送前两个DWORD或更小参数,节省push操作,因此速度较快
其他约定
___naked
naked是一个很少见的调用约定,一般不建议使用。编译器不会给这种函数增加初始化和清理代码,更特殊的是你不能用return返回返回值,只能用插入汇编返回结果,此调用约定必须跟_declspec同时使用。例如定义一个求和程序,如:_declspec (naked) int add(int a,int b) ;
___pascal
这是pascal语言的调用约定,跟_stdcall一样,参数按照从右至左的方式入栈,函数自身清理堆栈,返回值在EAX中。VS 中已经废弃了这种调用方式.
最后
以上就是明亮柠檬为你收集整理的C/C++函数调用约定(基于X86架构下)的全部内容,希望文章能够帮你解决C/C++函数调用约定(基于X86架构下)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复