This is the mail archive of the gcc-patches@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]

[Updated] dllimport/dllexport attributes for Win32/BeOS


Updates since last posting (14-May-1998)
========================================

 - Successfully used by BeOS folks. Needed this in order to have a self-
   hosting GCC. Fred Fish has more info on this.

 - C++ front-end problem fixed (cf: gcc/tree.c(staticp)).

 - Few cleanups. Closely follows Microsoft redeclaration rules now.

 - DLL magic prefix changed from __imp_ to _imp__ to conform to MS 
   standard.  New'ish dlltool creates both, so nobody should suffer 
   because of it.

dllimport and dllexport attributes for i386/pe
===============================================

This patch implements two new attributes, dllimport and dllexport, for 
i386-cygwin32, i386-mingw32* and i386-beos targets, which greatly simplify 
the process of using and creating DLLs. The attributes are specified using 
the usual __attribute__((dllimport)) and __attribute__((dllexport)), or 
via CPP macros __declspec(dllimport) and __declspec(dllexport).

This work is largely due to Doug Evans' work on ARM/PE at Cygnus.

The meat of this patch is about 4 lines of code, and the rest is really
support stuff. See i386_pe_mark_dll{import,export} for RTL mucking.

These patches do not affect code not using the new attributes, and even 
when used, can be reverted to old behavior with -fnop-fun-dllimport. 

Patches are against egcs-19980622 CVS tree. No testsuite regressions for
i386-cygwin32 and i386-mingw32.

