OSDN Git Service

PR c++/16030
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / winnt.c
1 /* Subroutines for insn-output.c for Windows NT.
2    Contributed by Douglas Rupp (drupp@cs.washington.edu)
3    Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
4    Free Software Foundation, Inc.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING.  If not, write to the Free
20 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
21 02111-1307, USA.  */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "rtl.h"
28 #include "regs.h"
29 #include "hard-reg-set.h"
30 #include "output.h"
31 #include "tree.h"
32 #include "flags.h"
33 #include "tm_p.h"
34 #include "toplev.h"
35 #include "hashtab.h"
36 #include "ggc.h"
37
38 /* i386/PE specific attribute support.
39
40    i386/PE has two new attributes:
41    dllexport - for exporting a function/variable that will live in a dll
42    dllimport - for importing a function/variable from a dll
43
44    Microsoft allows multiple declspecs in one __declspec, separating
45    them with spaces.  We do NOT support this.  Instead, use __declspec
46    multiple times.
47 */
48
49 static tree associated_type (tree);
50 static tree gen_stdcall_or_fastcall_suffix (tree, bool);
51 static int i386_pe_dllexport_p (tree);
52 static int i386_pe_dllimport_p (tree);
53 static void i386_pe_mark_dllexport (tree);
54 static void i386_pe_mark_dllimport (tree);
55
56 /* This is we how mark internal identifiers with dllimport or dllexport
57    attributes.  */
58 #ifndef DLL_IMPORT_PREFIX
59 #define DLL_IMPORT_PREFIX "#i."
60 #endif
61 #ifndef DLL_EXPORT_PREFIX
62 #define DLL_EXPORT_PREFIX "#e."
63 #endif
64
65 /* Handle a "shared" attribute;
66    arguments as in struct attribute_spec.handler.  */
67 tree
68 ix86_handle_shared_attribute (tree *node, tree name,
69                               tree args ATTRIBUTE_UNUSED,
70                               int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
71 {
72   if (TREE_CODE (*node) != VAR_DECL)
73     {
74       warning ("`%s' attribute only applies to variables",
75                IDENTIFIER_POINTER (name));
76       *no_add_attrs = true;
77     }
78
79   return NULL_TREE;
80 }
81 \f
82 /* Return the type that we should use to determine if DECL is
83    imported or exported.  */
84
85 static tree
86 associated_type (tree decl)
87 {
88   tree t = NULL_TREE;
89
90   /* In the C++ frontend, DECL_CONTEXT for a method doesn't actually refer
91      to the containing class.  So we look at the 'this' arg.  */
92   if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
93     {
94       /* Artificial methods are not affected by the import/export status
95          of their class unless they are COMDAT.  Implicit copy ctor's and
96          dtor's are not affected by class status but virtual and
97          non-virtual thunks are.  */
98       if (!DECL_ARTIFICIAL (decl) || DECL_COMDAT (decl))
99         t = TYPE_MAIN_VARIANT
100           (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
101     }
102   else if (DECL_CONTEXT (decl)
103            && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't')
104     t = DECL_CONTEXT (decl);
105
106   return t;
107 }
108
109 /* Return nonzero if DECL is a dllexport'd object.  */
110
111 static int
112 i386_pe_dllexport_p (tree decl)
113 {
114   tree exp;
115
116   if (TREE_CODE (decl) != VAR_DECL
117       && TREE_CODE (decl) != FUNCTION_DECL)
118     return 0;
119   exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl));
120   if (exp)
121     return 1;
122
123   /* Class members get the dllexport status of their class.  */
124   if (associated_type (decl))
125     {
126       exp = lookup_attribute ("dllexport",
127                               TYPE_ATTRIBUTES (associated_type (decl)));
128       if (exp)
129         return 1;
130     }
131
132   return 0;
133 }
134
135 /* Return nonzero if DECL is a dllimport'd object.  */
136
137 static int
138 i386_pe_dllimport_p (tree decl)
139 {
140   tree imp;
141   int context_imp = 0;
142
143   if (TREE_CODE (decl) == FUNCTION_DECL
144       && TARGET_NOP_FUN_DLLIMPORT)
145     return 0;
146
147   if (TREE_CODE (decl) != VAR_DECL
148       && TREE_CODE (decl) != FUNCTION_DECL)
149     return 0;
150
151   imp = lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl));
152
153   /* Class members get the dllimport status of their class.  */
154   if (!imp && associated_type (decl))
155     {
156       imp = lookup_attribute ("dllimport",
157                               TYPE_ATTRIBUTES (associated_type (decl)));
158       if (imp)
159         context_imp = 1;
160     }
161
162   if (imp)
163     {
164       /* Don't mark defined functions as dllimport.  If the definition
165          itself was marked with dllimport, than ix86_handle_dll_attribute
166          reports an error. This handles the case when the definition
167          overrides an earlier declaration.  */
168       if (TREE_CODE (decl) ==  FUNCTION_DECL && DECL_INITIAL (decl)
169           && !DECL_INLINE (decl))
170         {
171            /* Don't warn about artificial methods.  */
172           if (!DECL_ARTIFICIAL (decl))
173             warning ("%Jfunction '%D' is defined after prior declaration "
174                      "as dllimport: attribute ignored", decl, decl);
175           return 0;
176         }
177
178       /* We ignore the dllimport attribute for inline member functions.
179          This differs from MSVC behavior which treats it like GNUC
180          'extern inline' extension.  */
181       else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))
182         {
183           if (extra_warnings)
184             warning ("%Jinline function '%D' is declared as dllimport: "
185                      "attribute ignored.", decl, decl);
186           return 0;
187         }
188
189       /*  Don't allow definitions of static data members in dllimport class,
190           Just ignore attribute for vtable data.  */
191       else if (TREE_CODE (decl) == VAR_DECL
192                && TREE_STATIC (decl) && TREE_PUBLIC (decl)
193                && !DECL_EXTERNAL (decl) && context_imp)
194         {
195           if (!DECL_VIRTUAL_P (decl))
196             error ("%Jdefinition of static data member '%D' of "
197                    "dllimport'd class.", decl, decl);
198           return 0;
199         }
200
201       /* Since we can't treat a pointer to a dllimport'd symbol as a
202          constant address, we turn off the attribute on C++ virtual
203          methods to allow creation of vtables using thunks.  Don't mark
204          artificial methods either (in associated_type, only COMDAT
205          artificial method get import status from class context).  */
206       else if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
207                && (DECL_VIRTUAL_P (decl) || DECL_ARTIFICIAL (decl)))
208         return 0;
209
210       return 1;
211     }
212
213   return 0;
214 }
215
216 /* Return nonzero if SYMBOL is marked as being dllexport'd.  */
217
218 int
219 i386_pe_dllexport_name_p (const char *symbol)
220 {
221   return (strncmp (DLL_EXPORT_PREFIX, symbol,
222                    strlen (DLL_EXPORT_PREFIX)) == 0);
223 }
224
225 /* Return nonzero if SYMBOL is marked as being dllimport'd.  */
226
227 int
228 i386_pe_dllimport_name_p (const char *symbol)
229 {
230   return (strncmp (DLL_IMPORT_PREFIX, symbol,
231                    strlen (DLL_IMPORT_PREFIX)) == 0);
232 }
233
234 /* Mark a DECL as being dllexport'd.
235    Note that we override the previous setting (eg: dllimport).  */
236
237 static void
238 i386_pe_mark_dllexport (tree decl)
239 {
240   const char *oldname;
241   char  *newname;
242   rtx rtlname;
243   rtx symref;
244   tree idp;
245
246   rtlname = XEXP (DECL_RTL (decl), 0);
247   if (GET_CODE (rtlname) == SYMBOL_REF)
248     oldname = XSTR (rtlname, 0);
249   else if (GET_CODE (rtlname) == MEM
250            && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
251     oldname = XSTR (XEXP (rtlname, 0), 0);
252   else
253     abort ();
254   if (i386_pe_dllimport_name_p (oldname))
255     {
256       warning ("%Jinconsistent dll linkage for '%D', dllexport assumed.",
257                decl, decl);
258      /* Remove DLL_IMPORT_PREFIX.  */
259       oldname += strlen (DLL_IMPORT_PREFIX);
260       DECL_NON_ADDR_CONST_P (decl) = 0;
261     }
262   else if (i386_pe_dllexport_name_p (oldname))
263     return;  /*  already done  */
264
265   newname = alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1);
266   sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, oldname);
267
268   /* We pass newname through get_identifier to ensure it has a unique
269      address.  RTL processing can sometimes peek inside the symbol ref
270      and compare the string's addresses to see if two symbols are
271      identical.  */
272   idp = get_identifier (newname);
273
274   symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
275   SYMBOL_REF_DECL (symref) = decl;
276   XEXP (DECL_RTL (decl), 0) = symref;
277 }
278
279 /* Mark a DECL as being dllimport'd.  */
280
281 static void
282 i386_pe_mark_dllimport (tree decl)
283 {
284   const char *oldname;
285   char  *newname;
286   tree idp;
287   rtx rtlname, newrtl;
288   rtx symref;
289
290   rtlname = XEXP (DECL_RTL (decl), 0);
291   if (GET_CODE (rtlname) == SYMBOL_REF)
292     oldname = XSTR (rtlname, 0);
293   else if (GET_CODE (rtlname) == MEM
294            && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
295     oldname = XSTR (XEXP (rtlname, 0), 0);
296   else
297     abort ();
298   if (i386_pe_dllexport_name_p (oldname))
299     {
300       error ("`%s' declared as both exported to and imported from a DLL",
301              IDENTIFIER_POINTER (DECL_NAME (decl)));
302       return;
303     }
304   else if (i386_pe_dllimport_name_p (oldname))
305     {
306       /* Already done, but do a sanity check to prevent assembler errors.  */
307       if (!DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl))
308         {
309           error ("%Jfailure in redeclaration of '%D': dllimport'd "
310                  "symbol lacks external linkage.", decl, decl);
311           abort();
312         }
313       return;
314     }
315
316   newname = alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1);
317   sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname);
318
319   /* We pass newname through get_identifier to ensure it has a unique
320      address.  RTL processing can sometimes peek inside the symbol ref
321      and compare the string's addresses to see if two symbols are
322      identical.  */
323   idp = get_identifier (newname);
324
325   symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
326   SYMBOL_REF_DECL (symref) = decl;
327   newrtl = gen_rtx_MEM (Pmode,symref);
328   XEXP (DECL_RTL (decl), 0) = newrtl;
329
330   /* Can't treat a pointer to this as a constant address */
331   DECL_NON_ADDR_CONST_P (decl) = 1;
332 }
333
334 /* Return string which is the former assembler name modified with a
335    suffix consisting of an atsign (@) followed by the number of bytes of
336    arguments.  If FASTCALL is true, also add the FASTCALL_PREFIX.  */
337
338 static tree
339 gen_stdcall_or_fastcall_suffix (tree decl, bool fastcall)
340 {
341   int total = 0;
342   /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
343      of DECL_ASSEMBLER_NAME.  */
344    const char *asmname =  IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
345   char *newsym;
346   char *p;
347   tree formal_type;
348
349   /* Do not change the identifier if a verbatim asmspec or already done. */
350   if (*asmname == '*' || strchr (asmname, '@'))
351     return DECL_ASSEMBLER_NAME (decl);
352
353   formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
354   if (formal_type != NULL_TREE)
355     {
356       /* These attributes are ignored for variadic functions in
357          i386.c:ix86_return_pops_args. For compatibility with MS
358          compiler do not add @0 suffix here.  */ 
359       if (TREE_VALUE (tree_last (formal_type)) != void_type_node)
360         return DECL_ASSEMBLER_NAME (decl);
361
362       /* Quit if we hit an incomplete type.  Error is reported
363          by convert_arguments in c-typeck.c or cp/typeck.c.  */
364       while (TREE_VALUE (formal_type) != void_type_node
365              && COMPLETE_TYPE_P (TREE_VALUE (formal_type)))     
366         {
367           int parm_size
368             = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
369             /* Must round up to include padding.  This is done the same
370                way as in store_one_arg.  */
371           parm_size = ((parm_size + PARM_BOUNDARY - 1)
372                        / PARM_BOUNDARY * PARM_BOUNDARY);
373           total += parm_size;
374           formal_type = TREE_CHAIN (formal_type);\
375         }
376      }
377
378   /* Assume max of 8 base 10 digits in the suffix.  */
379   newsym = alloca (1 + strlen (asmname) + 1 + 8 + 1);
380   p = newsym;
381   if (fastcall)
382     *p++ = FASTCALL_PREFIX;
383   sprintf (p, "%s@%d", asmname, total/BITS_PER_UNIT);
384   return get_identifier (newsym);
385 }
386
387 void
388 i386_pe_encode_section_info (tree decl, rtx rtl, int first)
389 {
390   default_encode_section_info (decl, rtl, first);
391
392   if (first && TREE_CODE (decl) == FUNCTION_DECL)
393     {
394       tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
395       tree newid = NULL_TREE;
396
397       if (lookup_attribute ("stdcall", type_attributes))
398         newid = gen_stdcall_or_fastcall_suffix (decl, false);
399       else if (lookup_attribute ("fastcall", type_attributes))
400         newid = gen_stdcall_or_fastcall_suffix (decl, true);
401       if (newid != NULL_TREE)   
402         {
403           rtx rtlname = XEXP (rtl, 0);
404           if (GET_CODE (rtlname) == MEM)
405             rtlname = XEXP (rtlname, 0);
406           XSTR (rtlname, 0) = IDENTIFIER_POINTER (newid);
407           /* These attributes must be present on first declaration,
408              change_decl_assembler_name will warn if they are added
409              later and the decl has been referenced, but duplicate_decls
410              should catch the mismatch before this is called.  */ 
411           change_decl_assembler_name (decl, newid);
412         }
413     }
414
415   /* Mark the decl so we can tell from the rtl whether the object is
416      dllexport'd or dllimport'd.  This also handles dllexport/dllimport
417      override semantics.  */
418
419   if (i386_pe_dllexport_p (decl))
420     i386_pe_mark_dllexport (decl);
421   else if (i386_pe_dllimport_p (decl))
422     i386_pe_mark_dllimport (decl);
423   /* It might be that DECL has already been marked as dllimport, but a
424      subsequent definition nullified that.  The attribute is gone but
425      DECL_RTL still has (DLL_IMPORT_PREFIX) prefixed. We need to remove
426      that. Ditto for the DECL_NON_ADDR_CONST_P flag.  */
427   else if ((TREE_CODE (decl) == FUNCTION_DECL
428             || TREE_CODE (decl) == VAR_DECL)
429            && DECL_RTL (decl) != NULL_RTX
430            && GET_CODE (DECL_RTL (decl)) == MEM
431            && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
432            && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF
433            && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0)))
434     {
435       const char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
436
437       /* Remove DLL_IMPORT_PREFIX.  */
438       tree idp = get_identifier (oldname + strlen (DLL_IMPORT_PREFIX));
439       rtx symref = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
440       SYMBOL_REF_DECL (symref) = decl;
441       XEXP (DECL_RTL (decl), 0) = symref;
442       DECL_NON_ADDR_CONST_P (decl) = 0;
443
444       /* We previously set TREE_PUBLIC and DECL_EXTERNAL.
445          We leave these alone for now.  */
446
447       if (DECL_INITIAL (decl) || !DECL_EXTERNAL (decl))
448         warning ("%J'%D' defined locally after being "
449                  "referenced with dllimport linkage", decl, decl);
450       else
451         warning ("%J'%D' redeclared without dllimport attribute "
452                  "after being referenced with dllimport linkage", decl, decl);
453     }
454 }
455
456 /* Strip only the leading encoding, leaving the stdcall suffix and fastcall
457    prefix if it exists.  */
458
459 const char *
460 i386_pe_strip_name_encoding (const char *str)
461 {
462   if (strncmp (str, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX))
463       == 0)
464     str += strlen (DLL_IMPORT_PREFIX);
465   else if (strncmp (str, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX))
466            == 0)
467     str += strlen (DLL_EXPORT_PREFIX);
468   if (*str == '*')
469     str += 1;
470   return str;
471 }
472
473 /* Also strip the fastcall prefix and stdcall suffix.  */
474
475 const char *
476 i386_pe_strip_name_encoding_full (const char *str)
477 {
478   const char *p;
479   const char *name = i386_pe_strip_name_encoding (str);
480
481   /* Strip leading '@' on fastcall symbols.  */
482   if (*name == '@')
483     name++;
484
485   /* Strip trailing "@n".  */
486   p = strchr (name, '@');
487   if (p)
488     return ggc_alloc_string (name, p - name);
489
490   return name;
491 }
492
493 /* Output a reference to a label. Fastcall symbols are prefixed with @,
494    whereas symbols for functions using other calling conventions don't
495    have a prefix (unless they are marked dllimport or dllexport).  */
496
497 void i386_pe_output_labelref (FILE *stream, const char *name)
498 {
499   if (strncmp (name, DLL_IMPORT_PREFIX, strlen (DLL_IMPORT_PREFIX))
500       == 0)
501     /* A dll import */
502     {
503       if (name[strlen (DLL_IMPORT_PREFIX)] == FASTCALL_PREFIX)
504       /* A dllimport fastcall symbol.  */
505         {
506           fprintf (stream, "__imp_%s",
507                    i386_pe_strip_name_encoding (name));
508         }
509       else
510       /* A dllimport non-fastcall symbol.  */
511         {
512           fprintf (stream, "__imp__%s",
513                    i386_pe_strip_name_encoding (name));
514         }
515     }
516   else if ((name[0] == FASTCALL_PREFIX)
517            || (strncmp (name, DLL_EXPORT_PREFIX, strlen (DLL_EXPORT_PREFIX))
518                == 0
519                && name[strlen (DLL_EXPORT_PREFIX)] == FASTCALL_PREFIX))
520     /* A fastcall symbol.  */
521     {
522       fprintf (stream, "%s",
523                i386_pe_strip_name_encoding (name));
524     }
525   else
526     /* Everything else.  */
527     {
528       fprintf (stream, "%s%s", USER_LABEL_PREFIX,
529                i386_pe_strip_name_encoding (name));
530     }
531 }
532
533 void
534 i386_pe_unique_section (tree decl, int reloc)
535 {
536   int len;
537   const char *name, *prefix;
538   char *string;
539
540   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
541   name = i386_pe_strip_name_encoding_full (name);
542
543   /* The object is put in, for example, section .text$foo.
544      The linker will then ultimately place them in .text
545      (everything from the $ on is stripped). Don't put
546      read-only data in .rdata section to avoid a PE linker
547      bug when .rdata$* grouped sections are used in code
548      without a .rdata section.  */
549   if (TREE_CODE (decl) == FUNCTION_DECL)
550     prefix = ".text$";
551   else if (decl_readonly_section (decl, reloc))
552     prefix = ".rdata$";
553   else
554     prefix = ".data$";
555   len = strlen (name) + strlen (prefix);
556   string = alloca (len + 1);
557   sprintf (string, "%s%s", prefix, name);
558
559   DECL_SECTION_NAME (decl) = build_string (len, string);
560 }
561
562 /* Select a set of attributes for section NAME based on the properties
563    of DECL and whether or not RELOC indicates that DECL's initializer
564    might contain runtime relocations.
565
566    We make the section read-only and executable for a function decl,
567    read-only for a const data decl, and writable for a non-const data decl.
568
569    If the section has already been defined, to not allow it to have
570    different attributes, as (1) this is ambiguous since we're not seeing
571    all the declarations up front and (2) some assemblers (e.g. SVR4)
572    do not recognize section redefinitions.  */
573 /* ??? This differs from the "standard" PE implementation in that we
574    handle the SHARED variable attribute.  Should this be done for all
575    PE targets?  */
576
577 #define SECTION_PE_SHARED       SECTION_MACH_DEP
578
579 unsigned int
580 i386_pe_section_type_flags (tree decl, const char *name, int reloc)
581 {
582   static htab_t htab;
583   unsigned int flags;
584   unsigned int **slot;
585
586   /* The names we put in the hashtable will always be the unique
587      versions given to us by the stringtable, so we can just use
588      their addresses as the keys.  */
589   if (!htab)
590     htab = htab_create (31, htab_hash_pointer, htab_eq_pointer, NULL);
591
592   if (decl && TREE_CODE (decl) == FUNCTION_DECL)
593     flags = SECTION_CODE;
594   else if (decl && decl_readonly_section (decl, reloc))
595     flags = 0;
596   else
597     {
598       flags = SECTION_WRITE;
599
600       if (decl && TREE_CODE (decl) == VAR_DECL
601           && lookup_attribute ("shared", DECL_ATTRIBUTES (decl)))
602         flags |= SECTION_PE_SHARED;
603     }
604
605   if (decl && DECL_ONE_ONLY (decl))
606     flags |= SECTION_LINKONCE;
607
608   /* See if we already have an entry for this section.  */
609   slot = (unsigned int **) htab_find_slot (htab, name, INSERT);
610   if (!*slot)
611     {
612       *slot = (unsigned int *) xmalloc (sizeof (unsigned int));
613       **slot = flags;
614     }
615   else
616     {
617       if (decl && **slot != flags)
618         error ("%J'%D' causes a section type conflict", decl, decl);
619     }
620
621   return flags;
622 }
623
624 void
625 i386_pe_asm_named_section (const char *name, unsigned int flags)
626 {
627   char flagchars[8], *f = flagchars;
628
629   if ((flags & (SECTION_CODE | SECTION_WRITE)) == 0)
630     /* readonly data */
631     {
632       *f++ ='d';  /* This is necessary for older versions of gas.  */
633       *f++ ='r';
634     }
635   else  
636     {
637       if (flags & SECTION_CODE)
638         *f++ = 'x';
639       if (flags & SECTION_WRITE)
640         *f++ = 'w';
641       if (flags & SECTION_PE_SHARED)
642         *f++ = 's';
643     }
644
645   *f = '\0';
646
647   fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars);
648
649   if (flags & SECTION_LINKONCE)
650     {
651       /* Functions may have been compiled at various levels of
652          optimization so we can't use `same_size' here.
653          Instead, have the linker pick one.  */
654       fprintf (asm_out_file, "\t.linkonce %s\n",
655                (flags & SECTION_CODE ? "discard" : "same_size"));
656     }
657 }
658 \f
659 /* The Microsoft linker requires that every function be marked as
660    DT_FCN.  When using gas on cygwin, we must emit appropriate .type
661    directives.  */
662
663 #include "gsyms.h"
664
665 /* Mark a function appropriately.  This should only be called for
666    functions for which we are not emitting COFF debugging information.
667    FILE is the assembler output file, NAME is the name of the
668    function, and PUBLIC is nonzero if the function is globally
669    visible.  */
670
671 void
672 i386_pe_declare_function_type (FILE *file, const char *name, int public)
673 {
674   fprintf (file, "\t.def\t");
675   assemble_name (file, name);
676   fprintf (file, ";\t.scl\t%d;\t.type\t%d;\t.endef\n",
677            public ? (int) C_EXT : (int) C_STAT,
678            (int) DT_FCN << N_BTSHFT);
679 }
680
681 /* Keep a list of external functions.  */
682
683 struct extern_list GTY(())
684 {
685   struct extern_list *next;
686   const char *name;
687 };
688
689 static GTY(()) struct extern_list *extern_head;
690
691 /* Assemble an external function reference.  We need to keep a list of
692    these, so that we can output the function types at the end of the
693    assembly.  We can't output the types now, because we might see a
694    definition of the function later on and emit debugging information
695    for it then.  */
696
697 void
698 i386_pe_record_external_function (const char *name)
699 {
700   struct extern_list *p;
701
702   p = (struct extern_list *) ggc_alloc (sizeof *p);
703   p->next = extern_head;
704   p->name = name;
705   extern_head = p;
706 }
707
708 /* Keep a list of exported symbols.  */
709
710 struct export_list GTY(())
711 {
712   struct export_list *next;
713   const char *name;
714   int is_data;          /* used to type tag exported symbols.  */
715 };
716
717 static GTY(()) struct export_list *export_head;
718
719 /* Assemble an export symbol entry.  We need to keep a list of
720    these, so that we can output the export list at the end of the
721    assembly.  We used to output these export symbols in each function,
722    but that causes problems with GNU ld when the sections are
723    linkonce.  */
724
725 void
726 i386_pe_record_exported_symbol (const char *name, int is_data)
727 {
728   struct export_list *p;
729
730   p = (struct export_list *) ggc_alloc (sizeof *p);
731   p->next = export_head;
732   p->name = name;
733   p->is_data = is_data;
734   export_head = p;
735 }
736
737 /* This is called at the end of assembly.  For each external function
738    which has not been defined, we output a declaration now.  We also
739    output the .drectve section.  */
740
741 void
742 i386_pe_file_end (void)
743 {
744   struct extern_list *p;
745
746   ix86_file_end ();
747
748   for (p = extern_head; p != NULL; p = p->next)
749     {
750       tree decl;
751
752       decl = get_identifier (p->name);
753
754       /* Positively ensure only one declaration for any given symbol.  */
755       if (! TREE_ASM_WRITTEN (decl) && TREE_SYMBOL_REFERENCED (decl))
756         {
757           TREE_ASM_WRITTEN (decl) = 1;
758           i386_pe_declare_function_type (asm_out_file, p->name,
759                                          TREE_PUBLIC (decl));
760         }
761     }
762
763   if (export_head)
764     {
765       struct export_list *q;
766       drectve_section ();
767       for (q = export_head; q != NULL; q = q->next)
768         {
769           fprintf (asm_out_file, "\t.ascii \" -export:%s%s\"\n",
770                    i386_pe_strip_name_encoding (q->name),
771                    (q->is_data) ? ",data" : "");
772         }
773     }
774 }
775
776 #include "gt-winnt.h"