,,__stdcall 和 __cdecl 的区别浅析

,,__stdcall 和 __cdecl 的区别浅析

__stdcall与__cdecl的区别分析。有需要的朋友可以参考一下。

1.__cdecl__cdecl是C声明的缩写,表示C语言默认的函数调用方法:所有参数从右到左堆栈,调用者负责将参数推入堆栈,最后调用者负责清空堆栈的内容。一般来说,这是C/C调用函数的默认规则。这是MS编译器采用的规则。2.__stdcall_stdcall是StandardCall的缩写,是C的标准调用方法:所有参数从右向左堆栈,调用者负责将参数推入堆栈,最后被调用者负责清空堆栈的内容。Windows API采用的函数调用规则就是这个规则。

另外__cdecl和__stdcall规则不同的函数生成的修改名也不同。相同点是生成函数的修改名前缀加下划线,不同点是后缀。当然,两者最大的区别是栈的还原方式不同,这也是最重要的一点。

__cdecl规则要求调用方自己负责堆栈的恢复。从汇编的角度来看,恢复堆栈的位置在调用函数内。考虑这样一段C代码(VC下调试)复制代码如下:#include cstdio

void __cdecl func(int param1,int param2,int param 3){ int var 1=param 1;int var2=param2int var3=param3

printf('%ld\n ',long(param 1));printf('%ld\n ',long(param 2));printf('%ld\n ',long(param 3));printf('-\ n ');printf('%ld\n ',long(var 1));printf('%ld\n ',long(var 2));printf('%ld\n ',long(var 3));返回;}

int main() { func(1,2,3);返回0;}注意func函数是用__cdecl修饰的(实际上并不需要,因为VC下的默认规则是__cdecl,这里为了清楚起见),生成的汇编代码如下:

复制代码如下:3: void _ _ cdeclfunc (intparam1,intparam2,int param 3){ 00401020 push ebp 00401021 move BP,esp 00401023subesp,4Ch 00401026 push ebx 00401027 push ESI 00401028 push EDI 00401029 lea EDI,[ebp-4Ch]0040102C mov ecx,13h 00000401038 mov eax,dword ptr[ebp 8]0040103 b mov dword ptr[ebp-4],eax;注意var1,var2,var3压入堆栈的顺序!5:int var 2=param 2;0040103E mov ecx,dword ptr[ebp 0Ch]00401041 mov dword ptr[ebp-8],ecx 6:int var 3=param 3;00401044 mov edx,dword ptr [ebp 10h]

......省略printf的代码。

15:返回;16:} 004010 BD pop EDI 004010 be pop ESI 004010 BF pop ebx 004010 c 0 add esp,4Ch004010C3 cmp ebp,esp 004010 c 5 call _ _ chk esp(004011d 0)004010 ca mov esp,ebp 004010 cc pop ebp 004010 CD ret;这里是ret,调用者(main)还原堆栈,但是如果是__stdcall,这是堆栈恢复的地方。

*******************************************************************************************************************

18: int main() {

......构建堆栈的代码被省略了。

19: func(1,2,3);00401118推3;将param3推入堆栈0040111 a push 2;将param2推入堆栈0040111 c push 1;将param1推入堆栈0040111 call @ ILT 5(func)(0040100 a);@ILT 5(func)是函数func的修饰名,0040100a是他的地址00401123 add esp,0Ch堆栈恢复,__cdecl规则由调用者(这里是main) stack 20恢复:返回0;00401126 xor eax,eax 21:} 00401128 pop EDI 00401129 pop ESI 0040112 a pop ebx 0040112 b add esp,40h0040112E cmp ebp,esp 00401130 call _ _ chk esp(004011d 0)00401135 mov esp,ebp00401137 pop ebp00401138 ret

结果截图

程序中的堆栈结构如下:

__stdcall规则是被调用者自己调整堆栈。从组装的角度来看,恢复堆栈的行为发生在调用方的函数中。考虑这样一段代码(VC下调试):复制代码如下:#include cstdio

