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