通过虚函数表调用函数的问题
#include<iostream>
using namespace std;
class good
{
public:
virtual void f(){int a = 523;cout << a<<"\n"<<this->a<<endl; cout<<"fun::f()"<<endl;}
//此处a 办出为523;this->a为八位数;不会随a的改变而改变,但会随代码的改变而改变
int a;
};
typedef void (*pfun)();
good d;
pfun fun;
int main()
{
fun= (pfun)*((int*)*(int*)(&d));
fun();
}
问:为什么能调用成功,且this->a不报错,a为什么输出正常?
[解决办法]
(pfun)*((int*)*(int*)(&d));
你这一句其实就是强转虚表里的内容,也就是f函数的地址。
把f地址给fun函数指针
这里就涉及到一个问题了,他俩的调用约定。
因为你这两函数都没有参数,所以没有问题
你调用this->a,正常应该是ecx(this) + 偏移去调, 但你现在执行方式使用的是cdecl
调用的时候就不会把this指针压到ecx里
但你的代码我调了下,它在强转过程中,确实把this指针给ecx了,不知道是不是编译器比较聪明
00401978 mov eax,[d (00477740)]
0040197D mov ecx,dword ptr [eax]
0040197F mov dword ptr [fun (00477738)],ecx
[解决办法]
你知道类的对象的内存组成就很简单了,一个类对象前4个字节存放的是虚函数表的指针,虚函数表中存放了所有虚函数的指针,所以
(pfun)*((int*)*(int*)(&d));
这一句的&d的意思是获取该对象的地址,然后*(int*)(&d)这样就获取了虚函数表的指针值
*((int*)*(int*)(&d)),这样就获取了虚函数表中的第一个虚函数的指针值,该对象只有一个虚函数即f(),所以这个地方就获取了这个函数的指针并执行~
后边你就可以简单的当做一个函数在执行了,它输出了一个局部变量,一个问题就是this->a中的this究竟是什么,因为你是直接通过指针转换进行执行,所以此处的this是虚函数的指针,所以此处this->a是虚函数所指向的内存第4-7个字节,换而言之是虚函数f()函数体中的字节
[解决办法]
[解决办法]
[解决办法]
首先解释this指针的问题(注意注释部分)
-------------------_cdecl下的反汇编(lz的代码)--------------
- Assembly code
fun= (pfun)*((int*)*(int*)(&d));00FC1D33 mov eax,dword ptr [d] ;虚函数表地址 00FC1D36 mov ecx,dword ptr [eax] ;此处虽然给ecx赋值了,但其实是虚函数地址00FC1D38 mov dword ptr [fun (0FD222Ch)],ecx fun();00FC1D3E mov esi,esp 00FC1D40 call dword ptr [fun (0FD222Ch)] 00FC1D46 cmp esi,esp 00FC1D48 call @ILT+1050(__RTC_CheckEsp) (0FC141Fh)