文章目录
一、 直接调用和间接调用
汇编中:
call 地址 是直接调用 ,或者 E8。。。
call [。。。] 是间接调用 ,或者FF。。。
二、虚函数表:
class Base
{
public:
void Function_1()
{
printf("Function_1...\n");
}
virtual void Function_2()
{
printf("Function_2...\n");
}
};
对象调用时,没有任何区别
Base base;
base.Function_1();
00401090 8D 4D FC lea ecx,[ebp-4]
00401093 E8 9F FF FF FF call @ILT+50(Base::Function_1) (00401037)
base.Function_2();
00401098 8D 4D FC lea ecx,[ebp-4]
0040109B E8 65 FF FF FF call @ILT+0(Base::Function_2) (00401005)
指针调用
Base base;
Base* pb = &base;
pb->Function_1();
004010A6 8B 4D F8 mov ecx,dword ptr [ebp-8]
004010A9 E8 89 FF FF FF call @ILT+50(Base::Function_1) (00401037)
pb->Function_2();
004010AE 8B 4D F8 mov ecx,dword ptr [ebp-8]
004010B1 8B 11 mov edx,dword ptr [ecx]
004010B3 8B F4 mov esi,esp
004010B5 8B 4D F8 mov ecx,dword ptr [ebp-8]
004010B8 FF 12 call dword ptr [edx]
1、通过对象调用时,virtual函数与普通函数都是E8 Call
2、通过指针调用时,virtual函数是FF Call,也就是间接Call
三、虚函数大小
class Base
{
public:
int x;
int y;
virtual void Function_1()
{
printf("Function_1...\n");
}
virtual void Function_2()
{
printf("Function_2...\n");
}
};
Base base;
printf("%x\n",sizeof(base)); //12 虚函数4个字节(不管多少个)
多出来的4个字节在对象的首地址
pb->Function_1();
0040D9E3 8B 4D F0 mov ecx,dword ptr [ebp-10h]
0040D9E6 8B 11 mov edx,dword ptr [ecx]
0040D9E8 8B F4 mov esi,esp
0040D9EA 8B 4D F0 mov ecx,dword ptr [ebp-10h]
0040D9ED FF 12 call dword ptr [edx]
pb->Function_2();
0040D9F6 8B 45 F0 mov eax,dword ptr [ebp-10h]
0040D9F9 8B 10 mov edx,dword ptr [eax]
0040D9FB 8B F4 mov esi,esp
0040D9FD 8B 4D F0 mov ecx,dword ptr [ebp-10h]
0040DA00 FF 52 04 call dword ptr [edx+4]
1、当类中有虚函数时,会多一个属性,4个字节
2、多出的属性是一个地址,指向一张表,里面存储了所有虚函数的地址
四、虚函数的值
class Base
{
public:
int x;
int y;
virtual void Function_1()
{
printf("Function_1...\n");
}
virtual void Function_2()
{
printf("Function_2...\n");
}
virtual void Function_3()
{
printf("Function_3...\n");
}
};
void TestMethod()
{
//查看 Sub 的虚函数表
Base base;
//对象的前四个字节就是虚函数表
printf("base 的虚函数表地址为:%x\n",*(int*)&base);
//通过函数指针调用函数,验证正确性
typedef void(*pFunction)(void);
pFunction pFn;
int temp = *((int*)(*(int*)&base)+0);
}