出现错误的原因
代码
#include "stdafx.h"
#include <windows.h>
#include <string>
using namespace std;
void OnBnClickedButton2() //这个有问题
{
HINSTANCE hMod = LoadLibrary("testdll.dll");
typedef string (WINAPI *pnfOrgMYFUNC)();
pnfOrgMYFUNC CallFuntionName = (pnfOrgMYFUNC)GetProcAddress(hMod,"test");
CallFuntionName();
FreeLibrary(hMod);
}
int main(){
OnBnClickedButton2();
}
运行结果
分析结果
结果内容为:
The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
翻译内容为:
ESP的值没有通过一个函数调用被妥善保存 ,这通常是用一个调用约定调用一个函数,而用另一个调用约定调用一个函数指针的结果
这里的重点为:different calling convention,不同的调用协定
也就是说声明的pnfOrgMYFUNC并不匹配实际获取到的功能
楼主也发现将char 改为返回值的话就可以正常运行,所以归根结底问题出在string 和 char上
于是问题转化为分析string 和 char*的不同
分析char* 和 string
想要了解char* 和 string 最快的办法就是分析其汇编
代码
#include "stdafx.h"
#include <string>
void function(){
string a;
char* b;
a="this is a";
b="this is b";
}
int main(){
function();
}
反汇编代码
25: string a;
004011BD lea eax,[ebp-24h]
004011C0 push eax
004011C1 lea ecx,[ebp-1Ch]
004011C4 call @ILT+105(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_str
004011C9 mov dword ptr [ebp-4],0
26: char* b;
27: a="this is a";
004011D0 push offset string "this is a" (00426040)
004011D5 lea ecx,[ebp-1Ch]
004011D8 call @ILT+35(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator=)
28: b="this is b";
004011DD mov dword ptr [ebp-20h],offset string "this is b" (00426034)
反汇编分析
直接看对应的赋值语句
string的赋值
27: a="this is a";
004011D0 push offset string "this is a" (00426040)
004011D5 lea ecx,[ebp-1Ch]
004011D8 call @ILT+35(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator=)
1.首先将要赋值的字符串作为参数压入堆栈
004011D0 push offset string "this is a" (00426040)
2.然后将ebp-1Ch的地址传给ecx
004011D5 lea ecx,[ebp-1Ch]
ebp-1Ch的地址是什么?观察内存窗口
可以发现ebp-1Ch其实就是a的地址
3.调用string相关的call
004011D8 call @ILT+35(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::operator=)
char*的赋值
相比string,char*的赋值就简单多了,直接赋值即可
28: b="this is b";
004011DD mov dword ptr [ebp-20h],offset string "this is b" (00426034)
出错的反汇编分析
有了前面的铺垫大致了解了string 和 char*的区别后,现在来用反汇编分析出错的原因
string反汇编
首先要明确出错的地方为调用函数处,即CallFuntionName这里,直接看反汇编:
16: CallFuntionName();
004010AA mov esi,esp
004010AC lea ecx,[ebp-18h]
004010AF push ecx
004010B0 call dword ptr [ebp-8]
004010B3 cmp esi,esp
004010B5 call __chkesp (00401460)
004010BA lea ecx,[ebp-18h]
004010BD call @ILT+30(std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_str
17:
18: FreeLibrary(hMod);
看到函数里的call __chkesp 就知道报错是这个函数引发的,也就是堆栈不平衡引起的错误
为什么使用string会引起堆栈不平衡?而使用使用char* 不会?
对比char* 反汇编
16: CallFuntionName();
004010AA mov esi,esp
004010AC call dword ptr [ebp-8]
004010AF cmp esi,esp
004010B1 call __chkesp (00401460)
17:
18: FreeLibrary(hMod);
可以看到无论是string还是char* ,都调用了call dword ptr [ebp-8],不同的是string还需要lea ecx和push ecx,压入string所需的参数,因而导致了后续的堆栈不平衡
总结
string和char* 的区别在于要压入参数和调用string相关的call,而char* 则是直接赋值即可,前者破坏了堆栈的平衡而引发了错误