_cdecl和__stdcall修饰对比

_cdecl和__stdcall修饰对比

由_cdecl和__stdcall修饰的函数在被调用的时候的差别。
两个都是函数参数从右到左入栈,但是有细微的差别。
_cdecl修饰的函数,它的参数所占用的堆栈是由调用函数去清空的。
__stdcall修饰的函数,它的参数所占用的堆栈是由被调用的函数自己返回的时候清空的。

写一个简单的程序,查看汇编代码进行对比。

#include "stdafx.h" int _cdecl add1(int a, int b) { return a+b; } /// int __stdcall add2(int a, int b) { return a+b; } /// int main(int argc, char* argv[]) { int a, b, c; a = 12; b = 18; c = add1(a, b); c = add2(a, b); return 0; }

TITLE F:\SourceCode\VC\Test\Test.cpp .386P include listing.inc if @Version gt 510 .model FLAT else _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS _DATA SEGMENT DWORD USE32 PUBLIC 'DATA' _DATA ENDS CONST SEGMENT DWORD USE32 PUBLIC 'CONST' CONST ENDS _BSS SEGMENT DWORD USE32 PUBLIC 'BSS' _BSS ENDS $$SYMBOLS SEGMENT BYTE USE32 'DEBSYM' $$SYMBOLS ENDS $$TYPES SEGMENT BYTE USE32 'DEBTYP' $$TYPES ENDS _TLS SEGMENT DWORD USE32 PUBLIC 'TLS' _TLS ENDS ; COMDAT ?add1@@YAHHH@Z _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS ; COMDAT ?add2@@YGHHH@Z _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS ; COMDAT _main _TEXT SEGMENT PARA USE32 PUBLIC 'CODE' _TEXT ENDS FLAT GROUP _DATA, CONST, _BSS ASSUME CS: FLAT, DS: FLAT, SS: FLAT endif PUBLIC ?add1@@YAHHH@Z ; add1 ; COMDAT ?add1@@YAHHH@Z _TEXT SEGMENT _a$ = 8 _b$ = 12 ?add1@@YAHHH@Z PROC NEAR ; add1, COMDAT ; 7 : { push ebp mov ebp, esp sub esp, 64 ; 00000040H push ebx push esi push edi lea edi, DWORD PTR [ebp-64] mov ecx, 16 ; 00000010H mov eax, -858993460 ; ccccccccH rep stosd ; 8 : return a+b; mov eax, DWORD PTR _a$[ebp] add eax, DWORD PTR _b$[ebp] ; 9 : } pop edi pop esi pop ebx mov esp, ebp pop ebp ret 0 ;这里是_cdecl修饰的函数。函数执行完直接退出,并没有释放参数所点的堆栈 ?add1@@YAHHH@Z ENDP ; add1 _TEXT ENDS PUBLIC ?add2@@YGHHH@Z ; add2 ; COMDAT ?add2@@YGHHH@Z _TEXT SEGMENT _a$ = 8 _b$ = 12 ?add2@@YGHHH@Z PROC NEAR ; add2, COMDAT ; 12 : { push ebp mov ebp, esp sub esp, 64 ; 00000040H push ebx push esi push edi lea edi, DWORD PTR [ebp-64] mov ecx, 16 ; 00000010H mov eax, -858993460 ; ccccccccH rep stosd ; 13 : return a+b; mov eax, DWORD PTR _a$[ebp] add eax, DWORD PTR _b$[ebp] ; 14 : } pop edi pop esi pop ebx mov esp, ebp pop ebp <span style="color: #ff0000;" mce_style="color: #ff0000;"> ret 8 ;ret 8=ret && add esp,8。这里是__stdcall所修饰的函数,返回时清空参数所占的堆栈空间</style> ?add2@@YGHHH@Z ENDP ; add2 _TEXT ENDS PUBLIC _main EXTRN __chkesp:NEAR ; COMDAT _main _TEXT SEGMENT _a$ = -4 _b$ = -8 _c$ = -12 _main PROC NEAR ; COMDAT ; 17 : { push ebp mov ebp, esp sub esp, 76 ; 0000004cH push ebx push esi push edi lea edi, DWORD PTR [ebp-76] mov ecx, 19 ; 00000013H mov eax, -858993460 ; ccccccccH rep stosd ; 18 : int a, b, c; ; 19 : a = 12; mov DWORD PTR _a$[ebp], 12 ; 0000000cH ; 20 : b = 18; mov DWORD PTR _b$[ebp], 18 ; 00000012H ; 21 : c = add1(a, b); ;调用函数参数入栈 mov eax, DWORD PTR _b$[ebp] push eax mov ecx, DWORD PTR _a$[ebp] push ecx call ?add1@@YAHHH@Z ; add1 add esp, 8 ;_cdecl修饰的需要在调用函数结束之后,对参数所占的堆栈空间进行清空。 mov DWORD PTR _c$[ebp], eax ; 22 : c = add2(a, b); mov edx, DWORD PTR _b$[ebp] push edx mov eax, DWORD PTR _a$[ebp] push eax call ?add2@@YGHHH@Z ; add2 ;__stdcall修饰函数在返回的时候,参数所占的堆栈空间已经由被调用函数返回时清空。 mov DWORD PTR _c$[ebp], eax ; 23 : return 0; xor eax, eax ; 24 : } pop edi pop esi pop ebx add esp, 76 ; 0000004cH cmp ebp, esp call __chkesp mov esp, ebp pop ebp ret 0 _main ENDP _TEXT ENDS END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值