OSDN Git Service

gcc/ChangeLog:
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / winnt.c
index 08e7864..a6bd1e4 100644 (file)
@@ -1,13 +1,13 @@
 /* Subroutines for insn-output.c for Windows NT.
    Contributed by Douglas Rupp (drupp@cs.washington.edu)
-   Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
-   Free Software Foundation, Inc.
+   Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+   2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -33,7 +32,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm_p.h"
 #include "toplev.h"
 #include "hashtab.h"
+#include "langhooks.h"
 #include "ggc.h"
+#include "target.h"
 
 /* i386/PE specific attribute support.
 
@@ -46,23 +47,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    multiple times.
 */
 
-static tree associated_type (tree);
-static const char * gen_stdcall_suffix (tree);
-static const char * gen_fastcall_suffix (tree);
-static int i386_pe_dllexport_p (tree);
-static int i386_pe_dllimport_p (tree);
-static void i386_pe_mark_dllexport (tree);
-static void i386_pe_mark_dllimport (tree);
-
-/* This is we how mark internal identifiers with dllimport or dllexport
-   attributes.  */
-#ifndef DLL_IMPORT_PREFIX
-#define DLL_IMPORT_PREFIX "#i."
-#endif
-#ifndef DLL_EXPORT_PREFIX
-#define DLL_EXPORT_PREFIX "#e."
-#endif
-
 /* Handle a "shared" attribute;
    arguments as in struct attribute_spec.handler.  */
 tree
@@ -72,417 +56,271 @@ ix86_handle_shared_attribute (tree *node, tree name,
 {
   if (TREE_CODE (*node) != VAR_DECL)
     {
-      warning ("`%s' attribute only applies to variables",
-              IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute only applies to variables",
+              name);
       *no_add_attrs = true;
     }
 
   return NULL_TREE;
 }
-\f
-/* Return the type that we should use to determine if DECL is
-   imported or exported.  */
 
-static tree
-associated_type (tree decl)
+/* Handle a "selectany" attribute;
+   arguments as in struct attribute_spec.handler.  */
+tree
+ix86_handle_selectany_attribute (tree *node, tree name,
+                                tree args ATTRIBUTE_UNUSED,
+                                int flags ATTRIBUTE_UNUSED,
+                                bool *no_add_attrs)
 {
-  tree t = NULL_TREE;
-
-  /* In the C++ frontend, DECL_CONTEXT for a method doesn't actually refer
-     to the containing class.  So we look at the 'this' arg.  */
-  if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
-    {
-      /* Artificial methods are not affected by the import/export status
-        of their class unless they are COMDAT.  Implicit copy ctor's and
-        dtor's are not affected by class status but virtual and
-        non-virtual thunks are.  */
-      if (!DECL_ARTIFICIAL (decl) || DECL_COMDAT (decl))
-       t = TYPE_MAIN_VARIANT
-         (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
+  /* The attribute applies only to objects that are initialized and have
+     external linkage.  However, we may not know about initialization
+     until the language frontend has processed the decl. We'll check for
+     initialization later in encode_section_info.  */
+  if (TREE_CODE (*node) != VAR_DECL || !TREE_PUBLIC (*node))
+    {  
+      error ("%qE attribute applies only to initialized variables"
+                    " with external linkage", name);
+      *no_add_attrs = true;
     }
-  else if (DECL_CONTEXT (decl)
-          && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't')
-    t = DECL_CONTEXT (decl);
 
-  return t;
+  return NULL_TREE;
 }
 
-/* Return nonzero if DECL is a dllexport'd object.  */
+\f
+/* Return the type that we should use to determine if DECL is
+   imported or exported.  */
 
-static int
-i386_pe_dllexport_p (tree decl)
+static tree
+associated_type (tree decl)
 {
-  tree exp;
-
-  if (TREE_CODE (decl) != VAR_DECL
-      && TREE_CODE (decl) != FUNCTION_DECL)
-    return 0;
-  exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
-  if (exp)
-    return 1;
-
-  /* Class members get the dllexport status of their class.  */
-  if (associated_type (decl))
-    {
-      exp = lookup_attribute ("dllexport",
-                             TYPE_ATTRIBUTES (associated_type (decl)));
-      if (exp)
-       return 1;
-    }
-
-  return 0;
+  return (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))
+          ?  DECL_CONTEXT (decl) : NULL_TREE);
 }
 
-/* Return nonzero if DECL is a dllimport'd object.  */
+/* Return true if DECL should be a dllexport'd object.  */
 
-static int
-i386_pe_dllimport_p (tree decl)
+static bool
+i386_pe_determine_dllexport_p (tree decl)
 {
-  tree imp;
-  int context_imp = 0;
-
-  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;
+  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
+    return false;
 
-  imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
+  /* Don't export local clones of dllexports.  */
+  if (!TREE_PUBLIC (decl))
+    return false;
 
-  /* Class members get the dllimport status of their class.  */
-  if (!imp && associated_type (decl))
-    {
-      imp = lookup_attribute ("dllimport",
-                             TYPE_ATTRIBUTES (associated_type (decl)));
-      if (imp)
-       context_imp = 1;
-    }
-
-  if (imp)
-    {
-      /* Don't mark defined functions as dllimport.  If the definition
-        itself was marked with dllimport, than ix86_handle_dll_attribute
-        reports an error. This handles the case when the definition
-        overrides an earlier declaration.  */
-      if (TREE_CODE (decl) ==  FUNCTION_DECL && DECL_INITIAL (decl)
-         && !DECL_INLINE (decl))
-       {
-          /* Don't warn about artificial methods.  */
-         if (!DECL_ARTIFICIAL (decl))
-           warning ("%Jfunction '%D' is defined after prior declaration "
-                    "as dllimport: attribute ignored", decl, decl);
-         return 0;
-       }
-
-      /* We ignore the dllimport attribute for inline member functions.
-        This differs from MSVC behavior which treats it like GNUC
-        'extern inline' extension.  */
-      else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))
-        {
-         if (extra_warnings)
-           warning ("%Jinline function '%D' is declared as dllimport: "
-                    "attribute ignored.", decl, decl);
-         return 0;
-       }
+  if (lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)))
+    return true;
 
