类成员函数指针

如下代码:

#include "stdafx.h"

class A {
public:
	A():n(0xf1f1){}
	virtual ~A(){}
	virtual void show(){ printf("a"); }
	virtual void show1(){ printf("a1"); }
	void showA(){}
private:
	int n;
};

class A0 {
public:
	A0(){}
	virtual ~A0(){}
	virtual void show(){ printf("a0"); }
	virtual void show1(){ printf("a01"); }
	void showA0(){}
};

class B : public A , public A0 {
public:
	B(){}
	virtual ~B(){}
	virtual void show(){ printf("b"); }
	virtual void show1(){ printf("b1"); }
	void showB(){}
};

typedef void (A0::*PFUNA0)();
typedef void (B::*PFUNB)();

int _tmain(int argc, _TCHAR* argv[])
{
	printf("%p, %p\n", &A::show, &B::show);
	return 0;
}
会发现&A::show==&B::show.


把_tmain改一下:

int _tmain(int argc, _TCHAR* argv[])
{
	PFUNA0 lpProcA0 = (&A0::show1);
	A0 *lpa0 = &b0;
	(lpa0->*lpProcA0)();
	return 0;
}
 反汇编:

; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00401260 _main           proc near               ; CODE XREF: __tmainCRTStartup+10Ap
.text:00401260
.text:00401260 var_28          = dword ptr -28h
.text:00401260 var_24          = dword ptr -24h
.text:00401260 lpProcA0        = dword ptr -20h
.text:00401260 lpa0            = dword ptr -1Ch
.text:00401260 b0              = B ptr -18h
.text:00401260 var_C           = dword ptr -0Ch
.text:00401260 var_4           = dword ptr -4
.text:00401260 argc            = dword ptr  8
.text:00401260 argv            = dword ptr  0Ch
.text:00401260 envp            = dword ptr  10h
.text:00401260
.text:00401260                 push    ebp
.text:00401261                 mov     ebp, esp
.text:00401263                 push    0FFFFFFFFh
.text:00401265                 push    offset __ehhandler$_wmain
.text:0040126A                 mov     eax, large fs:0
.text:00401270                 push    eax
.text:00401271                 sub     esp, 1Ch
.text:00401274                 mov     eax, ___security_cookie
.text:00401279                 xor     eax, ebp
.text:0040127B                 push    eax
.text:0040127C                 lea     eax, [ebp+var_C]
.text:0040127F                 mov     large fs:0, eax
.text:00401285                 lea     ecx, [ebp+b0]   ; this
.text:00401288                 call    ??0B@@QAE@XZ    ; B::B(void)
.text:0040128D                 mov     [ebp+var_4], 0
.text:00401294                 mov     [ebp+lpProcA0], offset ??_9A0@@$B7AE ; [thunk]: A0::`vcall'{8,{flat}}
.text:0040129B                 lea     eax, [ebp+b0]
.text:0040129E                 test    eax, eax
.text:004012A0                 jz      short loc_4012AD
.text:004012A2                 lea     ecx, [ebp+b0]
.text:004012A5                 add     ecx, 8
.text:004012A8                 mov     [ebp+var_28], ecx
.text:004012AB                 jmp     short loc_4012B4
.text:004012AD ; ---------------------------------------------------------------------------
.text:004012AD
.text:004012AD loc_4012AD:                             ; CODE XREF: _main+40j
.text:004012AD                 mov     [ebp+var_28], 0
.text:004012B4
.text:004012B4 loc_4012B4:                             ; CODE XREF: _main+4Bj
.text:004012B4                 mov     edx, [ebp+var_28]
.text:004012B7                 mov     [ebp+lpa0], edx
.text:004012BA                 mov     ecx, [ebp+lpa0]
.text:004012BD                 call    [ebp+lpProcA0]
.text:004012C0                 mov     [ebp+var_24], 0
.text:004012C7                 mov     [ebp+var_4], 0FFFFFFFFh
.text:004012CE                 lea     ecx, [ebp+b0]   ; this
.text:004012D1                 call    ??1B@@UAE@XZ    ; B::~B(void)
.text:004012D6                 mov     eax, [ebp+var_24]
.text:004012D9                 mov     ecx, [ebp+var_C]
.text:004012DC                 mov     large fs:0, ecx
.text:004012E3                 pop     ecx
.text:004012E4                 mov     esp, ebp
.text:004012E6                 pop     ebp
.text:004012E7                 retn
.text:004012E7 _main           endp
会发现编译器做了不少事情,简单总结如下:

1.修正虚函数表指针偏移

2.修正虚函数指针偏移

3.修正this指针

4.调用类成员函数


大概流程:

1.修正虚函数表指针:

.text:004012A5                 add     ecx, 8

2.跳转到&A0::show1地址处处,修正虚函数指针:

.text:00401300 ; [thunk]: __thiscall A0::`vcall'{8,{flat}}
.text:00401300 ??_9A0@@$B7AE   proc near               ; DATA XREF: _main+34o
.text:00401300                 mov     eax, [ecx]
.text:00401302                 jmp     dword ptr [eax+8]
.text:00401302 ??_9A0@@$B7AE   endp

[ecx]是修正后的虚函数表指针,然后跳到偏移为[eax + 8]处,即虚函数表第三项,但这项并不是show1的地址,而是这段代码:

3.修正this指针:

.text:004012F0 ; [thunk]:public: virtual void __thiscall B::show1`adjustor{8}' (void)
.text:004012F0 ?show1@B@@W7AEXXZ proc near             ; DATA XREF: .rdata:00402150o
.text:004012F0                 sub     ecx, 8
.text:004012F3                 jmp     ?show1@B@@UAEXXZ ; B::show1(void)
.text:004012F3 ?show1@B@@W7AEXXZ endp
这段代码主要是修正了一下ecx,即是将this指针指回b0。然后跳转到?show1@B@@UAEXXZ ; B::show1(void),这个才是B::show1的地址。

对this指针做修正是为了下来的函数能正确访问到b0的成员。(个人猜测,未验证)

这些都是和编译器相关的,cl.exe.






                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值