关于stdcall

博客提到win32asm教程中,win32用stdcall约定,参数右向左入栈,被调用者恢复堆栈,但wsprintf参数个数不确定。作者使用该函数时发现不用自己恢复堆栈,反汇编程序后发现是编译器自动添加了恢复堆栈的语句。

from http://zerray.com/

 

记得看win32asm教程的时候,里面提到win32只使用stdcall约定,即参数由右向左压入堆栈,恢复堆栈的工作交给被调用者。但同时还提到有一个函数例外,wsprintf,因为它的参数个数是不确定的。原来一直没有用过这个函数,就没注意了。今天用了一下,发现也不用自己恢复堆栈啊,只要简单的

invoke wsprintf, OFFSET szBuf, OFFSET szFmt, ...

就OK了,并不用在后面加上add esp, xx,为什么呢?把程序反汇编了一下,恍然大悟!原来是编译器帮我搞定了,自动的加上了add esp, xx一句。如果自己再写add esp, xx就是画蛇添足了。

### 作用与机制 `__stdcall` 是一种常见的调用约定(calling convention),主要用于 Windows API 函数和许多系统级编程中。其核心作用是定义函数调用过程中参数如何传递、堆栈如何清理以及寄存器的使用方式。 在 `__stdcall` 约定下,函数调用时参数从右向左压入堆栈,由被调用方(callee)负责清理堆栈中的参数。这种机制与 `__cdecl` 不同,后者由调用方(caller)负责清理堆栈[^3]。 这种约定的一个典型汇编示例为: ```assembly 00412DB1 mov esi, esp 00412DB3 lea eax, [dws] 00412DB9 push eax 00412DBA push 80h 00412DBF lea ecx, [ebp-168h] 00412DC5 push ecx 00412DC6 mov edx, dword ptr [ebp-48h] 00412DC9 mov eax, dword ptr [edx+10h] 00412DCC push eax 00412DCD call dword ptr [ebp-61Ch] 00412DD3 cmp esi, esp ; 此时堆栈已被 callee 清理 ``` 该机制确保了堆栈的一致性和稳定性,特别是在函数调用后堆栈清理的责任明确归属被调用函数[^2]。 ### 使用场景 `__stdcall` 通常用于需要与操作系统或底层硬件交互的场景。例如,Windows API 函数广泛采用 `__stdcall`,以确保跨模块调用时堆栈的一致性[^3]。 此外,`__stdcall` 也常用于回调函数的定义,尤其是在图形用户界面(GUI)编程中,例如窗口过程函数(Window Procedure)通常使用 `__stdcall` 约定。这种做法可以确保回调函数在不同模块之间传递时,调用行为保持一致[^1]。 由于 `__stdcall` 在调用结束后由被调用函数清理堆栈,因此它适用于参数数量固定且已知的函数。对于参数数量可变的函数(如 `printf`),通常使用 `__cdecl`,因为调用者必须知道参数的数量才能正确清理堆栈[^1]。 ### 优势与局限性 `__stdcall` 的优势在于减少了调用者的负担,调用者无需关心参数的清理,只需关注函数调用本身。这在系统级编程中尤为重要,因为它可以减少出错的可能性并提高执行效率。 然而,`__stdcall` 的局限性在于它不适用于可变参数函数。由于被调用函数在编译时必须知道参数的数量和大小,才能正确清理堆栈,因此它无法支持如 `printf` 这类参数数量不固定的函数。 此外,在某些现代编译器和优化场景中,`__stdcall` 的性能优势可能不如寄存器传参的调用约定(如 `__fastcall`)显著,因此在高性能要求的场景中可能不是首选[^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值