-      /*  Don't allow definitions of static data members in dllimport class,
-         Just ignore attribute for vtable data.  */
-      else if (TREE_CODE (decl) == VAR_DECL
-              && TREE_STATIC (decl) && TREE_PUBLIC (decl)
-              && !DECL_EXTERNAL (decl) && context_imp)
-       {
-         if (!DECL_VIRTUAL_P (decl))
-            error ("%Jdefinition of static data member '%D' of "
-                  "dllimport'd class.", decl, decl);
-         return 0;
-       }
-
-      /* Since we can't treat a pointer to a dllimport'd symbol as a
-        constant address, we turn off the attribute on C++ virtual
-        methods to allow creation of vtables using thunks.  Don't mark
-        artificial methods either (in associated_type, only COMDAT
-        artificial method get import status from class context).  */
-      else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
-              && (DECL_VIRTUAL_P (decl) || DECL_ARTIFICIAL (decl)))
-       return 0;
-
-      return 1;
-    }
-
-  return 0;
+  return false;
 }
 
-/* Return nonzero if SYMBOL is marked as being dllexport'd.  */
+/* Return true if DECL should be a dllimport'd object.  */
 
-int
-i386_pe_dllexport_name_p (const char *symbol)
+static bool
+i386_pe_determine_dllimport_p (tree decl)
 {
-  return (strncmp (DLL_EXPORT_PREFIX, symbol,
-                  strlen (DLL_EXPORT_PREFIX)) == 0);
+  tree assoc;
+
+  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
+    return false;
+
+  if (DECL_DLLIMPORT_P (decl))
+    return true;
+
+  /* The DECL_DLLIMPORT_P flag was set for decls in the class definition
+     by  targetm.cxx.adjust_class_at_definition.  Check again to emit
+     error message if the class attribute has been overridden by an
+     out-of-class definition of static data.  */
+  assoc = associated_type (decl);
+  if (assoc && lookup_attribute ("dllimport", TYPE_ATTRIBUTES (assoc))
+      && TREE_CODE (decl) == VAR_DECL
+      && TREE_STATIC (decl) && TREE_PUBLIC (decl)
+      && !DECL_EXTERNAL (decl)
+      /* vtable's are linkonce constants, so defining a vtable is not
+        an error as long as we don't try to import it too.  */
+      && !DECL_VIRTUAL_P (decl))
+       error ("definition of static data member %q+D of "
+              "dllimport'd class", decl);
+
+  return false;
 }
 
