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