c++之于80X86汇编之stdcall,cdecl调用

本文详细解析了stdcall和cdecl两种函数调用约定的区别,包括它们如何处理参数传递及栈清理,以及在asm层面的具体表现。通过示例代码展示了不同调用方式下,ESP指针调整的责任方差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

stdcall:windows API调用方式,即WINAPI。

cdecl:c语言默认调用方式。

问题的由来。不同的调用方式,包括其它调用方式,fastcall,thiscall等等,主要是为了解决函数调用中,参数的传递问题。stdcall和cdecl调用都是通过栈来传递参数。调用之前先将参数入栈,再调用函数,调用后再清理栈。由此就有了不同的调用方式约定,这些调用方式决定了参数的传递方式及清理栈的负责方(调用方或被调用方)。

具体表现。在asm层面,两者表现为ESP指针的调整对象为调用方或被调用方。stdcall,ESP由被调用方,即函数本身来调整栈顶指针(ESP).;cdecl,ESP由调用方调整ESP。最终使执行下一条语句之前名ESP指针恢复到原来的值。在asm代码层面表现为:stdcall 调用 方式最后ret 指令为 ret x; 意义为函数调用结束,并且执行add esp,x。而cdecl调用方式,只是最后简单执行ret指令,因为由调用方来平衡栈。

那么为什么非要使调用后的ESP与调用之前一致呢?其中最重要的一点就是节省内存空间。若是不恢复ESP,则会一直增大,最后会使栈本身很大,没有内存可分配。

例:

c/c++代码:

int _stdcall add_stdcall(int m,int n)
{
    return m+n;
}
int _cdecl add_cdecl(int m,int n)
{
    return m+n;
}

等效的80x86 ASM代码:

add_stdcall proc
	push ebp
	mov ebp,esp
	
	mov eax,DWORD PTR [ebp+8]
	add eax,DWORD PTR [ebp+12]
	
	mov esp,ebp
	pop ebp
	ret 8
add_stdcall endp

add_cdecl proc
	push ebp
	mov ebp,esp
	
	mov eax,DWORD PTR [ebp+8]
	add eax,DWORD PTR [ebp+12]
	
	mov esp,ebp
	pop ebp
	ret
add_cdecl endp    

调用方式如下:

;szfmt db 'result=%u',13,10,0 

;stdcall
push 100
push 200
call add_stdcall

push eax
push offset szfmt
call crt_printf
add esp,8
;cdecl
push 300
push 400
call add_cdecl
add esp,8

push eax
push offset szfmt
call crt_printf
add esp,8

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值