-/* Return nonzero if SYMBOL is marked as being dllimport'd.  */
+/* Handle the -mno-fun-dllimport target switch.  */
 
-int
-i386_pe_dllimport_name_p (const char *symbol)
+bool
+i386_pe_valid_dllimport_attribute_p (const_tree decl)
 {
-  return (strncmp (DLL_IMPORT_PREFIX, symbol,
-                  strlen (DLL_IMPORT_PREFIX)) == 0);
+   if (TARGET_NOP_FUN_DLLIMPORT && TREE_CODE (decl) == FUNCTION_DECL)
+     return false;
+   return true;
 }
 
-/* Mark a DECL as being dllexport'd.
-   Note that we override the previous setting (eg: dllimport).  */
+/* Return string which is the function name, identified by ID, modified
+   with a suffix consisting of an atsign (@) followed by the number of
+   bytes of arguments.  If ID is NULL use the DECL_NAME as base. If
+   FASTCALL is true, also add the FASTCALL_PREFIX.
+   Return NULL if no change required.  */
 
-static void
-i386_pe_mark_dllexport (tree decl)
+static tree
+gen_stdcall_or_fastcall_suffix (tree decl, tree id, bool fastcall)
 {
-  const char *oldname;
-  char  *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))
-    {
-      warning ("%Jinconsistent dll linkage for '%D', dllexport assumed.",
-              decl, decl);
-     /* Remove DLL_IMPORT_PREFIX.  */
-      oldname += strlen (DLL_IMPORT_PREFIX);
-      DECL_NON_ADDR_CONST_P (decl) = 0;
-    }
-  else if (i386_pe_dllexport_name_p (oldname))
-    return;  /*  already done  */
-
-  newname = alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1);
-  sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, 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));
-}
+  HOST_WIDE_INT total = 0;
+  const char *old_str = IDENTIFIER_POINTER (id != NULL_TREE ? id : DECL_NAME (decl));
+  char *new_str, *p;
+  tree type = TREE_TYPE (decl);
+  tree arg;
+  function_args_iterator args_iter;
 
-/* Mark a DECL as being dllimport'd.  */
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);  
 
-static void
-i386_pe_mark_dllimport (tree decl)
-{
-  const char *oldname;
-  char  *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))
+  if (prototype_p (type))
     {
-      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 do a sanity check to prevent assembler errors.  */
-      if (!DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
+      /* This attribute is ignored for variadic functions.  */ 
+      if (stdarg_p (type))
+       return NULL_TREE;
+
+      /* Quit if we hit an incomplete type.  Error is reported
+        by convert_arguments in c-typeck.c or cp/typeck.c.  */
+      FOREACH_FUNCTION_ARGS(type, arg, args_iter)
        {
-         error ("%Jfailure in redeclaration of '%D': dllimport'd "
-                "symbol lacks external linkage.", decl, decl);
-         abort();
-       }
-      return;
-    }
+         HOST_WIDE_INT parm_size;
+         HOST_WIDE_INT parm_boundary_bytes = PARM_BOUNDARY / BITS_PER_UNIT;
 
-  newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1);
-  sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname);
+         if (! COMPLETE_TYPE_P (arg))
+           break;
 
-  /* 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);
+         parm_size = int_size_in_bytes (arg);
+         if (parm_size < 0)
+           break;
 
-  newrtl = gen_rtx_MEM (Pmode,
-                       gen_rtx_SYMBOL_REF (Pmode,
-                                           IDENTIFIER_POINTER (idp)));
-  XEXP (DECL_RTL (decl), 0) = newrtl;
+         /* Must round up to include padding.  This is done the same
+            way as in store_one_arg.  */
+         parm_size = ((parm_size + parm_boundary_bytes - 1)
+                      / parm_boundary_bytes * parm_boundary_bytes);
+         total += parm_size;
+       }
+      }
+  /* Assume max of 8 base 10 digits in the suffix.  */
+  p = new_str = XALLOCAVEC (char, 1 + strlen (old_str) + 1 + 8 + 1);
+  if (fastcall)
+    *p++ = FASTCALL_PREFIX;
+  sprintf (p, "%s@" HOST_WIDE_INT_PRINT_DEC, old_str, total);
 
