[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
What should the call stack look like when calling a C++ virtual function
From: |
Dev1024 |
Subject: |
What should the call stack look like when calling a C++ virtual function? |
Date: |
23 Sep 2006 14:31:05 -0700 |
User-agent: |
G2/1.0 |
Having been a long time user of Microsoft Visual C++ .Net 2003 (MSVC),
I've recently been using g++ on a project. I've found a difference
between the two compilers when calling a virtual function that has me
puzzled. I'm hoping someone will know the answer or point me in the
right direction to find the answer.
The issue is when calling virtual functions. In MSVC the parameters
are pushed on to the stack as expected and then the address of the
function is loaded into EAX. Finally "call EAX" is issues to call the
virtual function. In g++ (Cygwin g++ v3.4.4) the parameters are pushed
onto the stack as expected, but then a pointer (32 bit pointer in my
case) to the vtable is pushed on the stack as well then finally EAX is
loaded with the address of the function.
- Why does g++ load a pointer to the vtable on the stack after pushing
on the params?
- Is there a compiler option that can be used to avoid putting a
pointer to the vtable on the stack? (I looked but couldn't find one.)
Sincere thanks for your time and attention!
Dev1024
Details and background material:
========================================
C++ Source Code
#include <stdio.h>
class ITest
{
public:
void virtual TestFunc(int x, int y, int z) = 0;
};
class Test : ITest
{
public:
Test() {}
~Test() {}
void TestFunc(int x, int y, int z)
{
int a;
a = x + y + z;
}
};
int main (void)
{
ITest *testptr;
testptr = (ITest *) new Test();
testptr->TestFunc(1, 2, 3);
delete testptr;
}
To build with g++:
g++ -g -o myapp main.cpp
In MSVC build as release to get the code below. this remove all the
debug stuff Microsoft adds for error cheching.
============================================
In gdb it is disassembled as follows. Note my comments
(gdb) disas
Dump of assembler code for function main:
0x00401050 <main+0>: push %ebp
0x00401051 <main+1>: mov %esp,%ebp
0x00401053 <main+3>: push %ebx
0x00401054 <main+4>: sub $0x24,%esp
0x00401057 <main+7>: and $0xfffffff0,%esp
0x0040105a <main+10>: mov $0x0,%eax
0x0040105f <main+15>: add $0xf,%eax
0x00401062 <main+18>: add $0xf,%eax
0x00401065 <main+21>: shr $0x4,%eax
0x00401068 <main+24>: shl $0x4,%eax
0x0040106b <main+27>: mov %eax,0xfffffff4(%ebp)
0x0040106e <main+30>: mov 0xfffffff4(%ebp),%eax
0x00401071 <main+33>: call 0x403d50 <_alloca>
0x00401076 <main+38>: call 0x404a90 <__main>
0x0040107b <main+43>: movl $0x4,(%esp)
0x00401082 <main+50>: call 0x4022a0 <_Znwj>
0x00401087 <main+55>: mov %eax,%ebx
0x00401089 <main+57>: mov %ebx,(%esp)
0x0040108c <main+60>: call 0x404e14 <_ZN4TestC1Ev>
0x00401091 <main+65>: mov %ebx,%eax
0x00401093 <main+67>: mov %eax,0xfffffff8(%ebp)
0x00401096 <main+70>: mov 0xfffffff8(%ebp),%eax
0x00401099 <main+73>: mov (%eax),%edx //save the address of
the function in EDX
0x0040109b <main+75>: movl $0x3,0xc(%esp) //push params onto
stack
0x004010a3 <main+83>: movl $0x2,0x8(%esp)
0x004010ab <main+91>: movl $0x1,0x4(%esp)
0x004010b3 <main+99>: mov 0xfffffff8(%ebp),%eax //Address of the
vtable is loaded into EAX
0x004010b6 <main+102>: mov %eax,(%esp) //Now it is pushed
on the stack. Why???????
0x004010b9 <main+105>: mov (%edx),%eax //Load EAX with address of
virtual function
0x004010bb <main+107>: call *%eax
0x004010bd <main+109>: mov 0xfffffff8(%ebp),%eax
0x004010c0 <main+112>: mov %eax,(%esp)
0x004010c3 <main+115>: call 0x402280 <_ZdlPv>
0x004010c8 <main+120>: mov $0x0,%eax
0x004010cd <main+125>: mov 0xfffffffc(%ebp),%ebx
0x004010d0 <main+128>: leave
0x004010d1 <main+129>: ret
===========================================
In MSVC it compiles as follows. Note it does not put a pointer to the
vtable on the stack.
int main (void)
{
00401010 push esi
ITest *testptr;
testptr = (ITest *) new Test();
00401011 push 4
00401013 call operator new (401044h)
00401018 add esp,4
0040101B test eax,eax
0040101D je main+19h (401029h)
0040101F mov dword ptr [eax],offset Test::`vftable' (4060ECh)
00401025 mov esi,eax
00401027 jmp main+1Bh (40102Bh)
00401029 xor esi,esi
testptr->TestFunc(1, 2, 3);
0040102B mov eax,dword ptr [esi]
0040102D push 3
0040102F push 2
00401031 push 1
00401033 mov ecx,esi
00401035 call dword ptr [eax]
delete testptr;
00401037 push esi
00401038 call operator delete (401108h)
0040103D add esp,4
}
00401040 xor eax,eax
00401042 pop esi
00401043 ret
- What should the call stack look like when calling a C++ virtual function?,
Dev1024 <=
- Re: What should the call stack look like when calling a C++ virtual function?, Paul Pluzhnikov, 2006/09/23
- Re: What should the call stack look like when calling a C++ virtual function?, Dev1024, 2006/09/24
- Re: What should the call stack look like when calling a C++ virtual function?, Paul Pluzhnikov, 2006/09/25
- Re: What should the call stack look like when calling a C++ virtual function?, Dev1024, 2006/09/25
- Re: What should the call stack look like when calling a C++ virtual function?, Paul Pluzhnikov, 2006/09/25
- Re: What should the call stack look like when calling a C++ virtual function?, Dev1024, 2006/09/25
- Re: What should the call stack look like when calling a C++ virtual function?, Dev1024, 2006/09/25
- Re: What should the call stack look like when calling a C++ virtual function?, Dev1024, 2006/09/27
- Re: What should the call stack look like when calling a C++ virtual function?, Paul Pluzhnikov, 2006/09/28