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

Mumit Khan khan@nanotech.wisc.edu
Sat Dec 11 18:22:00 GMT 1999


Jason Merrill <jason@cygnus.com> writes:
> >>>>> Mumit Khan <khan@nanotech.wisc.edu> writes:
> 
>  >     For subclasses of dllimported functions, vtables reference the
>  >     *thunk* functions, not the synthetically created indirect references
>  >     (by backend in i386_pe_mark_dllimport); this is needed to allow 
>  >     taking the address of the virtual function. This is one thing that 
>  >     needs to be changed in current GCC implementation (eg., by 
>  >     nullifying the dllimport attribute of virtual functions in the 
>  >     backend, or dealing with specifically in the front-end).
> 
> Shouldn't the backend just treat code that wants the address of a function
> differently?

Yes, it should, and it does. I believe I have the changes needed to get the 
whole mess to work, w/out any change to current C++ front-end. The trick
here is to make sure virtual functions (* see below) and vtables are not
imported; if not, the vtable generation will fail. In fact, since vtables
are always generated (MULTIPLE_SYMBOL_SPACES in import_export_class), we
don't need to import vtables by reference from a DLL, and it's always works.

(*) unfortunately, I can't find any way in the target-dependent file to
figure out if a function is really virtual or not just by checking
DECL_VIRTUAL_P or DECL_VINDEX when marking dllimports. It works for:
  
  struct IMPORT base {
    virtual void foo ();
  }
  struct IMPORT derived1 {
    virtual void foo ();
  }

but not for,
  
  struct IMPORT base {
    virtual void foo ();
  }
  struct IMPORT derived1 {
    void foo ();
  }

So, I have to disable importing of all methods. This has no effect on the
user code other than a tiny penalty in calling the thunk instead.

Jason, ideas? here's the patch to i386/winnt.c, which fixes all the bug
reports of this type I've received to date. Unless you have an objection
to this, I'll submit it to gcc-patches after a bit of cleanup. The term
"thunk" used here is the thunk in the import library, and not as in
vtable thunks.

Fri Dec 10 19:29:48 1999  Mumit Khan  <khan@xraylith.wisc.edu>

	* i386/config/winnt.c (i386_pe_dllimport_p): Don't import inline
	functions, and C++ methods and vtables.
	* (i386_pe_mark_dllimport): Handle illegal dllimports.

Index: winnt.c
===================================================================
RCS file: /homes/khan/src/CVSROOT/gcc-2.95.2/gcc/config/i386/winnt.c,v
retrieving revision 1.4
diff -u -3 -p -r1.4 winnt.c
--- winnt.c	1999/11/05 08:21:44	1.4
+++ winnt.c	1999/12/11 01:39:02
@@ -214,6 +214,34 @@ i386_pe_dllimport_p (decl)
   if (TREE_CODE (decl) != VAR_DECL
       && TREE_CODE (decl) != FUNCTION_DECL)
     return 0;
+
+  /* We ignore the attribute for inline functions. */
+  if (TREE_CODE (decl) == FUNCTION_DECL 
+      && DECL_INITIAL (decl) 
+      && DECL_INLINE (decl) 
+      && TREE_CODE (TREE_TYPE (decl)) != METHOD_TYPE)
+    {
+      return 0;
+    }
+  
+  /* Also turn off importing C++ virtual methods to able to create 
+     vtables using thunks. 
+     
+     FIXME: However, since there is no way to tell if the type is 
+     really virtual at this point (the declaration of the method in 
+     a derived class may not have the virtual keyword), we just turn 
+     off all methods at the expense of slight performance penalty.  */
+  if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+    {
+      return 0;
+    }
+
+  /* Likewise for vtables. */
+  if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
+    {
+      return 0;
+    }
+
   imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl));
   if (imp)
     return 1;
@@ -342,6 +370,7 @@ i386_pe_mark_dllimport (decl)
       error_with_decl (decl, "initialized variable `%s' is marked dllimport");
       return;
     }
+
   /* Nor can they be static.  */
   if (TREE_CODE (decl) == VAR_DECL
       /* ??? Is this test for vtables needed?  */
@@ -352,6 +381,14 @@ i386_pe_mark_dllimport (decl)
       return;
     }
 
+  /* Nor can you define an imported function. */
+  if (TREE_CODE (decl) == FUNCTION_DECL 
+      && DECL_INITIAL (decl) && ! DECL_INLINE (decl))
+    {
+      error_with_decl (decl, "function `%s' definition is marked dllimport");
+      return;
+    }
+  
   /* `extern' needn't be specified with dllimport.
      Specify `extern' now and hope for the best.  Sigh.  */
   if (TREE_CODE (decl) == VAR_DECL
@@ -361,7 +398,7 @@ i386_pe_mark_dllimport (decl)
       DECL_EXTERNAL (decl) = 1;
       TREE_PUBLIC (decl) = 1;
     }
-
+  
   newname = alloca (strlen (oldname) + 11);
   sprintf (newname, "@i._imp__%s", oldname);
 
Regards,
Mumit



More information about the Gcc mailing list