I modified the old TestClass to include a virtual method:
class TestClass
{
public:
// _ZN9TestClassC1Ev
TestClass()
{
stuff = 1;
}
// _ZN9TestClassD1Ev
virtual ~TestClass()
{
stuff = 0;
}
// _ZN9TestClass8GetStuffEv
virtual int GetStuff()
{
return stuff;
}
private:
int stuff;
};
// _Z4DoItP9TestClass
int DoIt(TestClass* t1)
{
return t1->GetStuff();
}
int main()
{
TestClass* t1 = new TestClass();
int r = DoIt(t1);
delete t1;
return r;
}
Let's look at the disassebly of the function DoIt:
0804869d <_Z4DoItP9TestClass>: 804869d: push %ebp 804869e: mov %esp,%ebp 80486a0: lea -0x1028(%esp),%esp 80486a7: orl $0x0,(%esp) 80486ab: lea 0x1010(%esp),%esp 80486b2: mov 0x8(%ebp),%eax ; t1 = ebp + 8 80486b5: mov (%eax),%eax ; obj = *t1 80486b7: add $0x8,%eax ; 80486ba: mov (%eax),%eax ; GetStuff = obj[8] 80486bc: mov 0x8(%ebp),%edx 80486bf: mov %edx,(%esp) 80486c2: call *%eax ; GetStuff(this) 80486c4: leave 80486c5: ret
Unlike previous usages, the DoIt disassembly doesn't contain an explict call to GetStuff. Instead, there is a call to register eax, which is initialized by deferencing a field of TestClass. This particular field is not present into the C++ code, thus we must look at the disassembled constructor:
080487a6 <_ZN9TestClassC1Ev>: 80487a6: push %ebp 80487a7: mov %esp,%ebp 80487a9: lea -0x1010(%esp),%esp 80487b0: orl $0x0,(%esp) 80487b4: lea 0x1010(%esp),%esp 80487bb: mov 0x8(%ebp),%eax 80487be: movl $0x8048910,(%eax) ; this[0] = 0x8048910 80487c4: mov 0x8(%ebp),%eax 80487c7: movl $0x1,0x4(%eax) ; this->stuff = 1; 80487ce: pop %ebp 80487cf: ret
The address 0x8048910 resides in the .rodata section and point to the Virtual Table of TestClass. The vtable contains references to all virtual methods present in TestClass:
Contents of section .rodata: 8048900 03000000 01000200 00000000 28890408 ............(... 8048910 d0870408 0e880408 3c880408 39546573 ........<...9Tes 8048920 74436c61 73730000 28a00408 1c890408 tClass..(....... // TestClass virtual table: 0x8048910 + 0x00: 080487d0 ; _ZN9TestClassD1Ev (Complete Object destructor) 0x8048910 + 0x04: 0804880e ; _ZN9TestClassD0Ev (Deleting destructor) 0x8048910 + 0x08: 0804883c ; _ZN9TestClass8GetStuffEv (GetStuff)
To expain the difference between the two destruction, I quote the C++ ABI Itanium reference:
- Base object destructor of a class T: A function that runs the destructors for non-static data members of T and non-virtual direct base classes of T. Mangled with suffix D2.
- Complete object destructor of a class T: a function that, in addition to the actions required of a base object destructor, runs the destructors for the virtual base classes of T. Mangled with suffix D1.
- Deleting destructor of a class T: a function that, in addition to the actions required of a complete object destructor, calls the appropriate deallocation function (i.e,. operator delete) for T. Mangled with suffix D0.