问题描述
|
我只是在VS2010上编译了以下内容(关闭了优化功能)。
class Shape {
public:
int x,y;
Shape() {
x=10;
y=20;
}
virtual void function1() {
cout<<\"function1\";
}
virtual void function2() {
cout<<\"function2\";
}
};
int main() {
Shape *s = new Shape();
s->function1();
s->function2();
return 0;
}
反汇编未显示与虚拟函数相对应的代码块或对虚拟函数的任何调用,因此Im假定这是由于使用vftable查找虚拟函数的方式引起的。我正在使用IDA Pro,因此它可能无法解决此类问题。如果我错了,请纠正我。
在这方面,我也有一些疑问。
我有什么办法可以像在拆卸过程中查看其他虚拟功能一样查看虚拟功能?我可以使用任何脚本(IDAPython)/方法吗?
有什么办法可以列出可执行文件中的所有虚拟功能?
建议阅读?
解决方法
仅当对象的动态类型不同于其静态类型(指向派生类的Pointer-Base指针)时,才涉及虚拟调度。由于您甚至没有继承,并且在调用站点上没有确切的类型,因此为什么要在vtable中进行查找?
, 由于您已经在类定义中定义了虚函数,因此我认为您的函数可能已被编译器内联,因为它知道调用站点的确切类型。尝试将功能主体移出类主体。然后,它们一定会出现在反汇编中。我怀疑它们现在可能被链接器弄死了。
, 正如其他人指出的那样:您没有任何继承,因此编译器通过消除虚拟调度而变得很聪明。
建议阅读:Stroustrup的C ++设计与演进。它不会解决您所有的问题,但会为您提供一个框架来帮助回答或更有效地研究他们的答案。
, 我没有您的编译器,这在很大程度上取决于编译器和选项。在g ++ 4.5中,使用默认选项(并修复了代码中的一些问题),我已将代码编译为汇编代码(assembly1ѭ),并且确实通过虚拟分派机制显示了函数和调用(在调用构造函数后为
main
)它提取vptr,将其偏移并通过寄存器中的值进行调用)。
Shape :: function2的定义(注意.weak表示内联)
.globl __ZN5Shape9function2Ev
____.weak_definition __ZN5Shape9function2Ev
__ZN5Shape9function2Ev:
[...]
Shape :: function1的定义(同样,.weak表示内联)
.globl __ZN5Shape9function1Ev
____.weak_definition __ZN5Shape9function1Ev
__ZN5Shape9function1Ev:
[...]
vtable本身对Shape的定义:
.globl __ZTV5Shape
.weak_definition __ZTV5Shape
.section __DATA,__const_coal,coalesced
.align 5
__ZTV5Shape:
.quad 0
.quad __ZTI5Shape # Ptr to type_info object
.quad __ZN5Shape9function1Ev # vtable[0] is Shape::function1
.quad __ZN5Shape9function2Ev # vtable[1] is Shape::function2
主要的定义:
.globl _main
_main:
[...]
movq %rax,%rbx
movq %rbx,%rdi
call __ZN5ShapeC1Ev # Call to constructor this will setup the vptr
movq %rbx,-24(%rbp)
movq -24(%rbp),%rax # load **vptr into rax i.e. *vptr[0]: Shape::function1
movq (%rax),%rax
movq (%rax),%rax
movq -24(%rbp),%rdi
call *%rax # call it
至于其他人所说的,编译器可以完全取消虚拟调度或内联函数,这是事实。这个版本的g ++不会针对特定的代码段执行此操作,而是通过删除指针(使用具有静态存储持续时间的Shape
)来实现