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