测试方法:
interface IA1
{
public:
virtual void f1() = 0;
virtual void f2() = 0;
};
interface IA2
{
public:
virtual void f3() = 0;
virtual void f4() = 0;
};
class CB1 : public IA1
, public IA2
{
public:
void fb1()
{
int i = 0;
printf("fb1 - this:0x%08x", this);
}
};
class CB2 : public IA1
, public IA2
{
public:
void fb2()
{
int i = 0;
}
void f1()
{
;
}
void f2()
{
;
}
void f3()
{
;
}
void f4()
{
;
}
};
class CC : public CB1
, public CB2
{
public:
void f1()
{
int i = 1;
printf("f1:0x%08x 0x%08x\n", &CC::f1, this);
}
void f2()
{
int i = 1;
printf("f2:0x%08x 0x%08x\n", &CC::f2);
}
void f3()
{
int i = 1;
printf("f3:0x%08x 0x%08x\n", &CC::f3);
}
void f4()
{
int i = 1;
printf("f4:0x%08x 0x%08x\n", &CC::f4);
}
};
结果:
- | - | 0x00df4180 | CC::`RTTI Complete Object Locator':[0xdf4c80] |
this vtable==CC::CB1::IA1-> | 0x007a34e8-> | 0x00df4184 | pointer to->CC::f1() |
0x00df4188 | pointer to->CC::f2() | ||
0x00df418c | ???Unknown Data. Like const string. | ||
pCB1IA2::CC::CB1::IA2-> | 0x007a34ec-> | 0x00df4178 | pointer to->CC::f3() |
0x00df417c | pointer to->CC::f4() | ||
0x00df4180 | CC::`RTTI Complete Object Locator':[0xdf4c80] | ||
pCB2IA1==CC::CB2::IA1 vtable-> | 0x007a34f0 | 0x00df416c | pointer to->[thunk(p-8)]CC::f1 |
0x00DF4170 | pointer to->[thunk(p-8)]CC::f2 | ||
0x00DF4174 | CC::`RTTI Complete Object Locator':[0xdf4e68] | ||
pCB2IA2==CC::CB2::IA2 vtable-> | 0x007a34f4 | 0x00df4160 | pointer to->[thunk(p-8)]CC::f3 |
0x00df4164 | pointer to->[thunk(p-8)]CC::f4 | ||
0x00df4168 | CC::`RTTI Complete Object Locator':[0xdf4e7c] |
测试结果分析:
指针在调用时会把调用的指针存入ECX寄存器,thunk对ECX寄存器做减法运算得到真实的this.在调用类函数的时候,如果使用this指针的调用,在调用函数f1、f2时候是直接调用(this值存入ECX),f3、f4时候会先把this值加上4,然后存入ECX调用函数。当使用接口指针调用时,接口指针直接放入ECX,然后调用程序。根据不同的情况,会进入一个临时的thunk代码里面,thunk代码会对存入ECX的指针作出调整,使进入真正的函数前this总是正确的。 从上面的分析还可以看出,每个接口指针的上一个值DWORD】,是当前指针的RTTI信息,不知道是不是只有Debug版本才有??? |