This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Workaround for virtual function/dllimport bug, also patch guidance request


If I understand your question, you want to know how MSVC++ handles virtual
functions marked as "dllimport".  Having implemented some level of
compatability with VC++ in CodeWarrior, this is what I've observed.

There are two possible ways the function can be marked as dllimport.

1) the member function itself was marked

    class foo { __declspec(dllimport) virtual void bar(); }

2) the entire class was marked

    __declspec(dllimport) class foo2 { virtual void bar(); }

In both cases, a call to bar through a pointer to foo would go through the
vtable with no changes in the generated code.  However, case 1 will have the
vtable be staticly linked while case 2 will have the vtable be imported from
the DLL.  A constructor for foo in case 1 would resolve the vtable to
??_7foo@@6B@, but case 2 would be an indirect reference through
__imp_??_7foo2@@6B@ to get the address of the vtable plus an offset of 8 to
skip over the RTTI pointers.

Here is a disassembly of the two constructors from the CodeWarrior 2.3.1
compiler to show the difference.  Also included is the disassembly of a
function that accesses foo->bar().  Oh, this is VC++/MASM style assembly, so
reverse the fields mentally if needed.

============================================================================
====
SECTION SIZE = 0x00000017; NAME =    .text

DEFINED SYMBOLS:

name = ??0foo@@QAE@XZ
unmangled name = foo::foo()
offset = 0x00000000; type = 0x0020; class = 0x0002

00000000: 55                  push      ebp
00000001: 89 E5               mov       ebp,esp
00000003: 83 EC 08            sub       esp,8
00000006: 89 4D FC            mov       dword ptr [ebp-4],ecx
00000009: 8B 45 FC            mov       eax,dword ptr [ebp-4]
0000000C: C7 00 08 00 00 00   mov       dword ptr [eax],offset
??_7foo@@6B@+8
00000012: 8B 45 FC            mov       eax,dword ptr [ebp-4]
00000015: C9                  leave
00000016: C3                  ret       near

============================================================================
====
SECTION SIZE = 0x0000001C; NAME =    .text

DEFINED SYMBOLS:

name = ??0foo2@@QAE@XZ
unmangled name = foo2::foo2()
offset = 0x00000000; type = 0x0020; class = 0x0002

00000000: 55                  push      ebp
00000001: 89 E5               mov       ebp,esp
00000003: 83 EC 08            sub       esp,8
00000006: 89 4D FC            mov       dword ptr [ebp-4],ecx
00000009: 8B 15 00 00 00 00   mov       edx,dword ptr __imp_??_7foo2@@6B@
0000000F: 83 C2 08            add       edx,8
00000012: 8B 45 FC            mov       eax,dword ptr [ebp-4]
00000015: 89 10               mov       dword ptr [eax],edx
00000017: 8B 45 FC            mov       eax,dword ptr [ebp-4]
0000001A: C9                  leave
0000001B: C3                  ret       near

============================================================================
====
SECTION SIZE = 0x00000020; NAME =    .text

DEFINED SYMBOLS:

name = ?foobar@@YAXXZ
unmangled name = void foobar()
offset = 0x00000000; type = 0x0020; class = 0x0002

00000000: 55                  push      ebp
00000001: 89 E5               mov       ebp,esp
00000003: 56                  push      esi
00000004: 8B 0D 00 00 00 00   mov       ecx,dword ptr ?f@@3PAUfoo@@A
0000000A: 8B 31               mov       esi,dword ptr [ecx]
0000000C: FF 16               call      dword ptr [esi] near
0000000E: 8B 0D 00 00 00 00   mov       ecx,dword ptr ?f2@@3PAUfoo2@@A
00000014: 8B 31               mov       esi,dword ptr [ecx]
00000016: FF 16               call      dword ptr [esi] near
00000018: EB 00               jmp       $+2 ; --> 0x001a
0000001A: 8D 65 FC            lea       esp,dword ptr [ebp-4]
0000001D: 5E                  pop       esi
0000001E: 5D                  pop       ebp
0000001F: C3                  ret       near

When I modified the code to be dllexport (the code within the DLL), the
generated constructor code was the same, since accessing the vtable acts
like the static case from inside the DLL.

I'm at home, so I cannot verify if VC++ does exactly the same thing, but I
know we're very close in this area... I've personally had to look at several
bug reports about these kind of things.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]