What works (or doesn't)?
============================

The C front has gone through limited testing and apparently stable/usable.

The C++ global pointer initialization problem (to variables or functions 
imported from a DLL) is now *fixed* (see the change to gcc/tree.c). The 
last time around, the following did not work:
  
  // file scope
  __attribute__((dllimport) int imported_var;
  int *localvar_p = &imported_var;

nor did this:

  // file scope
  __attribute__((dllimport) int imported_func();
  int (*localfunc_p) = &imported_func;

Since the C++ front-end will parse '&imported_var' as a "static" 
ADDR_EXPR (cf: gcc/cp/typeck.c(build_unary_op), case ADDR_EXPR) and 
backend gets very confused. Both of these need initialization, and
can't treated as "static" as defined by staticp().

Specifying __attribute__((dllexport)) will do the right thing; however,
binutils does not yet take advantage of this information when building 
DLLs.

What doesn't work? I wouldn't know unless this gets integrated and people
start using it on real code and file bug reports.

Regards,
Mumit -- khan@xraylith.wisc.edu

=========================================================================

Mon Jun 22 18:35:56 1998  Mumit Khan  <khan@xraylith.wisc.edu>

	Support for dllimport and dllexport attributes for i386-pe.

	* i386/cygwin32.h (CPP_PREDEFINES): Map __declspec(x) to GCC
	attributes.
	(SUBTARGET_SWITCHES): Switches to turn on/off dllimport|export
	attributes. Also accept -mwindows option.
	(VALID_MACHINE_DECL_ATTRIBUTE): New macro.
	(MERGE_MACHINE_DECL_ATTRIBUTE): New macro.
	(REDO_SECTION_INFO_P): New macro.
	(DRECTVE_SECTION_FUNCTION): New macro.
	(drectve_section): Cover function to implement above.
	(SWITCH_TO_SECTION_FUNCTION): New macro.
	(switch_to_section): Covert function to implement above.
	(EXTRA_SECTIONS): Add in_drectve.
	(EXTRA_SECTION_FUNCTIONS): Add in_drectve and switch_to_section.
	(ENCODE_SECTION_INFO): Delete old macro and redefine as a function.
	(STRIP_NAME_ENCODING): Handle new attributes.
	(ASM_OUTPUT_LABELREF): New macro.
	(ASM_OUTPUT_FUNCTION_NAME): New macro.
	(ASM_OUTPUT_COMMON): New macro.
	(ASM_OUTPUT_DECLARE_OBJECT_NAME): New macro.

	* i386/mingw32.h (CPP_PREDEFINES): Map __declspec(x) to GCC
	attributes.

	* i386/winnt.c (i386_pe_valid_decl_attribute_p): New function.
	(i386_pe_merge_decl_attributes): New function.
	(i386_pe_check_vtable_importexport): New function.
	(i386_pe_dllexport_p): New function.
	(i386_pe_dllimport_p): New function.
	(i386_pe_dllexport_name_p): New function.
	(i386_pe_dllimport_name_p): New function.
	(i386_pe_mark_dllexport): New function.
	(i386_pe_mark_dllimport): New function.
	(i386_pe_encode_section_info): New function.
	(i386_pe_unique_section): Strip encoding from name first.

	* tree.c (staticp): Don't treat DLL imported functions and variables 
	at global scope as static.

Index: gcc/tree.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/tree.c,v
retrieving revision 1.33
diff -u -3 -p -r1.33 tree.c
--- tree.c	1998/06/20 00:35:42	1.33
+++ tree.c	1998/06/22 23:48:53
@@ -2256,10 +2256,26 @@ staticp (arg)
   switch (TREE_CODE (arg))
     {
     case FUNCTION_DECL:
+      /* Don't treat global scope DLL imported functions as static since
+	 taking their address involves initialization.  */
+      if (global_bindings_p ()
+          && lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES(arg))
+             != NULL_TREE)
+	{
+	  return 0;
+	}
       /* Nested functions aren't static, since taking their address
 	 involves a trampoline.  */
        return decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg);
     case VAR_DECL:
+      /* Don't treat global scope DLL imported variables as static since
+	 taking their address involves initialization.  */
+      if (global_bindings_p ()
+          && lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES(arg))
+             != NULL_TREE)
+	{
+	  return 0;
+	}
       return TREE_STATIC (arg) || DECL_EXTERNAL (arg);
 
     case CONSTRUCTOR:
Index: gcc/config/i386/cygwin32.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/i386/cygwin32.h,v
retrieving revision 1.7
diff -u -3 -p -r1.7 cygwin32.h
--- cygwin32.h	1998/04/04 17:38:55	1.7
+++ cygwin32.h	1998/06/22 23:48:53
@@ -30,6 +30,14 @@ Boston, MA 02111-1307, USA. */
 #include "i386/gas.h"
 #include "dbxcoff.h"
 
+/* Support the __declspec keyword by turning them into attributes.
+   We currently only support: dllimport and dllexport.
+   Note that the current way we do this may result in a collision with
+   predefined attributes later on.  This can be solved by using one attribute,
+   say __declspec__, and passing args to it.  The problem with that approach
+   is that args are not accumulated: each new appearance would clobber any
+   existing args.  */
+
 #ifdef CPP_PREDEFINES
 #undef CPP_PREDEFINES
 #endif
@@ -38,6 +46,7 @@ Boston, MA 02111-1307, USA. */
   -D__CYGWIN32__ -DWINNT  -D_X86_=1 -D__STDC__=1\
   -D__stdcall=__attribute__((__stdcall__)) \
   -D__cdecl=__attribute__((__cdecl__)) \
+  -D__declspec(x)=__attribute__((x)) \
   -Asystem(winnt) -Acpu(i386) -Amachine(i386)"
 
 #undef CPP_SPEC
@@ -69,13 +78,51 @@ Boston, MA 02111-1307, USA. */
 #define WCHAR_TYPE "short unsigned int"
 #define HAVE_ATEXIT 1
 
+
+/* Ignore dllimport for functions.  */
+#define TARGET_NOP_FUN_DLLIMPORT (target_flags & 0x20000)
+
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES 			\
+  { "nop-fun-dllimport",	 0x20000 },	\
+  { "no-nop-fun-dllimport",	-0x20000 },	\
+  { "windows",			 0x0     },
+
+/* A C expression whose value is nonzero if IDENTIFIER with arguments ARGS
+   is a valid machine specific attribute for DECL.
+   The attributes in ATTRIBUTES have previously been assigned to DECL.  */
+extern int i386_pe_valid_decl_attribute_p ();
+
+#undef VALID_MACHINE_DECL_ATTRIBUTE
+#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
+  i386_pe_valid_decl_attribute_p (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
+
+extern union tree_node *i386_pe_merge_decl_attributes ();
+#define MERGE_MACHINE_DECL_ATTRIBUTES(OLD, NEW) \
+  i386_pe_merge_decl_attributes ((OLD), (NEW))
+
+/* Used to implement dllexport overriding dllimport semantics.  It's also used
+   to handle vtables - the first pass won't do anything because
+   DECL_CONTEXT (DECL) will be 0 so i386_pe_dll{ex,im}port_p will return 0.
+   It's also used to handle dllimport override semantics.  */
+#if 0
+#define REDO_SECTION_INFO_P(DECL) \
+  ((DECL_MACHINE_ATTRIBUTES (DECL) != NULL_TREE) \
+   || (TREE_CODE (DECL) == VAR_DECL && DECL_VIRTUAL_P (DECL)))
+#else
+#define REDO_SECTION_INFO_P(DECL) 1
+#endif
+
+
 #undef EXTRA_SECTIONS
-#define EXTRA_SECTIONS in_ctor, in_dtor
+#define EXTRA_SECTIONS in_ctor, in_dtor, in_drectve
 
 #undef EXTRA_SECTION_FUNCTIONS
 #define EXTRA_SECTION_FUNCTIONS					\
   CTOR_SECTION_FUNCTION						\
-  DTOR_SECTION_FUNCTION
+  DTOR_SECTION_FUNCTION						\
+  DRECTVE_SECTION_FUNCTION					\
+  SWITCH_TO_SECTION_FUNCTION
 
 #define CTOR_SECTION_FUNCTION					\
 void								\
@@ -99,6 +146,41 @@ dtor_section ()							\
     }								\
 }
 