-  /* Can't treat a pointer to this as a constant address */
-  DECL_NON_ADDR_CONST_P (decl) = 1;
+  return get_identifier (new_str);
 }
 
-/* Return string which is the former assembler name modified with a
-   prefix consisting of FASTCALL_PREFIX and a suffix consisting of an
-   atsign (@) followed by the number of bytes of arguments.  */
+/* Maybe decorate and get a new identifier for the DECL of a stdcall or
+   fastcall function. The original identifier is supplied in ID. */
 
-static const char *
-gen_fastcall_suffix (tree decl)
+static tree
+i386_pe_maybe_mangle_decl_assembler_name (tree decl, tree id)
 {
-  int total = 0;
-  const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  char *newsym;
-
-  if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
-    if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
-        == void_type_node)
-      {
-       tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
-
-       /* Quit if we hit an incomplete type.  Error is reported
-          by convert_arguments in c-typeck.c or cp/typeck.c.  */
-       while (TREE_VALUE (formal_type) != void_type_node
-              && COMPLETE_TYPE_P (TREE_VALUE (formal_type)))   
-         {
-           int parm_size
-             = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
-           /* Must round up to include padding.  This is done the same
-              way as in store_one_arg.  */
-           parm_size = ((parm_size + PARM_BOUNDARY - 1)
-                        / PARM_BOUNDARY * PARM_BOUNDARY);
-           total += parm_size;
-           formal_type = TREE_CHAIN (formal_type);
-         }
-      }
+  tree new_id = NULL_TREE;
 
-  /* Assume max of 8 base 10 digits in the suffix.  */
-  newsym = xmalloc (1 + strlen (asmname) + 1 + 8 + 1);
-  sprintf (newsym, "%c%s@%d", FASTCALL_PREFIX, asmname, total/BITS_PER_UNIT);
-  return IDENTIFIER_POINTER (get_identifier (newsym));
-}
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    { 
+      tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
+      if (lookup_attribute ("stdcall", type_attributes))
+       new_id = gen_stdcall_or_fastcall_suffix (decl, id, false);
+      else if (lookup_attribute ("fastcall", type_attributes))
+       new_id = gen_stdcall_or_fastcall_suffix (decl, id, true);
+    }
 
-/* Return string which is the former assembler name modified with a
-   suffix consisting of an atsign (@) followed by the number of bytes of
-   arguments */
+  return new_id;
+}
 
-static const char *
-gen_stdcall_suffix (tree decl)
+/* This is used as a target hook to modify the DECL_ASSEMBLER_NAME
+   in the language-independent default hook
+   langhooks,c:lhd_set_decl_assembler_name ()
+   and in cp/mangle,c:mangle_decl ().  */
+tree
+i386_pe_mangle_decl_assembler_name (tree decl, tree id)
 {
-  int total = 0;
-  /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
-     of DECL_ASSEMBLER_NAME.  */
-  const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  char *newsym;
-
-  if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
-    if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
-        == void_type_node)
-      {
-       tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
-
-       /* Quit if we hit an incomplete type.  Error is reported
-          by convert_arguments in c-typeck.c or cp/typeck.c.  */
-       while (TREE_VALUE (formal_type) != void_type_node
-              && COMPLETE_TYPE_P (TREE_VALUE (formal_type)))   
-         {
-           int parm_size
-             = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
-           /* Must round up to include padding.  This is done the same
-              way as in store_one_arg.  */
-           parm_size = ((parm_size + PARM_BOUNDARY - 1)
-                        / PARM_BOUNDARY * PARM_BOUNDARY);
-           total += parm_size;
-           formal_type = TREE_CHAIN (formal_type);
-         }
-      }
+  tree new_id = i386_pe_maybe_mangle_decl_assembler_name (decl, id);   
 
-  /* Assume max of 8 base 10 digits in the suffix.  */
-  newsym = xmalloc (strlen (asmname) + 1 + 8 + 1);
-  sprintf (newsym, "%s@%d", asmname, total/BITS_PER_UNIT);
-  return IDENTIFIER_POINTER (get_identifier (newsym));
+  return (new_id ? new_id : id);
 }
 
 void
 i386_pe_encode_section_info (tree decl, rtx rtl, int first)
 {
-  default_encode_section_info (decl, rtl, first);
+  rtx symbol;
+  int flags;
 
-  if (first && TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
-      rtx rtlname = XEXP (rtl, 0);
-      if (GET_CODE (rtlname) == MEM)
-       rtlname = XEXP (rtlname, 0);
-      if (lookup_attribute ("stdcall", type_attributes))
-       XSTR (rtlname, 0) = gen_stdcall_suffix (decl);
-      else if (lookup_attribute ("fastcall", type_attributes))
-       XSTR (rtlname, 0) = gen_fastcall_suffix (decl);
-    }
-
-  /* Mark the decl so we can tell from the rtl whether the object is
-     dllexport'd or dllimport'd.  This also handles dllexport/dllimport
-     override semantics.  */
-
-  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 (DLL_IMPORT_PREFIX) prefixed. 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)))
-    {
-      const char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
+  /* Do this last, due to our frobbing of DECL_DLLIMPORT_P above.  */
+  default_encode_section_info (decl, rtl, first);
 
-      /* Remove DLL_IMPORT_PREFIX.  */
-      tree idp = get_identifier (oldname + strlen (DLL_IMPORT_PREFIX));
-      rtx newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
+  /* Careful not to prod global register variables.  */
+  if (!MEM_P (rtl))
+    return;
 
-      if (DECL_INITIAL (decl) || !DECL_EXTERNAL (decl))
-       warning ("%J'%D' defined locally after being "
-                "referenced with dllimport linkage", decl, decl);
-      else
-       warning ("%J'%D' redeclared without dllimport attribute "
-                "after being referenced with dllimport linkage", decl, decl);
+  symbol = XEXP (rtl, 0);
+  gcc_assert (GET_CODE (symbol) == SYMBOL_REF);
 
-      XEXP (DECL_RTL (decl), 0) = newrtl;
+  switch (TREE_CODE (decl))
+    {
+    case FUNCTION_DECL:
+      /* FIXME:  Imported stdcall names are not modified by the Ada frontend.
+        Check and decorate the RTL name now.  */
+      if  (strcmp (lang_hooks.name, "GNU Ada") == 0)
+       {
+         tree new_id;
+         tree old_id = DECL_ASSEMBLER_NAME (decl);
+         const char* asm_str = IDENTIFIER_POINTER (old_id);
+         /* Do not change the identifier if a verbatim asmspec
+            or if stdcall suffix already added. */
+         if (!(*asm_str == '*' || strchr (asm_str, '@'))
+             && (new_id = i386_pe_maybe_mangle_decl_assembler_name (decl,
+                                                                    old_id)))
+           XSTR (symbol, 0) = IDENTIFIER_POINTER (new_id);
+       }
+      break;
 
-      DECL_NON_ADDR_CONST_P (decl) = 0;
+    case VAR_DECL:
+      if (lookup_attribute ("selectany", DECL_ATTRIBUTES (decl)))
+       {
+         if (DECL_INITIAL (decl)
+             /* If an object is initialized with a ctor, the static
+                initialization and destruction code for it is present in
+                each unit defining the object.  The code that calls the
+                ctor is protected by a link-once guard variable, so that
+                the object still has link-once semantics,  */
+             || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
+           make_decl_one_only (decl, DECL_ASSEMBLER_NAME (decl));
+         else
+           error ("%q+D:'selectany' attribute applies only to "
+                  "initialized objects", decl);
+       }
+      break;
 
-      /* We previously set TREE_PUBLIC and DECL_EXTERNAL.
-        We leave these alone for now.  */
+    default:
+      return;
     }
-}
 
-/* Strip only the leading encoding, leaving the stdcall suffix and fastcall
-   prefix if it exists.  */
+  /* Mark the decl so we can tell from the rtl whether the object is
+     dllexport'd or dllimport'd.  tree.c: merge_dllimport_decl_attributes
+     handles dllexport/dllimport override semantics.  */
+  flags = (SYMBOL_REF_FLAGS (symbol) &
+          ~(SYMBOL_FLAG_DLLIMPORT | SYMBOL_FLAG_DLLEXPORT));
+  if (i386_pe_determine_dllexport_p (decl))
+    flags |= SYMBOL_FLAG_DLLEXPORT;
+  else if (i386_pe_determine_dllimport_p (decl))
+    flags |= SYMBOL_FLAG_DLLIMPORT;
+  SYMBOL_REF_FLAGS (symbol) = flags;
+}
 
-const char *
-i386_pe_strip_name_encoding (const char *str)
+bool
+i386_pe_binds_local_p (const_tree exp)
 {
-  if (strncmp (str, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX))
-      == 0)
-    str += strlen (DLL_IMPORT_PREFIX);
-  else if (strncmp (str, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX))
-          == 0)
-    str += strlen (DLL_EXPORT_PREFIX);
-  if (*str == '*')
-    str += 1;
-  return str;
+  /* PE does not do dynamic binding.  Indeed, the only kind of
+     non-local reference comes from a dllimport'd symbol.  */
+  if ((TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == FUNCTION_DECL)
+      && DECL_DLLIMPORT_P (exp))
+    return false;
+
+  return true;
 }
 
 /* Also strip the fastcall prefix and stdcall suffix.  */
@@ -491,7 +329,7 @@ const char *
 i386_pe_strip_name_encoding_full (const char *str)
 {
   const char *p;
-  const char *name = i386_pe_strip_name_encoding (str);
+  const char *name = default_strip_name_encoding (str);
 
   /* Strip leading '@' on fastcall symbols.  */
   if (*name == '@')
@@ -505,46 +343,6 @@ i386_pe_strip_name_encoding_full (const char *str)
   return name;
 }
 
-/* Output a reference to a label. Fastcall symbols are prefixed with @,
-   whereas symbols for functions using other calling conventions don't
-   have a prefix (unless they are marked dllimport or dllexport).  */
-
-void i386_pe_output_labelref (FILE *stream, const char *name)
-{
-  if (strncmp (name, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX))
-      == 0)
-    /* A dll import */
-    {
-      if (name[strlen (DLL_IMPORT_PREFIX)] == FASTCALL_PREFIX)
-      /* A dllimport fastcall symbol.  */
-        {
-          fprintf (stream, "__imp_%s",
-                   i386_pe_strip_name_encoding (name));
-        }
-      else
-      /* A dllimport non-fastcall symbol.  */
-        {
-          fprintf (stream, "__imp__%s",
-                   i386_pe_strip_name_encoding (name));
-        }
-    }
-  else if ((name[0] == FASTCALL_PREFIX)
-           || (strncmp (name, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX))
-              == 0
-              && name[strlen (DLL_EXPORT_PREFIX)] == FASTCALL_PREFIX))
-    /* A fastcall symbol.  */
-    {
-      fprintf (stream, "%s",
-               i386_pe_strip_name_encoding (name));
-    }
-  else
-    /* Everything else.  */
-    {
-      fprintf (stream, "%s%s", USER_LABEL_PREFIX,
-               i386_pe_strip_name_encoding (name));
-    }
-}
-
 void
 i386_pe_unique_section (tree decl, int reloc)
 {
@@ -568,7 +366,7 @@ i386_pe_unique_section (tree decl, int reloc)
   else
     prefix = ".data$";
   len = strlen (name) + strlen (prefix);
-  string = alloca (len + 1);
+  string = XALLOCAVEC (char, len + 1);
   sprintf (string, "%s%s", prefix, name);
 
   DECL_SECTION_NAME (decl) = build_string (len, string);
@@ -608,6 +406,15 @@ i386_pe_section_type_flags (tree decl, const char *name, int reloc)
     flags = SECTION_CODE;
   else if (decl && decl_readonly_section (decl, reloc))
     flags = 0;
+  else if (current_function_decl
+          && cfun
+          && crtl->subsections.unlikely_text_section_name
+          && strcmp (name, crtl->subsections.unlikely_text_section_name) == 0)
+    flags = SECTION_CODE;
+  else if (!decl
+          && (!current_function_decl || !cfun)
+          && strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0)
+    flags = SECTION_CODE;
   else
     {
       flags = SECTION_WRITE;
@@ -630,14 +437,15 @@ i386_pe_section_type_flags (tree decl, const char *name, int reloc)
   else
     {
       if (decl && **slot != flags)
-       error ("%J'%D' causes a section type conflict", decl, decl);
+       error ("%q+D causes a section type conflict", decl);
     }
 
   return flags;
 }
 
 void
-i386_pe_asm_named_section (const char *name, unsigned int flags)
+i386_pe_asm_named_section (const char *name, unsigned int flags, 
+                          tree decl)
 {
   char flagchars[8], *f = flagchars;
 
@@ -664,12 +472,48 @@ i386_pe_asm_named_section (const char *name, unsigned int flags)
   if (flags & SECTION_LINKONCE)
     {
       /* Functions may have been compiled at various levels of
-         optimization so we can't use `same_size' here.
-         Instead, have the linker pick one.  */
+        optimization so we can't use `same_size' here.
+        Instead, have the linker pick one, without warning.
+        If 'selectany' attribute has been specified,  MS compiler
+        sets 'discard' characteristic, rather than telling linker
+        to warn of size or content mismatch, so do the same.  */ 
+      bool discard = (flags & SECTION_CODE)
+                     || lookup_attribute ("selectany",
+                                          DECL_ATTRIBUTES (decl));      
       fprintf (asm_out_file, "\t.linkonce %s\n",
-              (flags & SECTION_CODE ? "discard" : "same_size"));
+              (discard  ? "discard" : "same_size"));
     }
 }
+
+void
+i386_pe_asm_output_aligned_decl_common (FILE *stream, tree decl,
+                                       const char *name, HOST_WIDE_INT size,
+                                       HOST_WIDE_INT align ATTRIBUTE_UNUSED)
+{
+  HOST_WIDE_INT rounded;
+
+  /* Compute as in assemble_noswitch_variable, since we don't have
+     support for aligned common on older binutils.  We must also
+     avoid emitting a common symbol of size zero, as this is the
+     overloaded representation that indicates an undefined external
+     symbol in the PE object file format.  */
+  rounded = size ? size : 1;
+  rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
+  rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
+            * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+  
+  i386_pe_maybe_record_exported_symbol (decl, name, 1);
+
+  fprintf (stream, "\t.comm\t");
+  assemble_name (stream, name);
+  if (use_pe_aligned_common)
+    fprintf (stream, ", " HOST_WIDE_INT_PRINT_DEC ", %d\n",
+          size ? size : (HOST_WIDE_INT) 1,
+          exact_log2 (align) - exact_log2 (CHAR_BIT));
+  else
+    fprintf (stream, ", " HOST_WIDE_INT_PRINT_DEC "\t" ASM_COMMENT_START
+          " " HOST_WIDE_INT_PRINT_DEC "\n", rounded, size);
+}
 \f
 /* The Microsoft linker requires that every function be marked as
    DT_FCN.  When using gas on cygwin, we must emit appropriate .type
@@ -680,24 +524,25 @@ i386_pe_asm_named_section (const char *name, unsigned int flags)
 /* Mark a function appropriately.  This should only be called for
    functions for which we are not emitting COFF debugging information.
    FILE is the assembler output file, NAME is the name of the
-   function, and PUBLIC is nonzero if the function is globally
+   function, and PUB is nonzero if the function is globally
    visible.  */
 
 void
-i386_pe_declare_function_type (FILE *file, const char *name, int public)
+i386_pe_declare_function_type (FILE *file, const char *name, int pub)
 {
   fprintf (file, "\t.def\t");
   assemble_name (file, name);
   fprintf (file, ";\t.scl\t%d;\t.type\t%d;\t.endef\n",
-          public ? (int) C_EXT : (int) C_STAT,
+          pub ? (int) C_EXT : (int) C_STAT,
           (int) DT_FCN << N_BTSHFT);
 }
 
 /* Keep a list of external functions.  */
 
-struct extern_list GTY(())
+struct GTY(()) extern_list
 {
   struct extern_list *next;
+  tree decl;
   const char *name;
 };
 
@@ -710,19 +555,20 @@ static GTY(()) struct extern_list *extern_head;
    for it then.  */
 
 void
-i386_pe_record_external_function (const char *name)
+i386_pe_record_external_function (tree decl, const char *name)
 {
   struct extern_list *p;
 
   p = (struct extern_list *) ggc_alloc (sizeof *p);
   p->next = extern_head;
+  p->decl = decl;
   p->name = name;
   extern_head = p;
 }
 
 /* Keep a list of exported symbols.  */
 
