]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Support for dllimport and dllexport attributes for i386-pe.
authorMumit Khan <khan@xraylith.wisc.edu>
Tue, 7 Jul 1998 00:05:27 +0000 (00:05 +0000)
committerJeff Law <law@gcc.gnu.org>
Tue, 7 Jul 1998 00:05:27 +0000 (18:05 -0600)
* tree.h (DECL_NON_ADDR_CONST_P): New accessor macro.
(struct tree_decl): Add non_addr_const_p field.
* tree.c (staticp): Use.
* 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.

From-SVN: r20983

gcc/ChangeLog
gcc/config/i386/cygwin32.h
gcc/config/i386/mingw32.h
gcc/config/i386/winnt.c
gcc/tree.c
gcc/tree.h

index 01affd1bcabc7c5b657525d41e4d7f0ec29390c2..d258618c837b12871ed51332a820f2a4fa6ce901 100644 (file)
@@ -1,3 +1,46 @@
+Tue Jul  7 01:03:03 1998  Mumit Khan <khan@xraylith.wisc.edu>
+
+       Support for dllimport and dllexport attributes for i386-pe.
+
+       * tree.h (DECL_NON_ADDR_CONST_P): New accessor macro.
+       (struct tree_decl): Add non_addr_const_p field.
+       * tree.c (staticp): Use.
+
+       * 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.
+
 Tue Jul  7 00:50:17 1998  Manfred Hollstein   (manfred@s-direktnet.de)
 
         * libgcc2.c (L_exit): Provide a fake for atexit on systems which
index 1677422af9119fd84322103bc44e37e2fbeab6ce..f76cd534add849ec2ce6b5a8a0094a5de76049b2 100644 (file)
@@ -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
 
+\f
+/* 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
+
+\f
 #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,62 @@ do {                                                                       \
     (VAR) = _name;                                                     \
 } while (0)
       
+\f
+/* 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)
+
+/* 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)
+
+\f
 /* Emit code to check the stack when allocating more that 4000
    bytes in one go. */
 
index 7c7a3bbc6faa3e30772c838d2b7eb074056b4b30..19299621f7b60994e3d715207d7e941e02659e86 100644 (file)
@@ -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 2f4cc888f6660000b65238e334b8dade81910353..95daf14ff90866e1b8f73cc558e2ab2996ad553e 100644 (file)
@@ -28,6 +28,351 @@ 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;
+}
+\f
+/* 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.  */
+  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
+    abort ();
+  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. Note that C++ classes
+     are marked initial, so we need to check.  */
+  if (TREE_CODE (decl) == VAR_DECL
+      && !DECL_VIRTUAL_P (decl)
+      && (DECL_INITIAL (decl)
+          && ! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (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.  */
+  idp = get_identifier (newname);
+
+  newrtl = gen_rtx (MEM, Pmode,
+                   gen_rtx (SYMBOL_REF, Pmode,
+                            IDENTIFIER_POINTER (idp)));
+  XEXP (DECL_RTL (decl), 0) = newrtl;
+
+  /* Can't treat a pointer to this as a constant address */
+  DECL_NON_ADDR_CONST_P (decl) = 1;
+}
+
 /* 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 +411,59 @@ 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. Ditto
+     for the DECL_NON_ADDR_CONST_P flag.  */
+  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;
+
+      DECL_NON_ADDR_CONST_P (decl) = 0;
+
+      /* We previously set TREE_PUBLIC and DECL_EXTERNAL.
+        We leave these alone for now.  */
+    }
+}
+
 /* Cover function for UNIQUE_SECTION.  */
 
 void
@@ -77,6 +475,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 6fcae3f94b6eeda32bf70bea8521fde4b6752bd6..ec42643f333e780cf51789cd4422a7fa0afe3b07 100644 (file)
@@ -2265,9 +2265,12 @@ staticp (arg)
     case FUNCTION_DECL:
       /* Nested functions aren't static, since taking their address
         involves a trampoline.  */
-       return decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg);
+       return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
+              && ! DECL_NON_ADDR_CONST_P (arg);
+
     case VAR_DECL:
-      return TREE_STATIC (arg) || DECL_EXTERNAL (arg);
+      return (TREE_STATIC (arg) || DECL_EXTERNAL (arg))
+             && ! DECL_NON_ADDR_CONST_P (arg);
 
     case CONSTRUCTOR:
       return TREE_STATIC (arg);
index b98f5552fa64f94008f337c6711114bcac66c319..c79270bf2a706180325977bf8790dbc10d1cc173 100644 (file)
@@ -1201,6 +1201,10 @@ struct tree_type
 #define DECL_LANG_FLAG_6(NODE) (DECL_CHECK (NODE)->decl.lang_flag_6)
 #define DECL_LANG_FLAG_7(NODE) (DECL_CHECK (NODE)->decl.lang_flag_7)
 
+/* Used to indicate that the pointer to this DECL cannot be treated as
+   an address constant.  */
+#define DECL_NON_ADDR_CONST_P(NODE) (DECL_CHECK (NODE)->decl.non_addr_const_p)
+
 struct tree_decl
 {
   char common[sizeof (struct tree_common)];
@@ -1242,6 +1246,8 @@ struct tree_decl
   unsigned lang_flag_6 : 1;
   unsigned lang_flag_7 : 1;
 
+  unsigned non_addr_const_p : 1;
+
   /* For a FUNCTION_DECL, if inline, this is the size of frame needed.
      If built-in, this is the code for which built-in function.
      For other kinds of decls, this is DECL_ALIGN.  */