+#define DRECTVE_SECTION_FUNCTION \
+void									\
+drectve_section ()							\
+{									\
+  if (in_section != in_drectve)						\
+    {									\
+      fprintf (asm_out_file, "%s\n", "\t.section .drectve\n");		\
+      in_section = in_drectve;						\
+    }									\
+}
+
+/* Switch to SECTION (an `enum in_section').
+
+   ??? This facility should be provided by GCC proper.
+   The problem is that we want to temporarily switch sections in
+   ASM_DECLARE_OBJECT_NAME and then switch back to the original section
+   afterwards.  */
+#define SWITCH_TO_SECTION_FUNCTION 				\
+void 								\
+switch_to_section (section, decl) 				\
+     enum in_section section; 					\
+     tree decl; 						\
+{ 								\
+  switch (section) 						\
+    { 								\
+      case in_text: text_section (); break; 			\
+      case in_data: data_section (); break; 			\
+      case in_named: named_section (decl, NULL, 0); break; 	\
+      case in_ctor: ctor_section (); break; 			\
+      case in_dtor: dtor_section (); break; 			\
+      case in_drectve: drectve_section (); break; 		\
+      default: abort (); break; 				\
+    } 								\
+}
+
 #define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME)	\
   do {						\
     ctor_section ();				\
@@ -111,7 +193,7 @@ dtor_section ()							\
   do {						\
     dtor_section ();                   		\
     fprintf (FILE, "%s\t", ASM_LONG);		\
-    assemble_name (FILE, NAME);              	\
+    assemble_name (FILE, NAME);			\
     fprintf (FILE, "\n");			\
   } while (0)
 
@@ -119,44 +201,38 @@ dtor_section ()							\
    differently depending on something about the variable or
    function named by the symbol (such as what section it is in).
 
-   On i386, if using PIC, mark a SYMBOL_REF for a non-global symbol
-   so that we may access it directly in the GOT.
-
    On i386 running Windows NT, modify the assembler name with a suffix 
    consisting of an atsign (@) followed by string of digits that represents
    the number of bytes of arguments passed to the function, if it has the 
-   attribute STDCALL. */
+   attribute STDCALL.
+
+   In addition, we must mark dll symbols specially. Definitions of 
+   dllexport'd objects install some info in the .drectve section.  
+   References to dllimport'd objects are fetched indirectly via
+   _imp__.  If both are declared, dllexport overrides.  This is also 
+   needed to implement one-only vtables: they go into their own
+   section and we need to set DECL_SECTION_NAME so we do that here.
+   Note that we can be called twice on the same decl.  */
+
+extern void i386_pe_encode_section_info ();
 
 #ifdef ENCODE_SECTION_INFO
 #undef ENCODE_SECTION_INFO
-#define ENCODE_SECTION_INFO(DECL) 					\
-do									\
-  {									\
-    if (flag_pic)							\
-      {									\
-	rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd'		\
-		   ? TREE_CST_RTL (DECL) : DECL_RTL (DECL));		\
-	SYMBOL_REF_FLAG (XEXP (rtl, 0))					\
-	  = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd'			\
-	     || ! TREE_PUBLIC (DECL));					\
-      }									\
-    if (TREE_CODE (DECL) == FUNCTION_DECL) 				\
-      if (lookup_attribute ("stdcall",					\
-			    TYPE_ATTRIBUTES (TREE_TYPE (DECL))))	\
-        XEXP (DECL_RTL (DECL), 0) = 					\
-          gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (DECL)); 	\
-  }									\
-while (0)
 #endif
