Traditionally, compilers implement virtual function calls via dual indirect addressing - if a class contains at least one virtual function, then the address of the virtual function table is stored at the beginning of each object of this class. If the compiler does not know the specific type of object pointed to by the pointer, then to call a virtual function, you must first take a pointer to the object, read the address of the beginning of the table, then read the address where the function implementation is stored, then call the function.class Base { public: virtual ~Base() {} virtual int Magic() { return 9000; } }; class Derived : public Base { public: virtual int Magic() { return 100500; } }; int main() { Derived derived; return derived.Magic(); } main: # @main movl $100500, %eax # imm = 0x18894 ret int magic( Base& object ) { return object.Magic(); } int main() { Base* base = new Derived(); int result = magic( *base ); delete base; return result; } magic(Base&): # @magic(Base&) movq (%rdi), %rax jmpq *(%rax) # TAILCALL main: # @main movl $100500, %eax # imm = 0x18894 ret main: subq $8, %rsp movl $8, %edi call operator new(unsigned long) movq vtable for Derived+16, (%rax) movq %rax, %rdi call Derived::~Derived() movl $100500, %eax addq $8, %rsp ret Derived::~Derived(): jmp operator delete(void*) movq %rax, %rdi call operator delete(void*) magic(Base&): subq $8, %rsp movq (%rdi), %rax call *(%rax) addq $8, %rsp ret main: pushq %rbp pushq %rbx subq $8, %rsp movl $8, %edi call operator new(unsigned long) movq %rax, %rbx movq vtable for Derived+16, (%rax) movq %rax, %rdi call magic(Base&) movl %eax, %ebp testq %rbx, %rbx je .L12 movq (%rbx), %rax movq %rbx, %rdi call *16(%rax) .L12: movl %ebp, %eax addq $8, %rsp popq %rbx popq %rbp ret //Classes.h class Base { public: virtual int Magic(); virtual ~Base(); }; class Derived : public Base { public: virtual int Magic(); }; //Classes.cpp #include <Classes.h> #include <stdio.h> Base::~Base() { } int Base::Magic() { return 9000; } int Derived::Magic() { return 100500; } //main.cpp #include <Classes.h> int magic( Base& object ) { return object.Magic(); } int main() { Base* base = new Derived(); int result = magic( *base ); delete base; return result; } g++ -flto -g -O3 main.cpp Classes.cpp objdump -d -M intel -S --no-show-raw-insn a.exe >a.txt int main() { 402830: push ebp 402831: mov ebp,esp 402833: and esp,0xfffffff0 402836: sub esp,0x10 402839: call 402050 <___main> Base* base = new Derived(); 40283e: mov DWORD PTR [esp],0x4 ::operator new() 402845: call 4015d8 <__Znwj> vtable 40284a: mov DWORD PTR [eax],0x404058 int result = magic( *base ); delete base; 402850: mov ecx,eax 402852: call 4015c0 <__ZN7DerivedD0Ev> return result; } 402857: mov eax,0x18894 40285c: leave 40285d: ret //Factory.h #include <Classes.h> class Factory { public: static Base* CreateInstance(); }; //Factory.cpp #include <Factory.h> Base* Factory::CreateInstance() { return new Derived(); } //main.cpp #include <Factory.h> int magic( Base& object ) { return object.Magic(); } int main() { Base* base = Factory::CreateInstance(); int result = magic( *base ); delete base; return result; } int main() { 402830: push ebp 402831: mov ebp,esp 402833: push esi 402834: push ebx 402835: and esp,0xfffffff0 402838: sub esp,0x10 40283b: call 402050 <___main> return new Derived(); 402840: mov DWORD PTR [esp],0x4 ::operator new() 402847: call 4015d8 <__Znwj> 40284c: mov ebx,eax int magic( Base& object ) { return object.Magic(); 40284e: mov ecx,eax vtable 402850: mov DWORD PTR [eax],0x404058 Derived::Magic() 402856: call 401580 <__ZN7Derived5MagicEv> int main() { delete base; 40285b: mov ecx,ebx 40285d: mov esi,eax 40285f: call 4015b0 <__ZN7DerivedD0Ev> return result; 402864: lea esp,[ebp-0x8] 402867: mov eax,esi 402869: pop ebx 40286a: pop esi 40286b: pop ebp 40286c: ret ( ) 402856: call 401580 <__ZN7Derived5MagicEv> 00401580 <__ZN7Derived5MagicEv>: int Derived::Magic() { return 100500; } 401580: mov eax,0x18894 401585: ret //Factory.h #include <Classes.h> enum ClassType { BaseType, DerivedType }; class Factory { public: static Base* CreateInstance(ClassType classType); }; //Factory.cpp #include <Factory.h> Base* Factory::CreateInstance(ClassType classType) { switch( classType ) { case BaseType: return new Base(); case DerivedType: return new Derived(); } } //main.cpp #include <Factory.h> int magic( Base& object ) { return object.Magic(); } int main() { Base* base = Factory::CreateInstance(DerivedType); int result = magic( *base ); delete base; return result; } #include <Factory.h> #include <cstdlib> int magic( Base& object ) { return object.Magic(); } int main() { Base* base = Factory::CreateInstance(rand() ? BaseType : DerivedType); int result = magic( *base ); delete base; return result; } int main() { 402830: push ebp 402831: mov ebp,esp 402833: push esi 402834: push ebx 402835: and esp,0xfffffff0 402838: sub esp,0x10 40283b: call 402050 <___main> Base* base = Factory::CreateInstance(rand() ? BaseType : DerivedType); rand() 402840: call 4027c8 <_rand> Base* Factory::CreateInstance(ClassType classType) { switch( classType ) { switch 402845: test eax,eax 402847: mov DWORD PTR [esp],0x4 40284e: jne 402875 <_main+0x45> rand() , 402875 rand() , ... case DerivedType: return new Derived(); ::operator new() 402850: call 4015d8 <__Znwj> vtable Derived 402855: mov DWORD PTR [eax],0x404070 40285b: mov ebx,eax int magic( Base& object ) { return object.Magic(); - "" , , 402875 (rand() != 0) 40285d: mov eax,DWORD PTR [ebx] 40285f: mov ecx,ebx Magic() 402861: call DWORD PTR [eax] 402863: mov esi,eax int main() { delete base; 402865: mov eax,DWORD PTR [ebx] 402867: mov ecx,ebx 402869: call DWORD PTR [eax+0x8] return result; } 40286c: lea esp,[ebp-0x8] 40286f: mov eax,esi 402871: pop ebx 402872: pop esi 402873: pop ebp 402874: ret Base* Factory::CreateInstance(ClassType classType) { switch( classType ) { case BaseType: return new Base(); 40284e rand() != 0 ::operator new() 402875: call 4015d8 <__Znwj> vtable Base 40287a: mov DWORD PTR [eax],0x404058 402880: mov ebx,eax 402882: jmp 40285d <_main+0x2d> Source: https://habr.com/ru/post/248429/
All Articles