I just compiled the following on VS2010(with optimization turned off).
class Shape {
public:
int x,y;
Shape() {
x=10;
y=20;
}
virtual void function1() {
cout<<"function1";
}
virtual void function2() {
开发者_C百科 cout<<"function2";
}
};
int main() {
Shape *s = new Shape();
s->function1();
s->function2();
return 0;
}
The disassembly does not show the code blocks corresponding to the virtual functions or any calls to it, so Im assuming that it is because of the way virtual functions are looked up using the vftable. I'm using IDA Pro so it is probably not able to resolve such issues. Please correct me if I'm wrong.
I also have a few doubts in this regard.
- Is there any way I can view the virtual functions just as the other functions during disassembly? Any script(IDAPython)/method that I could use?
- Is there any way I can list all virtual functions in an executable?
- Suggested Reading?
Virtual dispatch is only involved when the dynamic type of an object is different from its static type (pointer-to-Base pointing to a derived class). Since you don't even have inheritance, and an exact type at the call site, why should it do the lookup in the vtable?
Since you've defined your virtual functions inside the class definition, I think your functions might be being inlined by the compiler, as it knows the exact type at the call site. Try moving the function bodies out of the class body. They should definitely show up in disassembly then. I suspect they might be deadstripped by the linker at the moment.
As others have noted: you don't have any inheritance, so the compiler is being smart by eliminating virtual dispatch.
Suggested reading: Stroustrup's The Design and Evolution of C++. It won't address all your questions, but give you a framework to help answer them or research their answer more effectively.
I don't have your compiler, and this is highly dependent on the compiler and options. With g++ 4.5, with the default options (and after fixing a few issues in the code) I have compiled into assembly (g++ -S -o test.asm test.cpp
) the code and it does show the functions and the calls through the virtual dispatch mechanism (in main
after calling the constructor it extracts the vptr, offsets it and calls through the value in the register).
Definition of Shape::function2 (note the .weak means inline)
.globl __ZN5Shape9function2Ev
____.weak_definition __ZN5Shape9function2Ev
__ZN5Shape9function2Ev:
[...]
Definition of Shape::function1 (again, .weak means inline)
.globl __ZN5Shape9function1Ev
____.weak_definition __ZN5Shape9function1Ev
__ZN5Shape9function1Ev:
[...]
Definition of the vtable itself for 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
Definition of main:
.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
As to what others have been saying that the compiler can elide the virtual dispatch completely or inline the function, that is true. This version of g++ doesn't do it for that particular piece of code, but by removing the pointer (using a Shape
with static storage duration)
精彩评论