+#define ENCODE_SECTION_INFO(DECL) i386_pe_encode_section_info (DECL)
 
-/* This macro gets just the user-specified name out of the string in a
-   SYMBOL_REF.  Discard trailing @[NUM] encoded by ENCODE_SECTION_INFO.   */
-
+/* Utility used only in this file.  */
+#define I386_PE_STRIP_ENCODING(SYM_NAME) \
+  ((SYM_NAME) + ((SYM_NAME)[0] == '@' ? 3 : 0))
+
+/* This macro gets just the user-specified name
+   out of the string in a SYMBOL_REF.  Discard
+   trailing @[NUM] encoded by ENCODE_SECTION_INFO.  */
 #undef  STRIP_NAME_ENCODING
 #define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME)				\
 do {									\
   char *_p;								\
-  char *_name = ((SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*'));		\
+  char *_name = I386_PE_STRIP_ENCODING (SYMBOL_NAME);			\
   for (_p = _name; *_p && *_p != '@'; ++_p)				\
     ;									\
   if (*_p == '@')							\
@@ -170,6 +246,65 @@ do {									\
     (VAR) = _name;							\
 } while (0)
       
+
+/* Output a reference to a label.  */
+#undef ASM_OUTPUT_LABELREF
+#define ASM_OUTPUT_LABELREF(STREAM, NAME)  		\
+  fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, 		\
+           I386_PE_STRIP_ENCODING (NAME))		\
+
+/* Output a function definition label.  */
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL)	\
+do {							\
+  if (i386_pe_dllexport_name_p (NAME))			\
+    {							\
+      drectve_section ();				\
+      fprintf ((STREAM), "\t.ascii \" -export:%s\"\n", 	\
+               I386_PE_STRIP_ENCODING (NAME));		\
+      function_section (DECL);				\
+    }							\
+  ASM_OUTPUT_LABEL ((STREAM), (NAME));			\
+} while (0)
+
+#undef ASM_COMMENT_START
+#define ASM_COMMENT_START " #"
+
+/* Output a common block.  */
+#undef ASM_OUTPUT_COMMON
+#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED)	\
+do {							\
+  if (i386_pe_dllexport_name_p (NAME))			\
+    {							\
+      drectve_section ();				\
+      fprintf ((STREAM), "\t.ascii \" -export:%s\"\n",	\
+               I386_PE_STRIP_ENCODING (NAME));		\
+    }							\
+  if (! i386_pe_dllimport_name_p (NAME))		\
+    {							\
+      fprintf ((STREAM), "\t.comm\t"); 			\
+      assemble_name ((STREAM), (NAME));			\
+      fprintf ((STREAM), ", %d\t%s %d\n",		\
+	       (ROUNDED), ASM_COMMENT_START, (SIZE));	\
+    }							\
+} while (0)
+
+/* Output the label for an initialized variable.  */
+#undef ASM_DECLARE_OBJECT_NAME
+#define ASM_DECLARE_OBJECT_NAME(STREAM, NAME, DECL) 	\
+do {							\
+  if (i386_pe_dllexport_name_p (NAME))			\
+    {							\
+      enum in_section save_section = in_section;	\
+      drectve_section ();				\
+      fprintf ((STREAM), "\t.ascii \" -export:%s\"\n",	\
+               I386_PE_STRIP_ENCODING (NAME));		\
+      switch_to_section (save_section, (DECL));		\
+    }							\
+  ASM_OUTPUT_LABEL ((STREAM), (NAME));			\
+} while (0)
+
+
 /* Emit code to check the stack when allocating more that 4000
    bytes in one go. */
 
@@ -224,11 +359,9 @@ do {								\
 	     ? "discard" : "same_size");			\
 } while (0)
 
