众所周知,cdecl是父函数需要平衡栈,stdcall是子函数需要平衡栈,可是我近日发现stdcall函数指针调用,父函数也平衡栈了,是不是觉得非常奇怪?看如下代码:
typedef void (*__cdecl CppCdeclTest_t)(int a,int b);
typedef void (*__stdcall CppStdTest)(int a, int b);
int main()
{
HMODULE dll=LoadLibrary(L"CallingConventionTest.dll");
CppCdeclTest_t CppCdeclTest = (CppCdeclTest_t)GetProcAddress(dll, "CppCdeclTest");
CppCdeclTest(5,2);
CppStdTest CppStdlTest = (CppStdTest)GetProcAddress(dll, "?CppStdTest@@YGXXZ");
CppStdlTest(5,2);
getchar();
}
生成的汇编如下:
截取部分:
CppCdeclTest(5,2);
0074411A mov esi,esp
0074411C push 2
0074411E push 5
00744120 call dword ptr [CppCdeclTest]
00744123 add esp,8 ;由于CppCdeclTest是cdecl调用方式,由父函数恢复栈,所以这里add esp,8没什么问题
00744126 cmp esi,esp
00744128 call __RTC_CheckEsp (0741212h)
CppStdTest CppStdlTest = (CppStdTest)GetProcAddress(dll, "?CppStdTest@@YGXXZ");
0074412D mov esi,esp
0074412F push offset string "?CppStdTest@@YGXXZ" (0747BDCh)
00744134 mov eax,dword ptr [dll]
00744137 push eax
00744138 call dword ptr [__imp__GetProcAddress@8 (074B028h)]
0074413E cmp esi,esp
00744140 call __RTC_CheckEsp (0741212h)
00744145 mov dword ptr [CppStdlTest],eax
CppStdlTest(5,2);
00744148 mov esi,esp
0074414A push 2
0074414C push 5
0074414E call dword ptr [CppStdlTest]
00744151 add esp,8 ;CppStdlTest是个stdcall的函数指针,按道理stdcall的话是由子函数把控栈指针,父函数不应该再生成这条汇编指令才对。
00744154 cmp esi,esp
00744156 call __RTC_CheckEsp (0741212h)
00744151 add esp,8 ;CppStdlTest是个stdcall的函数指针,按道理stdcall的话是由子函数平衡栈指针,父函数不应该再生成这条汇编指令才对 ,为什么会生成呢?
解决方案:
typedef void ( *__stdcall CppStdTest)(int a, int b); ×
typedef void (__stdcall * CppStdTest)(int a, int b); √
改成下面的这个就好了。就不会生成那条指令了。