反汇编研究C++虚函数表,调用类内函数,调用虚函数

反汇编研究C++虚函数表,调用类内函数,调用虚函数

环境:gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)

测试代码1:

#include <iostream>
#include <stdio.h>

using namespace std;

class A {
public:
	virtual void func1() {printf("A func1\n");}
	virtual void func2() {printf("A func2\n");}
};

class B :public A {
public:
	int i;
	virtual void func1() {printf("%d\n",this->i); }
	virtual void func2() {printf("B func2\n");}
};

using namespace std;

typedef void(*FUNC)();
int main() {
	B b; 
	b.i = 1;
	A* a=&b;
	
/*FUNC* table = *(FUNC**)(&b);
	(*table)();*/
	a->func1();

	return 0;
}
}

注:std::cout反汇编后不太看得懂,所以使用printf输出

在这里插入图片描述
在这里插入图片描述
%rbp-0x28处是a的地址所在,可以看到
之后的两个mov (%rax),rax分别将虚函数表的地址推进rax,将虚函数表中的第一个函数也就是B::func1函数的地址推进rax,最后callq *%rax来调用B::func1

在这里插入图片描述
记录下当前b的地址
继续运行直到call *%rax前在这里插入图片描述
在这里插入图片描述
对%rax所指进行反汇编,可以发现此时rax的确指向B::func1,这也即虚函数的动态查找过程,实现了c++子类父类指针转换后仍然可以调用原本自己的虚函数
推测dynamic_cast进行转换时会更改类内虚函数表指针,而不是一成不变

另外,可以观察到B::fun1中将rdi压入了栈中,并且把rdi偏移地址为8处的4字节压入eax,rdi是64位操作系统&&程序传参时的第一个寄存器,从此可以得出,在调用类内函数时,c++会默认将this指针作为第一个参数传入,从前图的rdi的值也可以直到,rdi的确存着b的地址,也即a

测试代码2:

#include <iostream>
#include <stdio.h>

using namespace std;

class A {
public:
	virtual void func1() {printf("A func1\n");}
	virtual void func2() {printf("A func2\n");}
};

class B :public A {
public:
	int i;
	virtual void func1() {printf("%d\n",this->i); }
	virtual void func2() {printf("B func2\n");}
};

using namespace std;

typedef void(*FUNC)();
int main() {
	B b; 
	b.i = 1;
	A* a=&b;
	B b2;	

	FUNC* table = *(FUNC**)(&b);
	(*table)();
	/*a->func1();*/

	return 0;
}

指向虚函数表的指针被存放在虚类的最开头,这里通过强转直接取到B::func1的地址进行调用
注意:B b2的原因是,在我当前环境下,创建完b后,rdi直到调用(*table)()都未被更改,导致rdi仍然存储着b的地址来调用(*table)也即B::func1,可以输出正确结果1
这里B b2后,实际rdi在调用(*table)()时,实际存着的地址是b2的
在这里插入图片描述
在这里插入图片描述
可以看到c++先将b2即this指针保存进rdi,然后调用B:::B()默认构造函数,之后rdi都没有改变过

步进到callq *%rax
在这里插入图片描述
rdi保存着b2的地址,所以程序继续执行,会输出一个垃圾值b2.i在这里插入图片描述
前8子节为指向虚函数表的指针,预计输出1431652576,实际也是

over

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ObjetArx2004+VS2002前提:安装好以上两种软件创建步骤:1. 新建项目 Visual C++项目->选择ObjectARX/DBX/OMF->键入"Demo"项目名称 ->MFC Support中勾选Enxtension Dll->using MFC Shared DLL,其他取默认值2. 删除文件 在“解决方案资源管理器”中删除向导生成的acrxEntryPoint.cpp,DocData.cpp,DocData.h文件 同时可以在文件夹下彻底删除文件,后续步骤并不需要用到这3个文件3. 添加Demo.h文件 同时在Demo.h文件中加入代码 #pragma once #include"resource.h"3. 创建一个普通对话框,基于CDialog类,并生成类CDlgDemo4. 打开Demo.cpp文件,对这个文件要进行比较多的操作 ·注释掉"AFX_EXTENSION_MODULE DemoExtDLL ={ NULL, NULL };"这一句 ·添加#include "DlgDemo.h"头文件 ·添加函数DlgDemo(),具体见附件源文件代码 ·添加initApp(),unloadApp() ·注释掉DllMain中的"_hdllInstance =hInstance ;" ·在文件的末尾添加acrxEntryPoint() 这里需要提醒一下的是关于AC_IMPLEMENT_EXTENSION_MODULE(DemoDLL)的使用 涉及到了Dll资源的使用,所以DemoDLL在这里相当于一个连接AutoCAD和MFC的纽带, 保持整个Demo.cpp中,DemoDLL的一致5. 项目设置 菜单"工具"->"选项"->"项目"->"包含文件"->添加ObjectARX2004的inc目录 ->"库文件"->添加ObjectARX2004的lib目录6. 生成解决方案 一切pass,有2个警告rxapi.lib(libinit.obj) : warning LNK4099: 未发现 PDB“msvc.pdb” acedapi.lib(acedstub.obj) : warning LNK4099: 未发现 PDB“corehdr.pdb” 不用去管它,ObjectARX开发文档已经说明了这个问题的存在,不影响使用#至此为止,我们已经生成了MarkDemo.arx,在Debug目录下可以找到,下面将继续介绍如何在 AutoCAD2004菜单中自动加载Demo对话框
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值