-#undef ASM_COMMENT_START
-#define ASM_COMMENT_START " #"
-
 /* DWARF2 Unwinding doesn't work with exception handling yet. */
 #define DWARF2_UNWIND_INFO 0
 
 /* Don't assume anything about the header files. */
 #define NO_IMPLICIT_EXTERN_C
+
Index: gcc/config/i386/mingw32.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/i386/mingw32.h,v
retrieving revision 1.3
diff -u -3 -p -r1.3 mingw32.h
--- mingw32.h	1998/04/04 17:38:59	1.3
+++ mingw32.h	1998/06/22 23:48:53
@@ -31,6 +31,7 @@ Boston, MA 02111-1307, USA. */
   -D__MINGW32__ -DWINNT  -D_X86_=1 -D__STDC__=1\
   -D__stdcall=__attribute__((__stdcall__)) \
   -D__cdecl=__attribute__((__cdecl__)) \
+  -D__declspec(x)=__attribute__((x)) \
   -Asystem(winnt) -Acpu(i386) -Amachine(i386)"
 
 /* Specific a different directory for the standard include files.  */
Index: gcc/config/i386/winnt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/i386/winnt.c,v
retrieving revision 1.3
diff -u -3 -p -r1.3 winnt.c
--- winnt.c	1998/05/13 14:04:08	1.3
+++ winnt.c	1998/06/22 23:48:54
@@ -28,6 +28,346 @@ Boston, MA 02111-1307, USA.  */
 #include "tree.h"
 #include "flags.h"
 