void __stdcall func(int param1,int param2,int param 3){ int var 1=param 1;int var2=param2int var3=param3

printf("% LD \ n ",long(param 1));printf("% LD \ n ",long(param 2));printf("% LD \ n ",long(param 3));printf("-\ n ");printf("% LD \ n ",long(var 1));printf("% LD \ n ",long(var 2));printf("% LD \ n ",long(var 3));返回;}

int main() { func(1、2、3);返回0;}注意到func(消歧义)函数使用了_ _ _ cdcl进行修饰(其实不需要,因为你呢下默认的是_ _ _ cdcl规则,这里是为了更为清晰),生成汇编代码如下:

复制代码代码如下:1:#包括CST dio 2:3:void _ _ STD call func(int param 1,int param2,int param 3){ 00401020 push ebp 00401021 mov ebp,esp00401023 sub esp,4Ch 00401026 push ebx 00401027 push ESI 00401028 push EDI 00401029 lea EDI,[ebp-4Ch]0040102 c mov ECE职位ptr[EDI]4:int var 1=00401038 mov eax,ptr dword[ebp 8]0040103 b mov ptr dword[ebp-4],eax 5:int var 2=param 2;0040103E mov ecx,ptr dword[ebp 0ch]00401041 mov ptr dword[ebp-8],ecx 6:int var 3=param 3;00401044 mov edx,ptr dword[ebp 10h]

…………………………………………………。省略印夫代码

15:返回;16:} 004010 BD EDI 004010 be pop ESI 004010 BF pop ebx 004010 c 0 add esp,4Ch004010C3 cmp ebp,esp 004010 c 5 call _ _ chesp(004011 d0)004010 ca mov esp,ebp 004010 cc pop ebp 004010 CD ret 0ch;_ _ _ _ _标准呼叫在这里(被调用函数)恢复堆栈,但如果是_ _ _ cdcl的话,这里是ret,你知道吗?堆栈的恢复由调用者(这里是(手)来负责

-好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧,好吧

18: int main()

………………………………………。省略建立堆栈代码

19: func(1、2、3);00401118推进3;停止3压入堆栈0040111A推2;停止2压入堆栈0040111C推力1;停止一压入堆栈0040111E呼叫@ ILT 0(func)(00401005);@ILT 0(函数)是函数的修饰名,而00401005 则是调用函数func(消歧义)的地址20:返回0;00401123 xor eax,eax 21:} 00401125 pop EDI 00401126 pop ESI 00401127 pop ebx 00401128添加esp,40h0040112B cmp ebp,esp0040112D呼叫_ _ chkcesp(004011 d0)00401132 mov esp,ebp00401134 pop ebp00401135 ret运行的结果与使用_ _ _ cdcl规则的一样,两者的栈结构基本一致的,唯一的不同就是调整堆栈(恢复堆栈)的位置以及生成函数的修饰名不同,而这样的不同正是_ _ _ _ _标准呼叫和_ _ _ cdcl最为重要的不同点

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • word文档无法编辑是怎么回事-
  • 华为手机怎么设置返回键(华为手机下面的三个按键设置方法)
  • lumia950怎么样(Lumia950体验分享)
  • otg连接是什么意思(OTG连接手机方法)
  • 笔记本触摸板怎么右键(笔记本电脑触控板手势操作设置)
  • 真我x7怎么样(realme X7 系列体验)
  • 苹果的A16处理器有多强(苹果的A16处理器的介绍)
  • 小米互传怎么用(小米手机的连接与共享教程)
  • 怎么设置电脑桌面图标自动对齐 设置电脑桌面自动整理图标的方法
  • 宽带错误651最简单解决方法(处理宽带错误651的措施)
  • 大学生手机有什么推荐(大学生换手机攻略)
  • 天玑1100和骁龙778g哪个好(骁龙778G、天玑900、天玑1100购选建议)
  • yum update 升级报错的解决办法
  • Windows10禁用屏保教程
  • 连接wifi显示无互联网连接怎么办(无线连上了却不能上网处理绝招)
  • 留言与评论(共有 条评论)
       
    验证码: