1135446Strhodes/* Subroutines for insn-output.c for Windows NT.
2254402Serwin   Contributed by Douglas Rupp (drupp@cs.washington.edu)
3135446Strhodes   Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
4135446Strhodes   Free Software Foundation, Inc.
5174187Sdougb
6135446StrhodesThis file is part of GCC.
7135446Strhodes
8135446StrhodesGCC is free software; you can redistribute it and/or modify it under
9135446Strhodesthe terms of the GNU General Public License as published by the Free
10135446StrhodesSoftware Foundation; either version 2, or (at your option) any later
11135446Strhodesversion.
12135446Strhodes
13135446StrhodesGCC is distributed in the hope that it will be useful, but WITHOUT ANY
14135446StrhodesWARRANTY; without even the implied warranty of MERCHANTABILITY or
15135446StrhodesFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16135446Strhodesfor more details.
17135446Strhodes
18254897SerwinYou should have received a copy of the GNU General Public License
19135446Strhodesalong with GCC; see the file COPYING.  If not, write to the Free
20170222SdougbSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21170222Sdougb02110-1301, USA.  */
22135446Strhodes
23135446Strhodes#include "config.h"
24135446Strhodes#include "system.h"
25135446Strhodes#include "coretypes.h"
26135446Strhodes#include "tm.h"
27135446Strhodes#include "rtl.h"
28135446Strhodes#include "regs.h"
29135446Strhodes#include "hard-reg-set.h"
30135446Strhodes#include "output.h"
31135446Strhodes#include "tree.h"
32135446Strhodes#include "flags.h"
33135446Strhodes#include "tm_p.h"
34135446Strhodes#include "toplev.h"
35135446Strhodes#include "hashtab.h"
36135446Strhodes#include "ggc.h"
37135446Strhodes
38135446Strhodes/* i386/PE specific attribute support.
39135446Strhodes
40135446Strhodes   i386/PE has two new attributes:
41135446Strhodes   dllexport - for exporting a function/variable that will live in a dll
42135446Strhodes   dllimport - for importing a function/variable from a dll
43135446Strhodes
44135446Strhodes   Microsoft allows multiple declspecs in one __declspec, separating
45170222Sdougb   them with spaces.  We do NOT support this.  Instead, use __declspec
46135446Strhodes   multiple times.
47135446Strhodes*/
48135446Strhodes
49135446Strhodesstatic tree associated_type (tree);
50135446Strhodesstatic tree gen_stdcall_or_fastcall_suffix (tree, bool);
51186462Sdougbstatic bool i386_pe_dllexport_p (tree);
52135446Strhodesstatic bool i386_pe_dllimport_p (tree);
53135446Strhodesstatic void i386_pe_mark_dllexport (tree);
54135446Strhodesstatic void i386_pe_mark_dllimport (tree);
55135446Strhodes
56143731Sdougb/* This is we how mark internal identifiers with dllimport or dllexport
57135446Strhodes   attributes.  */
58135446Strhodes#ifndef DLL_IMPORT_PREFIX
59135446Strhodes#define DLL_IMPORT_PREFIX "#i."
60135446Strhodes#endif
61135446Strhodes#ifndef DLL_EXPORT_PREFIX
62135446Strhodes#define DLL_EXPORT_PREFIX "#e."
63143731Sdougb#endif
64135446Strhodes
65135446Strhodes/* Handle a "shared" attribute;
66135446Strhodes   arguments as in struct attribute_spec.handler.  */
67135446Strhodestree
68135446Strhodesix86_handle_shared_attribute (tree *node, tree name,
69224092Sdougb			      tree args ATTRIBUTE_UNUSED,
70254897Serwin			      int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
71254897Serwin{
72135446Strhodes  if (TREE_CODE (*node) != VAR_DECL)
73170222Sdougb    {
74186462Sdougb      warning (OPT_Wattributes, "%qs attribute only applies to variables",
75135446Strhodes	       IDENTIFIER_POINTER (name));
76135446Strhodes      *no_add_attrs = true;
77135446Strhodes    }
78135446Strhodes
79135446Strhodes  return NULL_TREE;
80135446Strhodes}
81135446Strhodes
82135446Strhodes/* Handle a "selectany" attribute;
83135446Strhodes   arguments as in struct attribute_spec.handler.  */
84135446Strhodestree
85135446Strhodesix86_handle_selectany_attribute (tree *node, tree name,
86135446Strhodes			         tree args ATTRIBUTE_UNUSED,
87135446Strhodes			         int flags ATTRIBUTE_UNUSED,
88135446Strhodes				 bool *no_add_attrs)
89135446Strhodes{
90135446Strhodes  /* The attribute applies only to objects that are initialized and have
91135446Strhodes     external linkage,  */
92135446Strhodes  if (TREE_CODE (*node) == VAR_DECL && TREE_PUBLIC (*node)
93170222Sdougb      && (DECL_INITIAL (*node)
94186462Sdougb          /* If an object is initialized with a ctor, the static
95135446Strhodes	     initialization and destruction code for it is present in
96135446Strhodes	     each unit defining the object.  The code that calls the
97135446Strhodes	     ctor is protected by a link-once guard variable, so that
98135446Strhodes	     the object still has link-once semantics,  */
99135446Strhodes    	  || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (*node))))
100135446Strhodes    make_decl_one_only (*node);
101135446Strhodes  else
102135446Strhodes    {
103135446Strhodes      error ("%qs attribute applies only to initialized variables"
104135446Strhodes       	     " with external linkage",  IDENTIFIER_POINTER (name));
105135446Strhodes      *no_add_attrs = true;
106135446Strhodes    }
107135446Strhodes
108135446Strhodes  return NULL_TREE;
109135446Strhodes}
110135446Strhodes
111135446Strhodes
112135446Strhodes/* Return the type that we should use to determine if DECL is
113135446Strhodes   imported or exported.  */
114193149Sdougb
115193149Sdougbstatic tree
116193149Sdougbassociated_type (tree decl)
117193149Sdougb{
118193149Sdougb  return  (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
119193149Sdougb            ?  DECL_CONTEXT (decl) : NULL_TREE;
120193149Sdougb}
121193149Sdougb
122193149Sdougb
123193149Sdougb/* Return true if DECL is a dllexport'd object.  */
124193149Sdougb
125193149Sdougbstatic bool
126193149Sdougbi386_pe_dllexport_p (tree decl)
127193149Sdougb{
128193149Sdougb  if (TREE_CODE (decl) != VAR_DECL
129193149Sdougb       && TREE_CODE (decl) != FUNCTION_DECL)
130193149Sdougb    return false;
131193149Sdougb
132170222Sdougb  if (lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)))
133135446Strhodes    return true;
134135446Strhodes
135135446Strhodes  /* Also mark class members of exported classes with dllexport.  */
136135446Strhodes  if (associated_type (decl)
137135446Strhodes      && lookup_attribute ("dllexport",
138135446Strhodes			    TYPE_ATTRIBUTES (associated_type (decl))))
139135446Strhodes    return i386_pe_type_dllexport_p (decl);
140135446Strhodes
141224092Sdougb  return false;
142224092Sdougb}
143224092Sdougb
144135446Strhodesstatic bool
145135446Strhodesi386_pe_dllimport_p (tree decl)
146135446Strhodes{
147135446Strhodes  if (TREE_CODE (decl) != VAR_DECL
148135446Strhodes       && TREE_CODE (decl) != FUNCTION_DECL)
149135446Strhodes    return false;
150135446Strhodes
151135446Strhodes  /* Lookup the attribute rather than rely on the DECL_DLLIMPORT_P flag.
152170222Sdougb     We may need to override an earlier decision.  */
153135446Strhodes  if (lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl)))
154135446Strhodes    return true;
155135446Strhodes
156135446Strhodes  /* The DECL_DLLIMPORT_P flag was set for decls in the class definition
157135446Strhodes     by  targetm.cxx.adjust_class_at_definition.  Check again to emit
158170222Sdougb     warnings if the class attribute has been overriden by an
159135446Strhodes     out-of-class definition.  */
160135446Strhodes  if (associated_type (decl)
161135446Strhodes      && lookup_attribute ("dllimport",
162135446Strhodes			    TYPE_ATTRIBUTES (associated_type (decl))))
163135446Strhodes    return i386_pe_type_dllimport_p (decl);
164135446Strhodes
165135446Strhodes  return false;
166135446Strhodes}
167135446Strhodes
168186462Sdougb/* Handle the -mno-fun-dllimport target switch.  */
169186462Sdougbbool
170135446Strhodesi386_pe_valid_dllimport_attribute_p (tree decl)
171135446Strhodes{
172135446Strhodes   if (TARGET_NOP_FUN_DLLIMPORT && TREE_CODE (decl) == FUNCTION_DECL)
173170222Sdougb     return false;
174135446Strhodes   return true;
175135446Strhodes}
176135446Strhodes
177170222Sdougb/* Return nonzero if SYMBOL is marked as being dllexport'd.  */
178135446Strhodes
179135446Strhodesint
180186462Sdougbi386_pe_dllexport_name_p (const char *symbol)
181135446Strhodes{
182135446Strhodes  return (strncmp (DLL_EXPORT_PREFIX, symbol,
183135446Strhodes		   strlen (DLL_EXPORT_PREFIX)) == 0);
184135446Strhodes}
185135446Strhodes
186135446Strhodes/* Return nonzero if SYMBOL is marked as being dllimport'd.  */
187135446Strhodes
188135446Strhodesint
189135446Strhodesi386_pe_dllimport_name_p (const char *symbol)
190254402Serwin{
191135446Strhodes  return (strncmp (DLL_IMPORT_PREFIX, symbol,
192170222Sdougb		   strlen (DLL_IMPORT_PREFIX)) == 0);
193135446Strhodes}
194135446Strhodes
195135446Strhodes/* Mark a DECL as being dllexport'd.
196135446Strhodes   Note that we override the previous setting (e.g.: dllimport).  */
197135446Strhodes
198135446Strhodesstatic void
199135446Strhodesi386_pe_mark_dllexport (tree decl)
200135446Strhodes{
201135446Strhodes  const char *oldname;
202135446Strhodes  char  *newname;
203135446Strhodes  rtx rtlname;
204135446Strhodes  rtx symref;
205254897Serwin  tree idp;
206254897Serwin
207135446Strhodes  rtlname = XEXP (DECL_RTL (decl), 0);
208135446Strhodes  if (GET_CODE (rtlname) == MEM)
209135446Strhodes    rtlname = XEXP (rtlname, 0);
210135446Strhodes  gcc_assert (GET_CODE (rtlname) == SYMBOL_REF);
211135446Strhodes  oldname = XSTR (rtlname, 0);
212135446Strhodes  if (i386_pe_dllimport_name_p (oldname))
213135446Strhodes    {
214135446Strhodes      warning (0, "inconsistent dll linkage for %q+D, dllexport assumed",
215135446Strhodes	       decl);
216135446Strhodes     /* Remove DLL_IMPORT_PREFIX.  */
217135446Strhodes      oldname += strlen (DLL_IMPORT_PREFIX);
218135446Strhodes    }
219254897Serwin  else if (i386_pe_dllexport_name_p (oldname))
220135446Strhodes    return;  /*  already done  */
221193149Sdougb
222135446Strhodes  newname = alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1);
223135446Strhodes  sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, oldname);
224135446Strhodes
225135446Strhodes  /* We pass newname through get_identifier to ensure it has a unique
226135446Strhodes     address.  RTL processing can sometimes peek inside the symbol ref
227135446Strhodes     and compare the string's addresses to see if two symbols are
228135446Strhodes     identical.  */
229254897Serwin  idp = get_identifier (newname);
230135446Strhodes
231224092Sdougb  symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
232262706Serwin  SYMBOL_REF_DECL (symref) = decl;
233135446Strhodes  XEXP (DECL_RTL (decl), 0) = symref;
234135446Strhodes}
235135446Strhodes
236135446Strhodes/* Mark a DECL as being dllimport'd.  */
237135446Strhodes
238135446Strhodesstatic void
239135446Strhodesi386_pe_mark_dllimport (tree decl)
240170222Sdougb{
241135446Strhodes  const char *oldname;
242135446Strhodes  char  *newname;
243135446Strhodes  tree idp;
244135446Strhodes  rtx rtlname, newrtl;
245135446Strhodes  rtx symref;
246135446Strhodes
247135446Strhodes  rtlname = XEXP (DECL_RTL (decl), 0);
248254402Serwin  if (GET_CODE (rtlname) == MEM)
249254402Serwin    rtlname = XEXP (rtlname, 0);
250135446Strhodes  gcc_assert (GET_CODE (rtlname) == SYMBOL_REF);
251135446Strhodes  oldname = XSTR (rtlname, 0);
252135446Strhodes  if (i386_pe_dllexport_name_p (oldname))
253135446Strhodes    {
254135446Strhodes      error ("%qs declared as both exported to and imported from a DLL",
255135446Strhodes             IDENTIFIER_POINTER (DECL_NAME (decl)));
256135446Strhodes      return;
257135446Strhodes    }
258135446Strhodes  else if (i386_pe_dllimport_name_p (oldname))
259135446Strhodes    {
260135446Strhodes      /* Already done, but do a sanity check to prevent assembler
261254402Serwin	 errors.  */
262254402Serwin      gcc_assert (DECL_EXTERNAL (decl) && TREE_PUBLIC (decl)
263254402Serwin		  && DECL_DLLIMPORT_P (decl));
264254402Serwin      return;
265135446Strhodes    }
266170222Sdougb
267170222Sdougb  newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1);
268170222Sdougb  sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname);
269170222Sdougb
270135446Strhodes  /* We pass newname through get_identifier to ensure it has a unique
271170222Sdougb     address.  RTL processing can sometimes peek inside the symbol ref
272135446Strhodes     and compare the string's addresses to see if two symbols are
273135446Strhodes     identical.  */
274135446Strhodes  idp = get_identifier (newname);
275135446Strhodes
276135446Strhodes  symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
277135446Strhodes  SYMBOL_REF_DECL (symref) = decl;
278135446Strhodes  newrtl = gen_rtx_MEM (Pmode,symref);
279135446Strhodes  XEXP (DECL_RTL (decl), 0) = newrtl;
280135446Strhodes
281135446Strhodes  DECL_DLLIMPORT_P (decl) = 1;
282135446Strhodes}
283135446Strhodes
284170222Sdougb/* Return string which is the former assembler name modified with a
285170222Sdougb   suffix consisting of an atsign (@) followed by the number of bytes of
286170222Sdougb   arguments.  If FASTCALL is true, also add the FASTCALL_PREFIX.  */
287170222Sdougb
288254402Serwinstatic tree
289135446Strhodesgen_stdcall_or_fastcall_suffix (tree decl, bool fastcall)
290135446Strhodes{
291135446Strhodes  int total = 0;
292135446Strhodes  /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
293135446Strhodes     of DECL_ASSEMBLER_NAME.  */
294135446Strhodes   const char *asmname =  IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
295135446Strhodes  char *newsym;
296135446Strhodes  char *p;
297135446Strhodes  tree formal_type;
298135446Strhodes
299135446Strhodes  /* Do not change the identifier if a verbatim asmspec or already done. */
300135446Strhodes  if (*asmname == '*' || strchr (asmname, '@'))
301135446Strhodes    return DECL_ASSEMBLER_NAME (decl);
302135446Strhodes
303135446Strhodes  formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
304170222Sdougb  if (formal_type != NULL_TREE)
305135446Strhodes    {
306135446Strhodes      /* These attributes are ignored for variadic functions in
307135446Strhodes	 i386.c:ix86_return_pops_args. For compatibility with MS
308135446Strhodes         compiler do not add @0 suffix here.  */
309135446Strhodes      if (TREE_VALUE (tree_last (formal_type)) != void_type_node)
310135446Strhodes        return DECL_ASSEMBLER_NAME (decl);
311135446Strhodes
312135446Strhodes      /* Quit if we hit an incomplete type.  Error is reported
313135446Strhodes         by convert_arguments in c-typeck.c or cp/typeck.c.  */
314135446Strhodes      while (TREE_VALUE (formal_type) != void_type_node
315135446Strhodes	     && COMPLETE_TYPE_P (TREE_VALUE (formal_type)))
316135446Strhodes	{
317135446Strhodes	  int parm_size
318135446Strhodes	    = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
319135446Strhodes	    /* Must round up to include padding.  This is done the same
320135446Strhodes	       way as in store_one_arg.  */
321218384Sdougb	  parm_size = ((parm_size + PARM_BOUNDARY - 1)
322218384Sdougb		       / PARM_BOUNDARY * PARM_BOUNDARY);
323135446Strhodes	  total += parm_size;
324135446Strhodes	  formal_type = TREE_CHAIN (formal_type);\
325135446Strhodes	}
326135446Strhodes     }
327135446Strhodes
328135446Strhodes  /* Assume max of 8 base 10 digits in the suffix.  */
329135446Strhodes  newsym = alloca (1 + strlen (asmname) + 1 + 8 + 1);
330135446Strhodes  p = newsym;
331135446Strhodes  if (fastcall)
332135446Strhodes    *p++ = FASTCALL_PREFIX;
333135446Strhodes  sprintf (p, "%s@%d", asmname, total/BITS_PER_UNIT);
334135446Strhodes  return get_identifier (newsym);
335135446Strhodes}
336170222Sdougb
337135446Strhodesvoid
338135446Strhodesi386_pe_encode_section_info (tree decl, rtx rtl, int first)
339135446Strhodes{
340135446Strhodes  default_encode_section_info (decl, rtl, first);
341135446Strhodes
342135446Strhodes  if (first && TREE_CODE (decl) == FUNCTION_DECL)
343135446Strhodes    {
344135446Strhodes      tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
345135446Strhodes      tree newid = NULL_TREE;
346135446Strhodes
347135446Strhodes      if (lookup_attribute ("stdcall", type_attributes))
348135446Strhodes	newid = gen_stdcall_or_fastcall_suffix (decl, false);
349135446Strhodes      else if (lookup_attribute ("fastcall", type_attributes))
350135446Strhodes	newid = gen_stdcall_or_fastcall_suffix (decl, true);
351135446Strhodes      if (newid != NULL_TREE)
352135446Strhodes	{
353135446Strhodes	  rtx rtlname = XEXP (rtl, 0);
354135446Strhodes	  if (GET_CODE (rtlname) == MEM)
355135446Strhodes	    rtlname = XEXP (rtlname, 0);
356135446Strhodes	  XSTR (rtlname, 0) = IDENTIFIER_POINTER (newid);
357135446Strhodes	  /* These attributes must be present on first declaration,
358135446Strhodes	     change_decl_assembler_name will warn if they are added
359135446Strhodes	     later and the decl has been referenced, but duplicate_decls
360135446Strhodes	     should catch the mismatch before this is called.  */
361135446Strhodes	  change_decl_assembler_name (decl, newid);
362135446Strhodes	}
363135446Strhodes    }
364135446Strhodes
365135446Strhodes  /* Mark the decl so we can tell from the rtl whether the object is
366135446Strhodes     dllexport'd or dllimport'd.  tree.c: merge_dllimport_decl_attributes
367135446Strhodes     handles dllexport/dllimport override semantics.  */
368135446Strhodes
369135446Strhodes  if (i386_pe_dllexport_p (decl))
370218384Sdougb    i386_pe_mark_dllexport (decl);
371218384Sdougb  else if (i386_pe_dllimport_p (decl))
372135446Strhodes    i386_pe_mark_dllimport (decl);
373135446Strhodes  /* It might be that DECL has been declared as dllimport, but a
374135446Strhodes     subsequent definition nullified that.  Assert that
375135446Strhodes     tree.c: merge_dllimport_decl_attributes has removed the attribute
376135446Strhodes     before the RTL name was marked with the DLL_IMPORT_PREFIX.  */
377135446Strhodes  else
378135446Strhodes    gcc_assert (!((TREE_CODE (decl) == FUNCTION_DECL
379135446Strhodes	    	   || TREE_CODE (decl) == VAR_DECL)
380135446Strhodes		  && rtl != NULL_RTX
381135446Strhodes		  && GET_CODE (rtl) == MEM
382135446Strhodes		  && GET_CODE (XEXP (rtl, 0)) == MEM
383135446Strhodes		  && GET_CODE (XEXP (XEXP (rtl, 0), 0)) == SYMBOL_REF
384135446Strhodes		  && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (rtl, 0), 0), 0))));
385135446Strhodes}
386135446Strhodes
387135446Strhodes/* Strip only the leading encoding, leaving the stdcall suffix and fastcall
388135446Strhodes   prefix if it exists.  */
389135446Strhodes
390135446Strhodesconst char *
391135446Strhodesi386_pe_strip_name_encoding (const char *str)
392135446Strhodes{
393135446Strhodes  if (strncmp (str, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX))
394135446Strhodes      == 0)
395135446Strhodes    str += strlen (DLL_IMPORT_PREFIX);
396135446Strhodes  else if (strncmp (str, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX))
397135446Strhodes	   == 0)
398135446Strhodes    str += strlen (DLL_EXPORT_PREFIX);
399135446Strhodes  if (*str == '*')
400135446Strhodes    str += 1;
401135446Strhodes  return str;
402135446Strhodes}
403254897Serwin
404254897Serwin/* Also strip the fastcall prefix and stdcall suffix.  */
405135446Strhodes
406135446Strhodesconst char *
407135446Strhodesi386_pe_strip_name_encoding_full (const char *str)
408135446Strhodes{
409135446Strhodes  const char *p;
410135446Strhodes  const char *name = i386_pe_strip_name_encoding (str);
411135446Strhodes
412135446Strhodes  /* Strip leading '@' on fastcall symbols.  */
413254897Serwin  if (*name == '@')
414135446Strhodes    name++;
415254897Serwin
416135446Strhodes  /* Strip trailing "@n".  */
417254897Serwin  p = strchr (name, '@');
418254897Serwin  if (p)
419254897Serwin    return ggc_alloc_string (name, p - name);
420135446Strhodes
421254897Serwin  return name;
422254897Serwin}
423254897Serwin
424186462Sdougb/* Output a reference to a label. Fastcall symbols are prefixed with @,
425254897Serwin   whereas symbols for functions using other calling conventions don't
426254897Serwin   have a prefix (unless they are marked dllimport or dllexport).  */
427254897Serwin
428135446Strhodesvoid i386_pe_output_labelref (FILE *stream, const char *name)
429135446Strhodes{
430135446Strhodes  if (strncmp (name, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX))
431135446Strhodes      == 0)
432135446Strhodes    /* A dll import */
433135446Strhodes    {
434186462Sdougb      if (name[strlen (DLL_IMPORT_PREFIX)] == FASTCALL_PREFIX)
435135446Strhodes      /* A dllimport fastcall symbol.  */
436135446Strhodes        {
437135446Strhodes          fprintf (stream, "__imp_%s",
438135446Strhodes                   i386_pe_strip_name_encoding (name));
439135446Strhodes        }
440135446Strhodes      else
441135446Strhodes      /* A dllimport non-fastcall symbol.  */
442135446Strhodes        {
443135446Strhodes          fprintf (stream, "__imp__%s",
444135446Strhodes                   i386_pe_strip_name_encoding (name));
445135446Strhodes        }
446135446Strhodes    }
447135446Strhodes  else if ((name[0] == FASTCALL_PREFIX)
448135446Strhodes           || (strncmp (name, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX))
449135446Strhodes	       == 0
450135446Strhodes	       && name[strlen (DLL_EXPORT_PREFIX)] == FASTCALL_PREFIX))
451135446Strhodes    /* A fastcall symbol.  */
452254897Serwin    {
453254897Serwin      fprintf (stream, "%s",
454254897Serwin               i386_pe_strip_name_encoding (name));
455254897Serwin    }
456135446Strhodes  else
457135446Strhodes    /* Everything else.  */
458135446Strhodes    {
459135446Strhodes      fprintf (stream, "%s%s", USER_LABEL_PREFIX,
460135446Strhodes               i386_pe_strip_name_encoding (name));
461135446Strhodes    }
462135446Strhodes}
463135446Strhodes
464135446Strhodesvoid
465135446Strhodesi386_pe_unique_section (tree decl, int reloc)
466135446Strhodes{
467254897Serwin  int len;
468135446Strhodes  const char *name, *prefix;
469135446Strhodes  char *string;
470254897Serwin
471254897Serwin  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
472254897Serwin  name = i386_pe_strip_name_encoding_full (name);
473135446Strhodes
474254897Serwin  /* The object is put in, for example, section .text$foo.
475254897Serwin     The linker will then ultimately place them in .text
476254897Serwin     (everything from the $ on is stripped). Don't put
477186462Sdougb     read-only data in .rdata section to avoid a PE linker
478254897Serwin     bug when .rdata$* grouped sections are used in code
479254897Serwin     without a .rdata section.  */
480254897Serwin  if (TREE_CODE (decl) == FUNCTION_DECL)
481135446Strhodes    prefix = ".text$";
482135446Strhodes  else if (decl_readonly_section (decl, reloc))
483135446Strhodes    prefix = ".rdata$";
484135446Strhodes  else
485135446Strhodes    prefix = ".data$";
486135446Strhodes  len = strlen (name) + strlen (prefix);
487135446Strhodes  string = alloca (len + 1);
488135446Strhodes  sprintf (string, "%s%s", prefix, name);
489135446Strhodes
490135446Strhodes  DECL_SECTION_NAME (decl) = build_string (len, string);
491135446Strhodes}
492135446Strhodes
493135446Strhodes/* Select a set of attributes for section NAME based on the properties
494135446Strhodes   of DECL and whether or not RELOC indicates that DECL's initializer
495135446Strhodes   might contain runtime relocations.
496135446Strhodes
497224092Sdougb   We make the section read-only and executable for a function decl,
498224092Sdougb   read-only for a const data decl, and writable for a non-const data decl.
499224092Sdougb
500135446Strhodes   If the section has already been defined, to not allow it to have
501135446Strhodes   different attributes, as (1) this is ambiguous since we're not seeing
502135446Strhodes   all the declarations up front and (2) some assemblers (e.g. SVR4)
503135446Strhodes   do not recognize section redefinitions.  */
504135446Strhodes/* ??? This differs from the "standard" PE implementation in that we
505135446Strhodes   handle the SHARED variable attribute.  Should this be done for all
506135446Strhodes   PE targets?  */
507135446Strhodes
508135446Strhodes#define SECTION_PE_SHARED	SECTION_MACH_DEP
509135446Strhodes
510135446Strhodesunsigned int
511135446Strhodesi386_pe_section_type_flags (tree decl, const char *name, int reloc)
512135446Strhodes{
513135446Strhodes  static htab_t htab;
514135446Strhodes  unsigned int flags;
515135446Strhodes  unsigned int **slot;
516135446Strhodes
517193149Sdougb  /* The names we put in the hashtable will always be the unique
518193149Sdougb     versions given to us by the stringtable, so we can just use
519135446Strhodes     their addresses as the keys.  */
520135446Strhodes  if (!htab)
521135446Strhodes    htab = htab_create (31, htab_hash_pointer, htab_eq_pointer, NULL);
522135446Strhodes
523135446Strhodes  if (decl && TREE_CODE (decl) == FUNCTION_DECL)
524135446Strhodes    flags = SECTION_CODE;
525135446Strhodes  else if (decl && decl_readonly_section (decl, reloc))
526135446Strhodes    flags = 0;
527135446Strhodes  else
528135446Strhodes    {
529135446Strhodes      flags = SECTION_WRITE;
530135446Strhodes
531135446Strhodes      if (decl && TREE_CODE (decl) == VAR_DECL
532135446Strhodes	  && lookup_attribute ("shared", DECL_ATTRIBUTES (decl)))
533135446Strhodes	flags |= SECTION_PE_SHARED;
534135446Strhodes    }
535218384Sdougb
536218384Sdougb  if (decl && DECL_ONE_ONLY (decl))
537135446Strhodes    flags |= SECTION_LINKONCE;
538135446Strhodes
539135446Strhodes  /* See if we already have an entry for this section.  */
540135446Strhodes  slot = (unsigned int **) htab_find_slot (htab, name, INSERT);
541135446Strhodes  if (!*slot)
542135446Strhodes    {
543135446Strhodes      *slot = (unsigned int *) xmalloc (sizeof (unsigned int));
544170222Sdougb      **slot = flags;
545170222Sdougb    }
546170222Sdougb  else
547170222Sdougb    {
548170222Sdougb      if (decl && **slot != flags)
549170222Sdougb	error ("%q+D causes a section type conflict", decl);
550135446Strhodes    }
551254402Serwin
552254402Serwin  return flags;
553254402Serwin}
554254402Serwin
555254402Serwinvoid
556262706Serwini386_pe_asm_named_section (const char *name, unsigned int flags,
557262706Serwin			   tree decl)
558262706Serwin{
559170222Sdougb  char flagchars[8], *f = flagchars;
560262706Serwin
561170222Sdougb  if ((flags & (SECTION_CODE | SECTION_WRITE)) == 0)
562135446Strhodes    /* readonly data */
563135446Strhodes    {
564135446Strhodes      *f++ ='d';  /* This is necessary for older versions of gas.  */
565135446Strhodes      *f++ ='r';
566135446Strhodes    }
567135446Strhodes  else
568135446Strhodes    {
569135446Strhodes      if (flags & SECTION_CODE)
570135446Strhodes        *f++ = 'x';
571135446Strhodes      if (flags & SECTION_WRITE)
572135446Strhodes        *f++ = 'w';
573135446Strhodes      if (flags & SECTION_PE_SHARED)
574135446Strhodes        *f++ = 's';
575135446Strhodes    }
576135446Strhodes
577135446Strhodes  *f = '\0';
578135446Strhodes
579135446Strhodes  fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars);
580135446Strhodes
581135446Strhodes  if (flags & SECTION_LINKONCE)
582135446Strhodes    {
583135446Strhodes      /* Functions may have been compiled at various levels of
584135446Strhodes	 optimization so we can't use `same_size' here.
585135446Strhodes	 Instead, have the linker pick one, without warning.
586135446Strhodes	 If 'selectany' attribute has been specified,  MS compiler
587135446Strhodes	 sets 'discard' characteristic, rather than telling linker
588135446Strhodes	 to warn of size or content mismatch, so do the same.  */
589135446Strhodes      bool discard = (flags & SECTION_CODE)
590135446Strhodes		      || lookup_attribute ("selectany",
591135446Strhodes					   DECL_ATTRIBUTES (decl));
592135446Strhodes      fprintf (asm_out_file, "\t.linkonce %s\n",
593135446Strhodes	       (discard  ? "discard" : "same_size"));
594135446Strhodes    }
595135446Strhodes}
596135446Strhodes
597135446Strhodes/* The Microsoft linker requires that every function be marked as
598135446Strhodes   DT_FCN.  When using gas on cygwin, we must emit appropriate .type
599135446Strhodes   directives.  */
600135446Strhodes
601135446Strhodes#include "gsyms.h"
602135446Strhodes
603135446Strhodes/* Mark a function appropriately.  This should only be called for
604135446Strhodes   functions for which we are not emitting COFF debugging information.
605135446Strhodes   FILE is the assembler output file, NAME is the name of the
606135446Strhodes   function, and PUBLIC is nonzero if the function is globally
607135446Strhodes   visible.  */
608135446Strhodes
609135446Strhodesvoid
610135446Strhodesi386_pe_declare_function_type (FILE *file, const char *name, int public)
611135446Strhodes{
612135446Strhodes  fprintf (file, "\t.def\t");
613135446Strhodes  assemble_name (file, name);
614135446Strhodes  fprintf (file, ";\t.scl\t%d;\t.type\t%d;\t.endef\n",
615135446Strhodes	   public ? (int) C_EXT : (int) C_STAT,
616135446Strhodes	   (int) DT_FCN << N_BTSHFT);
617135446Strhodes}
618135446Strhodes
619135446Strhodes/* Keep a list of external functions.  */
620135446Strhodes
621135446Strhodesstruct extern_list GTY(())
622135446Strhodes{
623135446Strhodes  struct extern_list *next;
624135446Strhodes  tree decl;
625135446Strhodes  const char *name;
626135446Strhodes};
627135446Strhodes
628135446Strhodesstatic GTY(()) struct extern_list *extern_head;
629135446Strhodes
630135446Strhodes/* Assemble an external function reference.  We need to keep a list of
631135446Strhodes   these, so that we can output the function types at the end of the
632135446Strhodes   assembly.  We can't output the types now, because we might see a
633135446Strhodes   definition of the function later on and emit debugging information
634135446Strhodes   for it then.  */
635135446Strhodes
636135446Strhodesvoid
637135446Strhodesi386_pe_record_external_function (tree decl, const char *name)
638135446Strhodes{
639135446Strhodes  struct extern_list *p;
640135446Strhodes
641135446Strhodes  p = (struct extern_list *) ggc_alloc (sizeof *p);
642135446Strhodes  p->next = extern_head;
643135446Strhodes  p->decl = decl;
644135446Strhodes  p->name = name;
645135446Strhodes  extern_head = p;
646135446Strhodes}
647135446Strhodes
648135446Strhodes/* Keep a list of exported symbols.  */
649135446Strhodes
650153816Sdougbstruct export_list GTY(())
651135446Strhodes{
652135446Strhodes  struct export_list *next;
653135446Strhodes  const char *name;
654135446Strhodes  int is_data;		/* used to type tag exported symbols.  */
655135446Strhodes};
656135446Strhodes
657135446Strhodesstatic GTY(()) struct export_list *export_head;
658135446Strhodes
659135446Strhodes/* Assemble an export symbol entry.  We need to keep a list of
660135446Strhodes   these, so that we can output the export list at the end of the
661135446Strhodes   assembly.  We used to output these export symbols in each function,
662135446Strhodes   but that causes problems with GNU ld when the sections are
663135446Strhodes   linkonce.  */
664170222Sdougb
665135446Strhodesvoid
666135446Strhodesi386_pe_record_exported_symbol (const char *name, int is_data)
667135446Strhodes{
668135446Strhodes  struct export_list *p;
669135446Strhodes
670135446Strhodes  p = (struct export_list *) ggc_alloc (sizeof *p);
671135446Strhodes  p->next = export_head;
672135446Strhodes  p->name = name;
673135446Strhodes  p->is_data = is_data;
674135446Strhodes  export_head = p;
675135446Strhodes}
676135446Strhodes
677135446Strhodes/* This is called at the end of assembly.  For each external function
678135446Strhodes   which has not been defined, we output a declaration now.  We also
679135446Strhodes   output the .drectve section.  */
680135446Strhodes
681135446Strhodesvoid
682135446Strhodesi386_pe_file_end (void)
683135446Strhodes{
684135446Strhodes  struct extern_list *p;
685135446Strhodes
686135446Strhodes  ix86_file_end ();
687135446Strhodes
688135446Strhodes  for (p = extern_head; p != NULL; p = p->next)
689143731Sdougb    {
690143731Sdougb      tree decl;
691143731Sdougb
692143731Sdougb      decl = p->decl;
693143731Sdougb
694143731Sdougb      /* Positively ensure only one declaration for any given symbol.  */
695143731Sdougb      if (! TREE_ASM_WRITTEN (decl)
696143731Sdougb	  && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
697143731Sdougb	{
698135446Strhodes	  TREE_ASM_WRITTEN (decl) = 1;
699186462Sdougb	  i386_pe_declare_function_type (asm_out_file, p->name,
700193149Sdougb					 TREE_PUBLIC (decl));
701193149Sdougb	}
702193149Sdougb    }
703135446Strhodes
704135446Strhodes  if (export_head)
705135446Strhodes    {
706135446Strhodes      struct export_list *q;
707135446Strhodes      drectve_section ();
708135446Strhodes      for (q = export_head; q != NULL; q = q->next)
709135446Strhodes	{
710135446Strhodes	  fprintf (asm_out_file, "\t.ascii \" -export:%s%s\"\n",
711170222Sdougb		   i386_pe_strip_name_encoding (q->name),
712135446Strhodes		   (q->is_data) ? ",data" : "");
713135446Strhodes	}
714135446Strhodes    }
715135446Strhodes}
716135446Strhodes
717135446Strhodes#include "gt-winnt.h"
718135446Strhodes