+/* i386/PE specific attribute support.
+
+   i386/PE has two new attributes:
+   dllexport - for exporting a function/variable that will live in a dll
+   dllimport - for importing a function/variable from a dll
+
+   Microsoft allows multiple declspecs in one __declspec, separating
+   them with spaces.  We do NOT support this.  Instead, use __declspec
+   multiple times.
+*/
+
+/* Return nonzero if ATTR is a valid attribute for DECL.
+   ATTRIBUTES are any existing attributes and ARGS are the arguments
+   supplied with ATTR.  */
+
+int
+i386_pe_valid_decl_attribute_p (decl, attributes, attr, args)
+     tree decl;
+     tree attributes;
+     tree attr;
+     tree args;
+{
+  if (args != NULL_TREE)
+    return 0;
+
+  if (is_attribute_p ("dllexport", attr))
+    return 1;
+  if (is_attribute_p ("dllimport", attr))
+    return 1;
+
+  return i386_valid_decl_attribute_p (decl, attributes, attr, args);
+}
+
+/* Merge attributes in decls OLD and NEW.
+
+   This handles the following situation:
+
+   __declspec (dllimport) int foo;
+   int foo;
+
+   The second instance of `foo' nullifies the dllimport.  */
+
+tree
+i386_pe_merge_decl_attributes (old, new)
+     tree old, new;
+{
+  tree a;
+  int delete_dllimport_p;
+
+  old = DECL_MACHINE_ATTRIBUTES (old);
+  new = DECL_MACHINE_ATTRIBUTES (new);
+
+  /* What we need to do here is remove from `old' dllimport if it doesn't
+     appear in `new'.  dllimport behaves like extern: if a declaration is
+     marked dllimport and a definition appears later, then the object
+     is not dllimport'd.  */
+
+  if (lookup_attribute ("dllimport", old) != NULL_TREE
+      && lookup_attribute ("dllimport", new) == NULL_TREE)
+    delete_dllimport_p = 1;
+  else
+    delete_dllimport_p = 0;
+
+  a = merge_attributes (old, new);
+
+  if (delete_dllimport_p)
+    {
+      tree prev,t;
+
+      /* Scan the list for dllimport and delete it.  */
+      for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t))
+	{
+	  if (is_attribute_p ("dllimport", TREE_PURPOSE (t)))
+	    {
+	      if (prev == NULL_TREE)
+		a = TREE_CHAIN (a);
+	      else
+		TREE_CHAIN (prev) = TREE_CHAIN (t);
+	      break;
+	    }
+	}
+    }
+
+  return a;
+}
+
+/* Check a type that has a virtual table, and see if any virtual methods are
+   marked for import or export, and if so, arrange for the vtable to
+   be imported or exported.  */
+
+static int
+i386_pe_check_vtable_importexport (type)
+     tree type;
+{
+  tree methods = TYPE_METHODS (type);
+  tree fndecl;
+
+  if (TREE_CODE (methods) == FUNCTION_DECL)
+    fndecl = methods;
+  else if (TREE_VEC_ELT (methods, 0) != NULL_TREE)
+    fndecl = TREE_VEC_ELT (methods, 0);
+  else
+    fndecl = TREE_VEC_ELT (methods, 1);
+
+  while (fndecl)
+    {
+      if (DECL_VIRTUAL_P (fndecl) || DECL_VINDEX (fndecl) != NULL_TREE)
+	{
+	  tree exp = lookup_attribute ("dllimport",
+				       DECL_MACHINE_ATTRIBUTES (fndecl));
+	  if (exp == 0)
+	    exp = lookup_attribute ("dllexport",
+				    DECL_MACHINE_ATTRIBUTES (fndecl));
+	  if (exp)
+	    return 1;
+	}
+
+      fndecl = TREE_CHAIN (fndecl);
+    }
+
+  return 0;
+}
+
+/* Return non-zero if DECL is a dllexport'd object.  */
+
+#if 0
+tree current_class_type; /* FIXME */
+#endif
+
+int
+i386_pe_dllexport_p (decl)
+     tree decl;
+{
+  tree exp;
+
+  if (TREE_CODE (decl) != VAR_DECL
+      && TREE_CODE (decl) != FUNCTION_DECL)
+    return 0;
+  exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl));
+  if (exp)
+    return 1;
+
+#if 0 /* This was a hack to get vtable's exported or imported since only one
+	 copy of them is ever output.  Disabled pending better solution.  */
+  /* For C++, the vtables might have to be marked.  */
+  if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
+    {
+      if (TREE_PUBLIC (decl)
+	  && DECL_EXTERNAL (decl) == 0
+	  && (DECL_CONTEXT (decl)
+	      ? i386_pe_check_vtable_importexport (DECL_CONTEXT (decl))
+	      : current_class_type
+	      ? i386_pe_check_vtable_importexport (current_class_type)
+	      : 0)
+	  )
+	return 1;
+    }
+#endif
+
+  return 0;
+}
+
+/* Return non-zero if DECL is a dllimport'd object.  */
+
+int
+i386_pe_dllimport_p (decl)
+     tree decl;
+{
+  tree imp;
+
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && TARGET_NOP_FUN_DLLIMPORT)
+    return 0;
+
+  if (TREE_CODE (decl) != VAR_DECL
+      && TREE_CODE (decl) != FUNCTION_DECL)
+    return 0;
+  imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl));
+  if (imp)
+    return 1;
+
+#if 0 /* This was a hack to get vtable's exported or imported since only one
+	 copy of them is ever output.  Disabled pending better solution.  */
+  /* For C++, the vtables might have to be marked.  */
+  if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
+    {
+      if (TREE_PUBLIC (decl)
+	  && DECL_EXTERNAL (decl)
+	  && (DECL_CONTEXT (decl)
+	      ? i386_pe_check_vtable_importexport (DECL_CONTEXT (decl))
+	      : current_class_type
+	      ? i386_pe_check_vtable_importexport (current_class_type)
+	      : 0)
+	  )
+	return 1;
+    }
+#endif
+
+  return 0;
+}
+
+/* Return non-zero if SYMBOL is marked as being dllexport'd.  */
+
+int
+i386_pe_dllexport_name_p (symbol)
+     char *symbol;
+{
+  return symbol[0] == '@' && symbol[1] == 'e' && symbol[2] == '.';
+}
+
+/* Return non-zero if SYMBOL is marked as being dllimport'd.  */
+
+int
+i386_pe_dllimport_name_p (symbol)
+     char *symbol;
+{
+  return symbol[0] == '@' && symbol[1] == 'i' && symbol[2] == '.';
+}
+
+/* Mark a DECL as being dllexport'd.
+   Note that we override the previous setting (eg: dllimport).  */
+
+void
+i386_pe_mark_dllexport (decl)
+     tree decl;
+{
+  char *oldname, *newname;
+  rtx rtlname;
+  tree idp;
+
+  rtlname = XEXP (DECL_RTL (decl), 0);
+  if (GET_CODE (rtlname) == SYMBOL_REF)
+    oldname = XSTR (rtlname, 0);
+  else if (GET_CODE (rtlname) == MEM
+	   && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
+    oldname = XSTR (XEXP (rtlname, 0), 0);
+  else
+    abort ();
+  if (i386_pe_dllimport_name_p (oldname))
+    oldname += 9;
+  else if (i386_pe_dllexport_name_p (oldname))
+    return; /* already done */
+
+  newname = alloca (strlen (oldname) + 4);
+  sprintf (newname, "@e.%s", oldname);
+
+  /* We pass newname through get_identifier to ensure it has a unique
+     address.  RTL processing can sometimes peek inside the symbol ref
+     and compare the string's addresses to see if two symbols are
+     identical.  */
+  /* ??? At least I think that's why we do this.  */
+  idp = get_identifier (newname);
+
+  XEXP (DECL_RTL (decl), 0) =
+    gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
+}
+
+/* Mark a DECL as being dllimport'd.  */
+
+void
+i386_pe_mark_dllimport (decl)
+     tree decl;
+{
+  char *oldname, *newname;
+  tree idp;
+  rtx rtlname, newrtl;
+
+  rtlname = XEXP (DECL_RTL (decl), 0);
+  if (GET_CODE (rtlname) == SYMBOL_REF)
+    oldname = XSTR (rtlname, 0);
+  else if (GET_CODE (rtlname) == MEM
+	   && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
+    oldname = XSTR (XEXP (rtlname, 0), 0);
+  else if (i386_pe_dllexport_name_p (oldname))
+    {
+      error ("`%s' declared as both exported to and imported from a DLL.",
+             IDENTIFIER_POINTER (DECL_NAME (decl)));
+      return;
+    }
+  else if (i386_pe_dllimport_name_p (oldname))
+    {
+      /* Already done, but force correct linkage since the redeclaration 
+         might have omitted explicit extern.  Sigh.  */
+      if (TREE_CODE (decl) == VAR_DECL
+	  /* ??? Is this test for vtables needed?  */
+	  && !DECL_VIRTUAL_P (decl))
+	{
+	  DECL_EXTERNAL (decl) = 1;
+	  TREE_PUBLIC (decl) = 1;
+	}
+	return;
+    }
+
+  /* ??? One can well ask why we're making these checks here,
+     and that would be a good question.  */
+
+  /* Imported variables can't be initialized.  */
+  if (TREE_CODE (decl) == VAR_DECL
+      && !DECL_VIRTUAL_P (decl)
+      && DECL_INITIAL (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?  */
+      && !DECL_VIRTUAL_P (decl)
+      && 0 /*???*/)
+    {
+      error_with_decl (decl, "static variable `%s' 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
+      /* ??? Is this test for vtables needed?  */
+      && !DECL_VIRTUAL_P (decl))
+    {
+      DECL_EXTERNAL (decl) = 1;
+      TREE_PUBLIC (decl) = 1;
+    }
+
+  newname = alloca (strlen (oldname) + 11);
+  sprintf (newname, "@i._imp__%s", oldname);
+
+  /* We pass newname through get_identifier to ensure it has a unique
+     address.  RTL processing can sometimes peek inside the symbol ref
+     and compare the string's addresses to see if two symbols are
+     identical.  */
+  /* ??? At least I think that's why we do this.  */
+  idp = get_identifier (newname);
+
+  newrtl = gen_rtx (MEM, Pmode,
+		    gen_rtx (SYMBOL_REF, Pmode,
+			     IDENTIFIER_POINTER (idp)));
+  XEXP (DECL_RTL (decl), 0) = newrtl;
+}
+
 /* Return string which is the former assembler name modified with a 
    suffix consisting of an atsign (@) followed by the number of bytes of 
    arguments */
@@ -66,6 +406,56 @@ gen_stdcall_suffix (decl)
   return IDENTIFIER_POINTER (get_identifier (newsym));
 }
 
+/* Cover function to implement ENCODE_SECTION_INFO.  */
+
+void
+i386_pe_encode_section_info (decl)
+     tree decl;
+{
+  /* This bit is copied from i386.h.  */
+  if (optimize > 0 && TREE_CONSTANT (decl)
+      && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST))
+    {
+      rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
+                 ? TREE_CST_RTL (decl) : DECL_RTL (decl));
+      SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
+    }
+
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    if (lookup_attribute ("stdcall",
+			  TYPE_ATTRIBUTES (TREE_TYPE (decl))))
+      XEXP (DECL_RTL (decl), 0) = 
+	gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl));
+
+  /* Mark the decl so we can tell from the rtl whether the object is
+     dllexport'd or dllimport'd.  */
+
+  if (i386_pe_dllexport_p (decl))
+    i386_pe_mark_dllexport (decl);
+  else if (i386_pe_dllimport_p (decl))
+    i386_pe_mark_dllimport (decl);
+  /* It might be that DECL has already been marked as dllimport, but a
+     subsequent definition nullified that.  The attribute is gone but
+     DECL_RTL still has @i._imp__foo.  We need to remove that.  */
+  else if ((TREE_CODE (decl) == FUNCTION_DECL
+	    || TREE_CODE (decl) == VAR_DECL)
+	   && DECL_RTL (decl) != NULL_RTX
+	   && GET_CODE (DECL_RTL (decl)) == MEM
+	   && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
+	   && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF
+	   && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0)))
+    {
+      char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
+      tree idp = get_identifier (oldname + 9);
+      rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
+
+      XEXP (DECL_RTL (decl), 0) = newrtl;
+
+      /* We previously set TREE_PUBLIC and DECL_EXTERNAL.
+	 ??? We leave these alone for now.  */
+    }
+}
+
 /* Cover function for UNIQUE_SECTION.  */
 
 void
@@ -77,6 +467,8 @@ i386_pe_unique_section (decl, reloc)
   char *name,*string,*prefix;
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  /* Strip off any encoding in fnname.  */
+  STRIP_NAME_ENCODING (name, name);
 
   /* The object is put in, for example, section .text$foo.
      The linker will then ultimately place them in .text


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