1 /* Subroutines for insn-output.c for Windows NT.
2    Contributed by Douglas Rupp (drupp@cs.washington.edu)
3    Copyright (C) 1995-2014 Free Software Foundation, Inc.
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11 
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "output.h"
29 #include "tree.h"
30 #include "stringpool.h"
31 #include "varasm.h"
32 #include "flags.h"
33 #include "tm_p.h"
34 #include "diagnostic-core.h"
35 #include "hash-table.h"
36 #include "langhooks.h"
37 #include "ggc.h"
38 #include "target.h"
39 #include "except.h"
40 #include "pointer-set.h"
41 #include "hash-table.h"
42 #include "vec.h"
43 #include "basic-block.h"
44 #include "tree-ssa-alias.h"
45 #include "internal-fn.h"
46 #include "gimple-fold.h"
47 #include "tree-eh.h"
48 #include "gimple-expr.h"
49 #include "is-a.h"
50 #include "gimple.h"
51 #include "lto-streamer.h"
52 
53 /* i386/PE specific attribute support.
54 
55    i386/PE has two new attributes:
56    dllexport - for exporting a function/variable that will live in a dll
57    dllimport - for importing a function/variable from a dll
58 
59    Microsoft allows multiple declspecs in one __declspec, separating
60    them with spaces.  We do NOT support this.  Instead, use __declspec
61    multiple times.
62 */
63 
64 /* Handle a "shared" attribute;
65    arguments as in struct attribute_spec.handler.  */
66 tree
ix86_handle_shared_attribute(tree * node,tree name,tree args ATTRIBUTE_UNUSED,int flags ATTRIBUTE_UNUSED,bool * no_add_attrs)67 ix86_handle_shared_attribute (tree *node, tree name,
68 			      tree args ATTRIBUTE_UNUSED,
69 			      int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
70 {
71   if (TREE_CODE (*node) != VAR_DECL)
72     {
73       warning (OPT_Wattributes, "%qE attribute only applies to variables",
74 	       name);
75       *no_add_attrs = true;
76     }
77 
78   return NULL_TREE;
79 }
80 
81 /* Handle a "selectany" attribute;
82    arguments as in struct attribute_spec.handler.  */
83 tree
ix86_handle_selectany_attribute(tree * node,tree name,tree args ATTRIBUTE_UNUSED,int flags ATTRIBUTE_UNUSED,bool * no_add_attrs)84 ix86_handle_selectany_attribute (tree *node, tree name,
85 			         tree args ATTRIBUTE_UNUSED,
86 			         int flags ATTRIBUTE_UNUSED,
87 				 bool *no_add_attrs)
88 {
89   /* The attribute applies only to objects that are initialized and have
90      external linkage.  However, we may not know about initialization
91      until the language frontend has processed the decl. We'll check for
92      initialization later in encode_section_info.  */
93   if (TREE_CODE (*node) != VAR_DECL || !TREE_PUBLIC (*node))
94     {
95       error ("%qE attribute applies only to initialized variables"
96        	     " with external linkage", name);
97       *no_add_attrs = true;
98     }
99 
100   return NULL_TREE;
101 }
102 
103 
104 /* Return the type that we should use to determine if DECL is
105    imported or exported.  */
106 
107 static tree
associated_type(tree decl)108 associated_type (tree decl)
109 {
110   return (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl))
111           ?  DECL_CONTEXT (decl) : NULL_TREE);
112 }
113 
114 /* Return true if DECL should be a dllexport'd object.  */
115 
116 static bool
i386_pe_determine_dllexport_p(tree decl)117 i386_pe_determine_dllexport_p (tree decl)
118 {
119   if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
120     return false;
121 
122   /* Don't export local clones of dllexports.  */
123   if (!TREE_PUBLIC (decl))
124     return false;
125 
126   if (TREE_CODE (decl) == FUNCTION_DECL
127       && DECL_DECLARED_INLINE_P (decl)
128       && !flag_keep_inline_dllexport)
129     return false;
130 
131   if (lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)))
132     return true;
133 
134   return false;
135 }
136 
137 /* Return true if DECL should be a dllimport'd object.  */
138 
139 static bool
i386_pe_determine_dllimport_p(tree decl)140 i386_pe_determine_dllimport_p (tree decl)
141 {
142   tree assoc;
143 
144   if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
145     return false;
146 
147   if (DECL_DLLIMPORT_P (decl))
148     return true;
149 
150   /* The DECL_DLLIMPORT_P flag was set for decls in the class definition
151      by  targetm.cxx.adjust_class_at_definition.  Check again to emit
152      error message if the class attribute has been overridden by an
153      out-of-class definition of static data.  */
154   assoc = associated_type (decl);
155   if (assoc && lookup_attribute ("dllimport", TYPE_ATTRIBUTES (assoc))
156       && TREE_CODE (decl) == VAR_DECL
157       && TREE_STATIC (decl) && TREE_PUBLIC (decl)
158       && !DECL_EXTERNAL (decl)
159       /* vtable's are linkonce constants, so defining a vtable is not
160 	 an error as long as we don't try to import it too.  */
161       && !DECL_VIRTUAL_P (decl))
162 	error ("definition of static data member %q+D of "
163 	       "dllimport%'d class", decl);
164 
165   return false;
166 }
167 
168 /* Handle the -mno-fun-dllimport target switch.  */
169 
170 bool
i386_pe_valid_dllimport_attribute_p(const_tree decl)171 i386_pe_valid_dllimport_attribute_p (const_tree decl)
172 {
173    if (TARGET_NOP_FUN_DLLIMPORT && TREE_CODE (decl) == FUNCTION_DECL)
174      return false;
175    return true;
176 }
177 
178 /* Return string which is the function name, identified by ID, modified
179    with a suffix consisting of an atsign (@) followed by the number of
180    bytes of arguments.  If ID is NULL use the DECL_NAME as base. If
181    FASTCALL is true, also add the FASTCALL_PREFIX.
182    Return NULL if no change required.  */
183 
184 static tree
gen_stdcall_or_fastcall_suffix(tree decl,tree id,bool fastcall)185 gen_stdcall_or_fastcall_suffix (tree decl, tree id, bool fastcall)
186 {
187   HOST_WIDE_INT total = 0;
188   const char *old_str = IDENTIFIER_POINTER (id != NULL_TREE ? id : DECL_NAME (decl));
189   char *new_str, *p;
190   tree type = TREE_TYPE (DECL_ORIGIN (decl));
191   tree arg;
192   function_args_iterator args_iter;
193 
194   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
195 
196   if (prototype_p (type))
197     {
198       /* This attribute is ignored for variadic functions.  */
199       if (stdarg_p (type))
200 	return NULL_TREE;
201 
202       /* Quit if we hit an incomplete type.  Error is reported
203 	 by convert_arguments in c-typeck.c or cp/typeck.c.  */
204       FOREACH_FUNCTION_ARGS(type, arg, args_iter)
205 	{
206 	  HOST_WIDE_INT parm_size;
207 	  HOST_WIDE_INT parm_boundary_bytes = PARM_BOUNDARY / BITS_PER_UNIT;
208 
209 	  if (! COMPLETE_TYPE_P (arg))
210 	    break;
211 
212 	  parm_size = int_size_in_bytes (arg);
213 	  if (parm_size < 0)
214 	    break;
215 
216 	  /* Must round up to include padding.  This is done the same
217 	     way as in store_one_arg.  */
218 	  parm_size = ((parm_size + parm_boundary_bytes - 1)
219 		       / parm_boundary_bytes * parm_boundary_bytes);
220 	  total += parm_size;
221 	}
222     }
223 
224   /* Assume max of 8 base 10 digits in the suffix.  */
225   p = new_str = XALLOCAVEC (char, 1 + strlen (old_str) + 1 + 8 + 1);
226   if (fastcall)
227     *p++ = FASTCALL_PREFIX;
228   sprintf (p, "%s@" HOST_WIDE_INT_PRINT_DEC, old_str, total);
229 
230   return get_identifier (new_str);
231 }
232 
233 /* Maybe decorate and get a new identifier for the DECL of a stdcall or
234    fastcall function. The original identifier is supplied in ID. */
235 
236 static tree
i386_pe_maybe_mangle_decl_assembler_name(tree decl,tree id)237 i386_pe_maybe_mangle_decl_assembler_name (tree decl, tree id)
238 {
239   tree new_id = NULL_TREE;
240 
241   if (TREE_CODE (decl) == FUNCTION_DECL)
242     {
243       unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (decl));
244       if ((ccvt & IX86_CALLCVT_STDCALL) != 0)
245         {
246 	  if (TARGET_RTD)
247 	    /* If we are using -mrtd emit undecorated symbol and let linker
248 	       do the proper resolving.  */
249 	    return NULL_TREE;
250 	  new_id = gen_stdcall_or_fastcall_suffix (decl, id, false);
251 	}
252       else if ((ccvt & IX86_CALLCVT_FASTCALL) != 0)
253 	new_id = gen_stdcall_or_fastcall_suffix (decl, id, true);
254     }
255 
256   return new_id;
257 }
258 
259 /* Emit an assembler directive to set symbol for DECL visibility to
260    the visibility type VIS, which must not be VISIBILITY_DEFAULT.
261    As for PE there is no hidden support in gas, we just warn for
262    user-specified visibility attributes.  */
263 
264 void
i386_pe_assemble_visibility(tree decl,int vis ATTRIBUTE_UNUSED)265 i386_pe_assemble_visibility (tree decl,
266 			     int vis ATTRIBUTE_UNUSED)
267 {
268   if (!decl
269       || !lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
270     return;
271   if (!DECL_ARTIFICIAL (decl))
272     warning (OPT_Wattributes, "visibility attribute not supported "
273 			      "in this configuration; ignored");
274 }
275 
276 /* This is used as a target hook to modify the DECL_ASSEMBLER_NAME
277    in the language-independent default hook
278    langhooks,c:lhd_set_decl_assembler_name ()
279    and in cp/mangle,c:mangle_decl ().  */
280 tree
i386_pe_mangle_decl_assembler_name(tree decl,tree id)281 i386_pe_mangle_decl_assembler_name (tree decl, tree id)
282 {
283   tree new_id = i386_pe_maybe_mangle_decl_assembler_name (decl, id);
284 
285   return (new_id ? new_id : id);
286 }
287 
288 /* This hook behaves the same as varasm.c/assemble_name(), but
289    generates the name into memory rather than outputting it to
290    a file stream.  */
291 
292 tree
i386_pe_mangle_assembler_name(const char * name ATTRIBUTE_UNUSED)293 i386_pe_mangle_assembler_name (const char *name ATTRIBUTE_UNUSED)
294 {
295   const char *skipped = name + (*name == '*' ? 1 : 0);
296   const char *stripped = targetm.strip_name_encoding (skipped);
297   if (*name != '*' && *user_label_prefix && *stripped != FASTCALL_PREFIX)
298     stripped = ACONCAT ((user_label_prefix, stripped, NULL));
299   return get_identifier (stripped);
300 }
301 
302 void
i386_pe_encode_section_info(tree decl,rtx rtl,int first)303 i386_pe_encode_section_info (tree decl, rtx rtl, int first)
304 {
305   rtx symbol;
306   int flags;
307 
308   /* Do this last, due to our frobbing of DECL_DLLIMPORT_P above.  */
309   default_encode_section_info (decl, rtl, first);
310 
311   /* Careful not to prod global register variables.  */
312   if (!MEM_P (rtl))
313     return;
314 
315   symbol = XEXP (rtl, 0);
316   gcc_assert (GET_CODE (symbol) == SYMBOL_REF);
317 
318   switch (TREE_CODE (decl))
319     {
320     case FUNCTION_DECL:
321       /* FIXME:  Imported stdcall names are not modified by the Ada frontend.
322 	 Check and decorate the RTL name now.  */
323       if  (strcmp (lang_hooks.name, "GNU Ada") == 0)
324 	{
325 	  tree new_id;
326 	  tree old_id = DECL_ASSEMBLER_NAME (decl);
327 	  const char* asm_str = IDENTIFIER_POINTER (old_id);
328 	  /* Do not change the identifier if a verbatim asmspec
329 	     or if stdcall suffix already added. */
330 	  if (!(*asm_str == '*' || strchr (asm_str, '@'))
331 	      && (new_id = i386_pe_maybe_mangle_decl_assembler_name (decl,
332 								     old_id)))
333 	    XSTR (symbol, 0) = IDENTIFIER_POINTER (new_id);
334 	}
335       break;
336 
337     case VAR_DECL:
338       if (lookup_attribute ("selectany", DECL_ATTRIBUTES (decl)))
339 	{
340 	  if (DECL_INITIAL (decl)
341 	      /* If an object is initialized with a ctor, the static
342 		 initialization and destruction code for it is present in
343 		 each unit defining the object.  The code that calls the
344 		 ctor is protected by a link-once guard variable, so that
345 		 the object still has link-once semantics,  */
346 	      || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
347 	    make_decl_one_only (decl, DECL_ASSEMBLER_NAME (decl));
348 	  else
349 	    error ("%q+D:'selectany' attribute applies only to "
350 		   "initialized objects", decl);
351 	}
352       break;
353 
354     default:
355       return;
356     }
357 
358   /* Mark the decl so we can tell from the rtl whether the object is
359      dllexport'd or dllimport'd.  tree.c: merge_dllimport_decl_attributes
360      handles dllexport/dllimport override semantics.  */
361   flags = (SYMBOL_REF_FLAGS (symbol) &
362 	   ~(SYMBOL_FLAG_DLLIMPORT | SYMBOL_FLAG_DLLEXPORT));
363   if (i386_pe_determine_dllexport_p (decl))
364     flags |= SYMBOL_FLAG_DLLEXPORT;
365   else if (i386_pe_determine_dllimport_p (decl))
366     flags |= SYMBOL_FLAG_DLLIMPORT;
367 
368   SYMBOL_REF_FLAGS (symbol) = flags;
369 }
370 
371 
372 bool
i386_pe_binds_local_p(const_tree exp)373 i386_pe_binds_local_p (const_tree exp)
374 {
375   if ((TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == FUNCTION_DECL)
376       && DECL_DLLIMPORT_P (exp))
377     return false;
378 
379   /* External public symbols, which aren't weakref-s,
380      have local-binding for PE targets.  */
381   if (DECL_P (exp)
382       && !lookup_attribute ("weakref", DECL_ATTRIBUTES (exp))
383       && TREE_PUBLIC (exp)
384       && DECL_EXTERNAL (exp))
385     return true;
386   return default_binds_local_p_1 (exp, 0);
387 }
388 
389 /* Also strip the fastcall prefix and stdcall suffix.  */
390 
391 const char *
i386_pe_strip_name_encoding_full(const char * str)392 i386_pe_strip_name_encoding_full (const char *str)
393 {
394   const char *p;
395   const char *name = default_strip_name_encoding (str);
396 
397   /* Strip leading '@' on fastcall symbols.  */
398   if (*name == '@')
399     name++;
400 
401   /* Strip trailing "@n".  */
402   p = strchr (name, '@');
403   if (p)
404     return ggc_alloc_string (name, p - name);
405 
406   return name;
407 }
408 
409 void
i386_pe_unique_section(tree decl,int reloc)410 i386_pe_unique_section (tree decl, int reloc)
411 {
412   int len;
413   const char *name, *prefix;
414   char *string;
415 
416   /* Ignore RELOC, if we are allowed to put relocated
417      const data into read-only section.  */
418   if (!flag_writable_rel_rdata)
419     reloc = 0;
420   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
421   name = i386_pe_strip_name_encoding_full (name);
422 
423   /* The object is put in, for example, section .text$foo.
424      The linker will then ultimately place them in .text
425      (everything from the $ on is stripped). Don't put
426      read-only data in .rdata section to avoid a PE linker
427      bug when .rdata$* grouped sections are used in code
428      without a .rdata section.  */
429   if (TREE_CODE (decl) == FUNCTION_DECL)
430     prefix = ".text$";
431   else if (decl_readonly_section (decl, reloc))
432     prefix = ".rdata$";
433   else
434     prefix = ".data$";
435   len = strlen (name) + strlen (prefix);
436   string = XALLOCAVEC (char, len + 1);
437   sprintf (string, "%s%s", prefix, name);
438 
439   DECL_SECTION_NAME (decl) = build_string (len, string);
440 }
441 
442 /* Local and global relocs can be placed always into readonly memory for
443    memory for PE-COFF targets.  */
444 int
i386_pe_reloc_rw_mask(void)445 i386_pe_reloc_rw_mask (void)
446 {
447   return 0;
448 }
449 
450 /* Select a set of attributes for section NAME based on the properties
451    of DECL and whether or not RELOC indicates that DECL's initializer
452    might contain runtime relocations.
453 
454    We make the section read-only and executable for a function decl,
455    read-only for a const data decl, and writable for a non-const data decl.
456 
457    If the section has already been defined, to not allow it to have
458    different attributes, as (1) this is ambiguous since we're not seeing
459    all the declarations up front and (2) some assemblers (e.g. SVR4)
460    do not recognize section redefinitions.  */
461 /* ??? This differs from the "standard" PE implementation in that we
462    handle the SHARED variable attribute.  Should this be done for all
463    PE targets?  */
464 
465 #define SECTION_PE_SHARED	SECTION_MACH_DEP
466 
467 unsigned int
i386_pe_section_type_flags(tree decl,const char * name,int reloc)468 i386_pe_section_type_flags (tree decl, const char *name, int reloc)
469 {
470   static hash_table <pointer_hash <unsigned int> > htab;
471   unsigned int flags;
472   unsigned int **slot;
473 
474   /* Ignore RELOC, if we are allowed to put relocated
475      const data into read-only section.  */
476   if (!flag_writable_rel_rdata)
477     reloc = 0;
478   /* The names we put in the hashtable will always be the unique
479      versions given to us by the stringtable, so we can just use
480      their addresses as the keys.  */
481   if (!htab.is_created ())
482     htab.create (31);
483 
484   if (decl && TREE_CODE (decl) == FUNCTION_DECL)
485     flags = SECTION_CODE;
486   else if (decl && decl_readonly_section (decl, reloc))
487     flags = 0;
488   else
489     {
490       flags = SECTION_WRITE;
491 
492       if (decl && TREE_CODE (decl) == VAR_DECL
493 	  && lookup_attribute ("shared", DECL_ATTRIBUTES (decl)))
494 	flags |= SECTION_PE_SHARED;
495     }
496 
497   if (decl && DECL_P (decl) && DECL_ONE_ONLY (decl))
498     flags |= SECTION_LINKONCE;
499 
500   /* See if we already have an entry for this section.  */
501   slot = htab.find_slot ((const unsigned int *)name, INSERT);
502   if (!*slot)
503     {
504       *slot = (unsigned int *) xmalloc (sizeof (unsigned int));
505       **slot = flags;
506     }
507   else
508     {
509       if (decl && **slot != flags)
510 	error ("%q+D causes a section type conflict", decl);
511     }
512 
513   return flags;
514 }
515 
516 void
i386_pe_asm_named_section(const char * name,unsigned int flags,tree decl)517 i386_pe_asm_named_section (const char *name, unsigned int flags,
518 			   tree decl)
519 {
520   char flagchars[8], *f = flagchars;
521 
522 #if defined (HAVE_GAS_SECTION_EXCLUDE) && HAVE_GAS_SECTION_EXCLUDE == 1
523   if ((flags & SECTION_EXCLUDE) != 0)
524     *f++ = 'e';
525 #endif
526 
527   if ((flags & (SECTION_CODE | SECTION_WRITE)) == 0)
528     /* readonly data */
529     {
530       *f++ ='d';  /* This is necessary for older versions of gas.  */
531       *f++ ='r';
532     }
533   else
534     {
535       if (flags & SECTION_CODE)
536         *f++ = 'x';
537       if (flags & SECTION_WRITE)
538         *f++ = 'w';
539       if (flags & SECTION_PE_SHARED)
540         *f++ = 's';
541 #if !defined (HAVE_GAS_SECTION_EXCLUDE) || HAVE_GAS_SECTION_EXCLUDE == 0
542       /* If attribute "e" isn't supported we mark this section as
543          never-load.  */
544       if ((flags & SECTION_EXCLUDE) != 0)
545 	*f++ = 'n';
546 #endif
547     }
548 
549   /* LTO sections need 1-byte alignment to avoid confusing the
550      zlib decompression algorithm with trailing zero pad bytes.  */
551   if (strncmp (name, LTO_SECTION_NAME_PREFIX,
552 			strlen (LTO_SECTION_NAME_PREFIX)) == 0)
553     *f++ = '0';
554 
555   *f = '\0';
556 
557   fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars);
558 
559   if (flags & SECTION_LINKONCE)
560     {
561       /* Functions may have been compiled at various levels of
562 	 optimization so we can't use `same_size' here.
563 	 Instead, have the linker pick one, without warning.
564 	 If 'selectany' attribute has been specified,  MS compiler
565 	 sets 'discard' characteristic, rather than telling linker
566 	 to warn of size or content mismatch, so do the same.  */
567       bool discard = (flags & SECTION_CODE)
568 		      || (TREE_CODE (decl) != IDENTIFIER_NODE
569 			  && lookup_attribute ("selectany",
570 					       DECL_ATTRIBUTES (decl)));
571       fprintf (asm_out_file, "\t.linkonce %s\n",
572 	       (discard  ? "discard" : "same_size"));
573     }
574 }
575 
576 /* Beware, DECL may be NULL if compile_file() is emitting the LTO marker.  */
577 
578 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)579 i386_pe_asm_output_aligned_decl_common (FILE *stream, tree decl,
580 					const char *name, HOST_WIDE_INT size,
581 					HOST_WIDE_INT align ATTRIBUTE_UNUSED)
582 {
583   HOST_WIDE_INT rounded;
584 
585   /* Compute as in assemble_noswitch_variable, since we don't have
586      support for aligned common on older binutils.  We must also
587      avoid emitting a common symbol of size zero, as this is the
588      overloaded representation that indicates an undefined external
589      symbol in the PE object file format.  */
590   rounded = size ? size : 1;
591   rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
592   rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
593 	     * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
594 
595   i386_pe_maybe_record_exported_symbol (decl, name, 1);
596 
597   fprintf (stream, "\t.comm\t");
598   assemble_name (stream, name);
599   if (use_pe_aligned_common)
600     fprintf (stream, ", " HOST_WIDE_INT_PRINT_DEC ", %d\n",
601 	   size ? size : (HOST_WIDE_INT) 1,
602 	   exact_log2 (align) - exact_log2 (CHAR_BIT));
603   else
604     fprintf (stream, ", " HOST_WIDE_INT_PRINT_DEC "\t" ASM_COMMENT_START
605 	   " " HOST_WIDE_INT_PRINT_DEC "\n", rounded, size);
606 }
607 
608 /* The Microsoft linker requires that every function be marked as
609    DT_FCN.  When using gas on cygwin, we must emit appropriate .type
610    directives.  */
611 
612 #include "gsyms.h"
613 
614 /* Mark a function appropriately.  This should only be called for
615    functions for which we are not emitting COFF debugging information.
616    FILE is the assembler output file, NAME is the name of the
617    function, and PUB is nonzero if the function is globally
618    visible.  */
619 
620 void
i386_pe_declare_function_type(FILE * file,const char * name,int pub)621 i386_pe_declare_function_type (FILE *file, const char *name, int pub)
622 {
623   fprintf (file, "\t.def\t");
624   assemble_name (file, name);
625   fprintf (file, ";\t.scl\t%d;\t.type\t%d;\t.endef\n",
626 	   pub ? (int) C_EXT : (int) C_STAT,
627 	   (int) DT_FCN << N_BTSHFT);
628 }
629 
630 /* Keep a list of external functions.  */
631 
632 struct GTY(()) extern_list
633 {
634   struct extern_list *next;
635   tree decl;
636   const char *name;
637 };
638 
639 static GTY(()) struct extern_list *extern_head;
640 
641 /* Assemble an external function reference.  We need to keep a list of
642    these, so that we can output the function types at the end of the
643    assembly.  We can't output the types now, because we might see a
644    definition of the function later on and emit debugging information
645    for it then.  */
646 
647 void
i386_pe_record_external_function(tree decl,const char * name)648 i386_pe_record_external_function (tree decl, const char *name)
649 {
650   struct extern_list *p;
651 
652   p = ggc_alloc_extern_list ();
653   p->next = extern_head;
654   p->decl = decl;
655   p->name = name;
656   extern_head = p;
657 }
658 
659 /* Keep a list of exported symbols.  */
660 
661 struct GTY(()) export_list
662 {
663   struct export_list *next;
664   const char *name;
665   int is_data;		/* used to type tag exported symbols.  */
666 };
667 
668 /* Keep a list of stub symbols.  */
669 
670 struct GTY(()) stub_list
671 {
672   struct stub_list *next;
673   const char *name;
674 };
675 
676 static GTY(()) struct export_list *export_head;
677 
678 static GTY(()) struct stub_list *stub_head;
679 
680 /* Assemble an export symbol entry.  We need to keep a list of
681    these, so that we can output the export list at the end of the
682    assembly.  We used to output these export symbols in each function,
683    but that causes problems with GNU ld when the sections are
684    linkonce.  Beware, DECL may be NULL if compile_file() is emitting
685    the LTO marker.  */
686 
687 void
i386_pe_maybe_record_exported_symbol(tree decl,const char * name,int is_data)688 i386_pe_maybe_record_exported_symbol (tree decl, const char *name, int is_data)
689 {
690   rtx symbol;
691   struct export_list *p;
692 
693   if (!decl)
694     return;
695 
696   symbol = XEXP (DECL_RTL (decl), 0);
697   gcc_assert (GET_CODE (symbol) == SYMBOL_REF);
698   if (!SYMBOL_REF_DLLEXPORT_P (symbol))
699     return;
700 
701   gcc_assert (TREE_PUBLIC (decl));
702 
703   p = ggc_alloc_export_list ();
704   p->next = export_head;
705   p->name = name;
706   p->is_data = is_data;
707   export_head = p;
708 }
709 
710 void
i386_pe_record_stub(const char * name)711 i386_pe_record_stub (const char *name)
712 {
713   struct stub_list *p;
714 
715   if (!name || *name == 0)
716     return;
717 
718   p = stub_head;
719   while (p != NULL)
720     {
721       if (p->name[0] == *name
722           && !strcmp (p->name, name))
723 	return;
724       p = p->next;
725     }
726 
727   p = ggc_alloc_stub_list ();
728   p->next = stub_head;
729   p->name = name;
730   stub_head = p;
731 }
732 
733 
734 #ifdef CXX_WRAP_SPEC_LIST
735 
736 /* Hashtable helpers.  */
737 
738 struct wrapped_symbol_hasher : typed_noop_remove <char>
739 {
740   typedef char value_type;
741   typedef char compare_type;
742   static inline hashval_t hash (const value_type *);
743   static inline bool equal (const value_type *, const compare_type *);
744   static inline void remove (value_type *);
745 };
746 
747 inline hashval_t
hash(const value_type * v)748 wrapped_symbol_hasher::hash (const value_type *v)
749 {
750   return htab_hash_string (v);
751 }
752 
753 /*  Hash table equality helper function.  */
754 
755 inline bool
equal(const value_type * x,const compare_type * y)756 wrapped_symbol_hasher::equal (const value_type *x, const compare_type *y)
757 {
758   return !strcmp (x, y);
759 }
760 
761 /* Search for a function named TARGET in the list of library wrappers
762    we are using, returning a pointer to it if found or NULL if not.
763    This function might be called on quite a few symbols, and we only
764    have the list of names of wrapped functions available to us as a
765    spec string, so first time round we lazily initialise a hash table
766    to make things quicker.  */
767 
768 static const char *
i386_find_on_wrapper_list(const char * target)769 i386_find_on_wrapper_list (const char *target)
770 {
771   static char first_time = 1;
772   static hash_table <wrapped_symbol_hasher> wrappers;
773 
774   if (first_time)
775     {
776       /* Beware that this is not a complicated parser, it assumes
777          that any sequence of non-whitespace beginning with an
778 	 underscore is one of the wrapped symbols.  For now that's
779 	 adequate to distinguish symbols from spec substitutions
780 	 and command-line options.  */
781       static char wrapper_list_buffer[] = CXX_WRAP_SPEC_LIST;
782       char *bufptr;
783       /* Breaks up the char array into separated strings
784          strings and enter them into the hash table.  */
785       wrappers.create (8);
786       for (bufptr = wrapper_list_buffer; *bufptr; ++bufptr)
787 	{
788 	  char *found = NULL;
789 	  if (ISSPACE (*bufptr))
790 	    continue;
791 	  if (*bufptr == '_')
792 	    found = bufptr;
793 	  while (*bufptr && !ISSPACE (*bufptr))
794 	    ++bufptr;
795 	  if (*bufptr)
796 	    *bufptr = 0;
797 	  if (found)
798 	    *wrappers.find_slot (found, INSERT) = found;
799 	}
800       first_time = 0;
801     }
802 
803   return wrappers.find (target);
804 }
805 
806 #endif /* CXX_WRAP_SPEC_LIST */
807 
808 /* This is called at the end of assembly.  For each external function
809    which has not been defined, we output a declaration now.  We also
810    output the .drectve section.  */
811 
812 void
i386_pe_file_end(void)813 i386_pe_file_end (void)
814 {
815   struct extern_list *p;
816 
817   for (p = extern_head; p != NULL; p = p->next)
818     {
819       tree decl;
820 
821       decl = p->decl;
822 
823       /* Positively ensure only one declaration for any given symbol.  */
824       if (! TREE_ASM_WRITTEN (decl)
825 	  && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
826 	{
827 #ifdef CXX_WRAP_SPEC_LIST
828 	  /* To ensure the DLL that provides the corresponding real
829 	     functions is still loaded at runtime, we must reference
830 	     the real function so that an (unused) import is created.  */
831 	  const char *realsym = i386_find_on_wrapper_list (p->name);
832 	  if (realsym)
833 	    i386_pe_declare_function_type (asm_out_file,
834 		concat ("__real_", realsym, NULL), TREE_PUBLIC (decl));
835 #endif /* CXX_WRAP_SPEC_LIST */
836 	  TREE_ASM_WRITTEN (decl) = 1;
837 	  i386_pe_declare_function_type (asm_out_file, p->name,
838 					 TREE_PUBLIC (decl));
839 	}
840     }
841 
842   if (export_head)
843     {
844       struct export_list *q;
845       drectve_section ();
846       for (q = export_head; q != NULL; q = q->next)
847 	{
848 	  fprintf (asm_out_file, "\t.ascii \" -export:\\\"%s\\\"%s\"\n",
849 		   default_strip_name_encoding (q->name),
850 		   (q->is_data ? ",data" : ""));
851 	}
852     }
853 
854   if (stub_head)
855     {
856       struct stub_list *q;
857 
858       for (q = stub_head; q != NULL; q = q->next)
859 	{
860 	  const char *name = q->name;
861 	  const char *oname;
862 
863 	  if (name[0] == '*')
864 	    ++name;
865 	  oname = name;
866 	  if (name[0] == '.')
867 	    ++name;
868 	  if (strncmp (name, "refptr.", 7) != 0)
869 	    continue;
870 	  name += 7;
871 	  fprintf (asm_out_file, "\t.section\t.rdata$%s, \"dr\"\n"
872 	  		   "\t.globl\t%s\n"
873 			   "\t.linkonce\tdiscard\n", oname, oname);
874 	  fprintf (asm_out_file, "%s:\n\t.quad\t%s\n", oname, name);
875 	}
876     }
877 }
878 
879 
880 /* x64 Structured Exception Handling unwind info.  */
881 
882 struct seh_frame_state
883 {
884   /* SEH records saves relative to the "current" stack pointer, whether
885      or not there's a frame pointer in place.  This tracks the current
886      stack pointer offset from the CFA.  */
887   HOST_WIDE_INT sp_offset;
888 
889   /* The CFA is located at CFA_REG + CFA_OFFSET.  */
890   HOST_WIDE_INT cfa_offset;
891   rtx cfa_reg;
892 };
893 
894 /* Set up data structures beginning output for SEH.  */
895 
896 void
i386_pe_seh_init(FILE * f)897 i386_pe_seh_init (FILE *f)
898 {
899   struct seh_frame_state *seh;
900 
901   if (!TARGET_SEH)
902     return;
903   if (cfun->is_thunk)
904     return;
905 
906   /* We cannot support DRAP with SEH.  We turned off support for it by
907      re-defining MAX_STACK_ALIGNMENT when SEH is enabled.  */
908   gcc_assert (!stack_realign_drap);
909 
910   seh = XCNEW (struct seh_frame_state);
911   cfun->machine->seh = seh;
912 
913   seh->sp_offset = INCOMING_FRAME_SP_OFFSET;
914   seh->cfa_offset = INCOMING_FRAME_SP_OFFSET;
915   seh->cfa_reg = stack_pointer_rtx;
916 
917   fputs ("\t.seh_proc\t", f);
918   assemble_name (f, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (cfun->decl)));
919   fputc ('\n', f);
920 }
921 
922 void
i386_pe_seh_end_prologue(FILE * f)923 i386_pe_seh_end_prologue (FILE *f)
924 {
925   struct seh_frame_state *seh;
926 
927   if (!TARGET_SEH)
928     return;
929   if (cfun->is_thunk)
930     return;
931   seh = cfun->machine->seh;
932 
933   XDELETE (seh);
934   cfun->machine->seh = NULL;
935 
936   fputs ("\t.seh_endprologue\n", f);
937 }
938 
939 static void
i386_pe_seh_fini(FILE * f)940 i386_pe_seh_fini (FILE *f)
941 {
942   if (!TARGET_SEH)
943     return;
944   if (cfun->is_thunk)
945     return;
946   fputs ("\t.seh_endproc\n", f);
947 }
948 
949 /* Emit an assembler directive to save REG via a PUSH.  */
950 
951 static void
seh_emit_push(FILE * f,struct seh_frame_state * seh,rtx reg)952 seh_emit_push (FILE *f, struct seh_frame_state *seh, rtx reg)
953 {
954   unsigned int regno = REGNO (reg);
955 
956   gcc_checking_assert (GENERAL_REGNO_P (regno));
957 
958   seh->sp_offset += UNITS_PER_WORD;
959   if (seh->cfa_reg == stack_pointer_rtx)
960     seh->cfa_offset += UNITS_PER_WORD;
961 
962   fputs ("\t.seh_pushreg\t", f);
963   print_reg (reg, 0, f);
964   fputc ('\n', f);
965 }
966 
967 /* Emit an assembler directive to save REG at CFA - CFA_OFFSET.  */
968 
969 static void
seh_emit_save(FILE * f,struct seh_frame_state * seh,rtx reg,HOST_WIDE_INT cfa_offset)970 seh_emit_save (FILE *f, struct seh_frame_state *seh,
971 	       rtx reg, HOST_WIDE_INT cfa_offset)
972 {
973   unsigned int regno = REGNO (reg);
974   HOST_WIDE_INT offset;
975 
976   /* Negative save offsets are of course not supported, since that
977      would be a store below the stack pointer and thus clobberable.  */
978   gcc_assert (seh->sp_offset >= cfa_offset);
979   offset = seh->sp_offset - cfa_offset;
980 
981   fputs ((SSE_REGNO_P (regno) ? "\t.seh_savexmm\t"
982 	 : GENERAL_REGNO_P (regno) ?  "\t.seh_savereg\t"
983 	 : (gcc_unreachable (), "")), f);
984   print_reg (reg, 0, f);
985   fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
986 }
987 
988 /* Emit an assembler directive to adjust RSP by OFFSET.  */
989 
990 static void
seh_emit_stackalloc(FILE * f,struct seh_frame_state * seh,HOST_WIDE_INT offset)991 seh_emit_stackalloc (FILE *f, struct seh_frame_state *seh,
992 		     HOST_WIDE_INT offset)
993 {
994   /* We're only concerned with prologue stack allocations, which all
995      are subtractions from the stack pointer.  */
996   gcc_assert (offset < 0);
997   offset = -offset;
998 
999   if (seh->cfa_reg == stack_pointer_rtx)
1000     seh->cfa_offset += offset;
1001   seh->sp_offset += offset;
1002 
1003   /* Do not output the stackalloc in that case (it won't work as there is no
1004      encoding for very large frame size).  */
1005   if (offset < SEH_MAX_FRAME_SIZE)
1006     fprintf (f, "\t.seh_stackalloc\t" HOST_WIDE_INT_PRINT_DEC "\n", offset);
1007 }
1008 
1009 /* Process REG_CFA_ADJUST_CFA for SEH.  */
1010 
1011 static void
seh_cfa_adjust_cfa(FILE * f,struct seh_frame_state * seh,rtx pat)1012 seh_cfa_adjust_cfa (FILE *f, struct seh_frame_state *seh, rtx pat)
1013 {
1014   rtx dest, src;
1015   HOST_WIDE_INT reg_offset = 0;
1016   unsigned int dest_regno;
1017 
1018   dest = SET_DEST (pat);
1019   src = SET_SRC (pat);
1020 
1021   if (GET_CODE (src) == PLUS)
1022     {
1023       reg_offset = INTVAL (XEXP (src, 1));
1024       src = XEXP (src, 0);
1025     }
1026   else if (GET_CODE (src) == MINUS)
1027     {
1028       reg_offset = -INTVAL (XEXP (src, 1));
1029       src = XEXP (src, 0);
1030     }
1031   gcc_assert (src == stack_pointer_rtx);
1032   gcc_assert (seh->cfa_reg == stack_pointer_rtx);
1033   dest_regno = REGNO (dest);
1034 
1035   if (dest_regno == STACK_POINTER_REGNUM)
1036     seh_emit_stackalloc (f, seh, reg_offset);
1037   else if (dest_regno == HARD_FRAME_POINTER_REGNUM)
1038     {
1039       HOST_WIDE_INT offset;
1040 
1041       seh->cfa_reg = dest;
1042       seh->cfa_offset -= reg_offset;
1043 
1044       offset = seh->sp_offset - seh->cfa_offset;
1045 
1046       gcc_assert ((offset & 15) == 0);
1047       gcc_assert (IN_RANGE (offset, 0, 240));
1048 
1049       fputs ("\t.seh_setframe\t", f);
1050       print_reg (seh->cfa_reg, 0, f);
1051       fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset);
1052     }
1053   else
1054     gcc_unreachable ();
1055 }
1056 
1057 /* Process REG_CFA_OFFSET for SEH.  */
1058 
1059 static void
seh_cfa_offset(FILE * f,struct seh_frame_state * seh,rtx pat)1060 seh_cfa_offset (FILE *f, struct seh_frame_state *seh, rtx pat)
1061 {
1062   rtx dest, src;
1063   HOST_WIDE_INT reg_offset;
1064 
1065   dest = SET_DEST (pat);
1066   src = SET_SRC (pat);
1067 
1068   gcc_assert (MEM_P (dest));
1069   dest = XEXP (dest, 0);
1070   if (REG_P (dest))
1071     reg_offset = 0;
1072   else
1073     {
1074       gcc_assert (GET_CODE (dest) == PLUS);
1075       reg_offset = INTVAL (XEXP (dest, 1));
1076       dest = XEXP (dest, 0);
1077     }
1078   gcc_assert (dest == seh->cfa_reg);
1079 
1080   seh_emit_save (f, seh, src, seh->cfa_offset - reg_offset);
1081 }
1082 
1083 /* Process a FRAME_RELATED_EXPR for SEH.  */
1084 
1085 static void
seh_frame_related_expr(FILE * f,struct seh_frame_state * seh,rtx pat)1086 seh_frame_related_expr (FILE *f, struct seh_frame_state *seh, rtx pat)
1087 {
1088   rtx dest, src;
1089   HOST_WIDE_INT addend;
1090 
1091   /* See the full loop in dwarf2out_frame_debug_expr.  */
1092   if (GET_CODE (pat) == PARALLEL || GET_CODE (pat) == SEQUENCE)
1093     {
1094       int i, n = XVECLEN (pat, 0), pass, npass;
1095 
1096       npass = (GET_CODE (pat) == PARALLEL ? 2 : 1);
1097       for (pass = 0; pass < npass; ++pass)
1098 	for (i = 0; i < n; ++i)
1099 	  {
1100 	    rtx ele = XVECEXP (pat, 0, i);
1101 
1102 	    if (GET_CODE (ele) != SET)
1103 	      continue;
1104 	    dest = SET_DEST (ele);
1105 
1106 	    /* Process each member of the PARALLEL independently.  The first
1107 	       member is always processed; others only if they are marked.  */
1108 	    if (i == 0 || RTX_FRAME_RELATED_P (ele))
1109 	      {
1110 		/* Evaluate all register saves in the first pass and all
1111 		   register updates in the second pass.  */
1112 		if ((MEM_P (dest) ^ pass) || npass == 1)
1113 		  seh_frame_related_expr (f, seh, ele);
1114 	      }
1115 	  }
1116       return;
1117     }
1118 
1119   dest = SET_DEST (pat);
1120   src = SET_SRC (pat);
1121 
1122   switch (GET_CODE (dest))
1123     {
1124     case REG:
1125       switch (GET_CODE (src))
1126 	{
1127 	case REG:
1128 	  /* REG = REG: This should be establishing a frame pointer.  */
1129 	  gcc_assert (src == stack_pointer_rtx);
1130 	  gcc_assert (dest == hard_frame_pointer_rtx);
1131 	  seh_cfa_adjust_cfa (f, seh, pat);
1132 	  break;
1133 
1134 	case PLUS:
1135 	  addend = INTVAL (XEXP (src, 1));
1136 	  src = XEXP (src, 0);
1137 	  if (dest == hard_frame_pointer_rtx)
1138 	    seh_cfa_adjust_cfa (f, seh, pat);
1139 	  else if (dest == stack_pointer_rtx)
1140 	    {
1141 	      gcc_assert (src == stack_pointer_rtx);
1142 	      seh_emit_stackalloc (f, seh, addend);
1143 	    }
1144 	  else
1145 	    gcc_unreachable ();
1146 	  break;
1147 
1148 	default:
1149 	  gcc_unreachable ();
1150 	}
1151       break;
1152 
1153     case MEM:
1154       /* A save of some kind.  */
1155       dest = XEXP (dest, 0);
1156       if (GET_CODE (dest) == PRE_DEC)
1157 	{
1158 	  gcc_checking_assert (GET_MODE (src) == Pmode);
1159 	  gcc_checking_assert (REG_P (src));
1160 	  seh_emit_push (f, seh, src);
1161 	}
1162       else
1163 	seh_cfa_offset (f, seh, pat);
1164       break;
1165 
1166     default:
1167       gcc_unreachable ();
1168     }
1169 }
1170 
1171 /* This function looks at a single insn and emits any SEH directives
1172    required for unwind of this insn.  */
1173 
1174 void
i386_pe_seh_unwind_emit(FILE * asm_out_file,rtx insn)1175 i386_pe_seh_unwind_emit (FILE *asm_out_file, rtx insn)
1176 {
1177   rtx note, pat;
1178   bool handled_one = false;
1179   struct seh_frame_state *seh;
1180 
1181   if (!TARGET_SEH)
1182     return;
1183 
1184   /* We free the SEH data once done with the prologue.  Ignore those
1185      RTX_FRAME_RELATED_P insns that are associated with the epilogue.  */
1186   seh = cfun->machine->seh;
1187   if (seh == NULL)
1188     return;
1189 
1190   if (NOTE_P (insn) || !RTX_FRAME_RELATED_P (insn))
1191     return;
1192 
1193   for (note = REG_NOTES (insn); note ; note = XEXP (note, 1))
1194     {
1195       switch (REG_NOTE_KIND (note))
1196 	{
1197 	case REG_FRAME_RELATED_EXPR:
1198 	  pat = XEXP (note, 0);
1199 	  goto found;
1200 
1201 	case REG_CFA_DEF_CFA:
1202 	case REG_CFA_EXPRESSION:
1203 	  /* Only emitted with DRAP, which we disable.  */
1204 	  gcc_unreachable ();
1205 	  break;
1206 
1207 	case REG_CFA_REGISTER:
1208 	  /* Only emitted in epilogues, which we skip.  */
1209 	  gcc_unreachable ();
1210 
1211 	case REG_CFA_ADJUST_CFA:
1212 	  pat = XEXP (note, 0);
1213 	  if (pat == NULL)
1214 	    {
1215 	      pat = PATTERN (insn);
1216 	      if (GET_CODE (pat) == PARALLEL)
1217 		pat = XVECEXP (pat, 0, 0);
1218 	    }
1219 	  seh_cfa_adjust_cfa (asm_out_file, seh, pat);
1220 	  handled_one = true;
1221 	  break;
1222 
1223 	case REG_CFA_OFFSET:
1224 	  pat = XEXP (note, 0);
1225 	  if (pat == NULL)
1226 	    pat = single_set (insn);
1227 	  seh_cfa_offset (asm_out_file, seh, pat);
1228 	  handled_one = true;
1229 	  break;
1230 
1231 	default:
1232 	  break;
1233 	}
1234     }
1235   if (handled_one)
1236     return;
1237   pat = PATTERN (insn);
1238  found:
1239   seh_frame_related_expr (asm_out_file, seh, pat);
1240 }
1241 
1242 void
i386_pe_seh_emit_except_personality(rtx personality)1243 i386_pe_seh_emit_except_personality (rtx personality)
1244 {
1245   int flags = 0;
1246 
1247   if (!TARGET_SEH)
1248     return;
1249 
1250   fputs ("\t.seh_handler\t", asm_out_file);
1251   output_addr_const (asm_out_file, personality);
1252 
1253 #if 0
1254   /* ??? The current implementation of _GCC_specific_handler requires
1255      both except and unwind handling, regardless of which sorts the
1256      user-level function requires.  */
1257   eh_region r;
1258   FOR_ALL_EH_REGION(r)
1259     {
1260       if (r->type == ERT_CLEANUP)
1261 	flags |= 1;
1262       else
1263 	flags |= 2;
1264     }
1265 #else
1266   flags = 3;
1267 #endif
1268 
1269   if (flags & 1)
1270     fputs (", @unwind", asm_out_file);
1271   if (flags & 2)
1272     fputs (", @except", asm_out_file);
1273   fputc ('\n', asm_out_file);
1274 }
1275 
1276 void
i386_pe_seh_init_sections(void)1277 i386_pe_seh_init_sections (void)
1278 {
1279   if (TARGET_SEH)
1280     exception_section = get_unnamed_section (0, output_section_asm_op,
1281 					     "\t.seh_handlerdata");
1282 }
1283 
1284 void
i386_pe_start_function(FILE * f,const char * name,tree decl)1285 i386_pe_start_function (FILE *f, const char *name, tree decl)
1286 {
1287   i386_pe_maybe_record_exported_symbol (decl, name, 0);
1288   if (write_symbols != SDB_DEBUG)
1289     i386_pe_declare_function_type (f, name, TREE_PUBLIC (decl));
1290   /* In case section was altered by debugging output.  */
1291   if (decl != NULL_TREE)
1292     switch_to_section (function_section (decl));
1293   ASM_OUTPUT_FUNCTION_LABEL (f, name, decl);
1294 }
1295 
1296 void
i386_pe_end_function(FILE * f,const char * name ATTRIBUTE_UNUSED,tree decl ATTRIBUTE_UNUSED)1297 i386_pe_end_function (FILE *f, const char *name ATTRIBUTE_UNUSED,
1298 		      tree decl ATTRIBUTE_UNUSED)
1299 {
1300   i386_pe_seh_fini (f);
1301 }
1302 
1303 
1304 #include "gt-winnt.h"
1305