-struct export_list GTY(())
+struct GTY(()) export_list
 {
   struct export_list *next;
   const char *name;
@@ -738,10 +584,18 @@ static GTY(()) struct export_list *export_head;
    linkonce.  */
 
 void
-i386_pe_record_exported_symbol (const char *name, int is_data)
+i386_pe_maybe_record_exported_symbol (tree decl, const char *name, int is_data)
 {
+  rtx symbol;
   struct export_list *p;
 
+  symbol = XEXP (DECL_RTL (decl), 0);
+  gcc_assert (GET_CODE (symbol) == SYMBOL_REF);
+  if (!SYMBOL_REF_DLLEXPORT_P (symbol))
+    return;
+
+  gcc_assert (TREE_PUBLIC (decl));
+
   p = (struct export_list *) ggc_alloc (sizeof *p);
   p->next = export_head;
   p->name = name;
@@ -749,6 +603,64 @@ i386_pe_record_exported_symbol (const char *name, int is_data)
   export_head = p;
 }
 
+#ifdef CXX_WRAP_SPEC_LIST
+
+/*  Hash table equality helper function.  */
+
+static int
+wrapper_strcmp (const void *x, const void *y)
+{
+  return !strcmp ((const char *) x, (const char *) y);
+}
+
+/* Search for a function named TARGET in the list of library wrappers
+   we are using, returning a pointer to it if found or NULL if not.
+   This function might be called on quite a few symbols, and we only
+   have the list of names of wrapped functions available to us as a
+   spec string, so first time round we lazily initialise a hash table
+   to make things quicker.  */
+
+static const char *
+i386_find_on_wrapper_list (const char *target)
+{
+  static char first_time = 1;
+  static htab_t wrappers;
+
+  if (first_time)
+    {
+      /* Beware that this is not a complicated parser, it assumes
+         that any sequence of non-whitespace beginning with an
+        underscore is one of the wrapped symbols.  For now that's
+        adequate to distinguish symbols from spec substitutions
+        and command-line options.  */
+      static char wrapper_list_buffer[] = CXX_WRAP_SPEC_LIST;
+      char *bufptr;
+      /* Breaks up the char array into separated strings
+         strings and enter them into the hash table.  */
+      wrappers = htab_create_alloc (8, htab_hash_string, wrapper_strcmp,
+       0, xcalloc, free);
+      for (bufptr = wrapper_list_buffer; *bufptr; ++bufptr)
+       {
+         char *found = NULL;
+         if (ISSPACE (*bufptr))
+           continue;
+         if (*bufptr == '_')
+           found = bufptr;
+         while (*bufptr && !ISSPACE (*bufptr))
+           ++bufptr;
+         if (*bufptr)
+           *bufptr = 0;
+         if (found)
+           *htab_find_slot (wrappers, found, INSERT) = found;
+       }
+      first_time = 0;
+    }
+
+  return (const char *) htab_find (wrappers, target);
+}
+
+#endif /* CXX_WRAP_SPEC_LIST */
+
 /* This is called at the end of assembly.  For each external function
    which has not been defined, we output a declaration now.  We also
    output the .drectve section.  */
@@ -764,11 +676,21 @@ i386_pe_file_end (void)
     {
       tree decl;
 
-      decl = get_identifier (p->name);
+      decl = p->decl;
 
       /* Positively ensure only one declaration for any given symbol.  */
-      if (! TREE_ASM_WRITTEN (decl) && TREE_SYMBOL_REFERENCED (decl))
+      if (! TREE_ASM_WRITTEN (decl)
+         && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
        {
+#ifdef CXX_WRAP_SPEC_LIST
+         /* To ensure the DLL that provides the corresponding real
+            functions is still loaded at runtime, we must reference
+            the real function so that an (unused) import is created.  */
+         const char *realsym = i386_find_on_wrapper_list (p->name);
+         if (realsym)
+           i386_pe_declare_function_type (asm_out_file,
+               concat ("__real_", realsym, NULL), TREE_PUBLIC (decl));
+#endif /* CXX_WRAP_SPEC_LIST */
          TREE_ASM_WRITTEN (decl) = 1;
          i386_pe_declare_function_type (asm_out_file, p->name,
                                         TREE_PUBLIC (decl));
@@ -782,8 +704,8 @@ i386_pe_file_end (void)
       for (q = export_head; q != NULL; q = q->next)
        {
          fprintf (asm_out_file, "\t.ascii \" -export:%s%s\"\n",
-                  i386_pe_strip_name_encoding (q->name),
-                  (q->is_data) ? ",data" : "");
+                  default_strip_name_encoding (q->name),
+                  (q->is_data ? ",data" : ""));
        }
     }
 }