48: if ( m= s )
004011B3 mov eax,dword ptr [ebp+8]
004011B6 mov ecx,dword ptr [eax]
004011B8 cmp ecx,dword ptr [ebp-4]
004011BB jl Input+0AFh (004011bf)
57: break;
004011BD jmp Input+0C1h (004011d1)
58: else
59: printf(" m < n*(n+1)/2,Please input again!\n");
004011BF push offset string " m < n*(n+1)/2,Please input agai"... (00426060)
004011C4 call printf (00401530)
004011C9 add esp,4
60: }
004011CC jmp Input+18h (00401128)
61:
62: }
004011D1 pop edi
004011D2 pop esi
004011D3 pop ebx
004011D4 add esp,48h
004011D7 cmp ebp,esp
004011D9 call __chkesp (004015b0)
004011DE mov esp,ebp
004011E0 pop ebp
004011E1 ret 8
-
最后,我们看到在函数末尾部分,有ret 8,明显是恢复堆栈, 由于在32位C++(www.cppentry.com)中,变量地址为4个字节(int也为4个字节),所以弹栈两个地址即8 个字节。
由此可以看出:在主调用函数中负责压栈,在被调用函数中负责 恢复堆栈。因此不能实现变参函数,因为被调函数不能事先知道弹栈数量,但在 主调函数中是可以做到的,因为参数数量由主调函数确定。
下面再看一下 ,ebp-8和ebp-4这两个地址实际存储的是什么值,ebp-8地址存储的是n 的值, ebp -4存储的是m的值。说明也是从右到左压栈,进行参数传递。
总结:在 主调用函数中负责压栈,在被调用函数中负责弹出堆栈中的参数,并且负责恢复 堆栈。因此不能实现变参函数,参数传递是从右到左。另外,命名修饰方法是在 函数前加一个下划线(_),在函数名后有符号(@),在@后面紧跟参数列表中的参数 所占字节数(10进制),如:void Input(int &m,int &n),被修饰成: _Input@8
对于大多数api函数以及窗口消息处理函数皆用 CALLBACK ,所以 调用前,主调函数会先压栈,然后api函数自己恢复堆栈。
如:
push edx
push edi
push eax
push ebx
call getdlgitemtexta
你可以想一下,这几个寄存器中存的都 是什么?
参考:msdn
例子为在VC6.0下debug模式下的Win32 Console反汇编代码。