]>
Commit | Line | Data |
---|---|---|
30c71308 RK |
1 | /* Subroutines for insn-output.c for Windows NT. |
2 | Contributed by Douglas Rupp (drupp@cs.washington.edu) | |
c675621f | 3 | Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc. |
30c71308 RK |
4 | |
5 | This file is part of GNU CC. | |
6 | ||
7 | GNU CC is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GNU CC is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GNU CC; see the file COPYING. If not, write to | |
97aadbb9 RK |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, |
20 | Boston, MA 02111-1307, USA. */ | |
30c71308 | 21 | |
30c71308 | 22 | #include "config.h" |
293bcdc9 | 23 | #include "system.h" |
30c71308 RK |
24 | #include "rtl.h" |
25 | #include "regs.h" | |
26 | #include "hard-reg-set.h" | |
27 | #include "output.h" | |
28 | #include "tree.h" | |
29 | #include "flags.h" | |
79f96374 DB |
30 | #include "tm_p.h" |
31 | #include "toplev.h" | |
7c262518 | 32 | #include "hashtab.h" |
30c71308 | 33 | |
27da1b4d MK |
34 | /* i386/PE specific attribute support. |
35 | ||
36 | i386/PE has two new attributes: | |
37 | dllexport - for exporting a function/variable that will live in a dll | |
38 | dllimport - for importing a function/variable from a dll | |
39 | ||
40 | Microsoft allows multiple declspecs in one __declspec, separating | |
41 | them with spaces. We do NOT support this. Instead, use __declspec | |
42 | multiple times. | |
43 | */ | |
44 | ||
79f96374 DB |
45 | static tree associated_type PARAMS ((tree)); |
46 | const char * gen_stdcall_suffix PARAMS ((tree)); | |
47 | int i386_pe_dllexport_p PARAMS ((tree)); | |
48 | int i386_pe_dllimport_p PARAMS ((tree)); | |
49 | void i386_pe_mark_dllexport PARAMS ((tree)); | |
50 | void i386_pe_mark_dllimport PARAMS ((tree)); | |
51 | ||
27da1b4d MK |
52 | /* Return nonzero if ATTR is a valid attribute for DECL. |
53 | ATTRIBUTES are any existing attributes and ARGS are the arguments | |
54 | supplied with ATTR. */ | |
55 | ||
56 | int | |
57 | i386_pe_valid_decl_attribute_p (decl, attributes, attr, args) | |
58 | tree decl; | |
7c262518 | 59 | tree attributes ATTRIBUTE_UNUSED; |
27da1b4d MK |
60 | tree attr; |
61 | tree args; | |
62 | { | |
ac478ac0 JM |
63 | if (args == NULL_TREE) |
64 | { | |
65 | if (is_attribute_p ("dllexport", attr)) | |
66 | return 1; | |
67 | if (is_attribute_p ("dllimport", attr)) | |
68 | return 1; | |
593d3a34 MK |
69 | if (is_attribute_p ("shared", attr)) |
70 | return TREE_CODE (decl) == VAR_DECL; | |
ac478ac0 | 71 | } |
27da1b4d | 72 | |
f5f4be42 | 73 | return 0; |
27da1b4d MK |
74 | } |
75 | ||
ac478ac0 JM |
76 | /* Return nonzero if ATTR is a valid attribute for TYPE. |
77 | ATTRIBUTES are any existing attributes and ARGS are the arguments | |
78 | supplied with ATTR. */ | |
79 | ||
80 | int | |
81 | i386_pe_valid_type_attribute_p (type, attributes, attr, args) | |
82 | tree type; | |
83 | tree attributes; | |
84 | tree attr; | |
85 | tree args; | |
86 | { | |
87 | if (args == NULL_TREE | |
88 | && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE)) | |
89 | { | |
90 | if (is_attribute_p ("dllexport", attr)) | |
91 | return 1; | |
92 | if (is_attribute_p ("dllimport", attr)) | |
93 | return 1; | |
94 | } | |
95 | ||
e075ae69 | 96 | return ix86_valid_type_attribute_p (type, attributes, attr, args); |
ac478ac0 | 97 | } |
27da1b4d | 98 | \f |
ac478ac0 JM |
99 | /* Return the type that we should use to determine if DECL is |
100 | imported or exported. */ | |
27da1b4d | 101 | |
ac478ac0 JM |
102 | static tree |
103 | associated_type (decl) | |
104 | tree decl; | |
27da1b4d | 105 | { |
ac478ac0 | 106 | tree t = NULL_TREE; |
27da1b4d | 107 | |
ac478ac0 JM |
108 | /* In the C++ frontend, DECL_CONTEXT for a method doesn't actually refer |
109 | to the containing class. So we look at the 'this' arg. */ | |
110 | if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) | |
27da1b4d | 111 | { |
ac478ac0 JM |
112 | /* Artificial methods are not affected by the import/export status of |
113 | their class unless they are virtual. */ | |
114 | if (! DECL_ARTIFICIAL (decl) || DECL_VINDEX (decl)) | |
115 | t = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))); | |
27da1b4d | 116 | } |
ac478ac0 JM |
117 | else if (DECL_CONTEXT (decl) |
118 | && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't') | |
119 | t = DECL_CONTEXT (decl); | |
27da1b4d | 120 | |
ac478ac0 | 121 | return t; |
27da1b4d MK |
122 | } |
123 | ||
124 | /* Return non-zero if DECL is a dllexport'd object. */ | |
125 | ||
27da1b4d MK |
126 | int |
127 | i386_pe_dllexport_p (decl) | |
128 | tree decl; | |
129 | { | |
130 | tree exp; | |
131 | ||
132 | if (TREE_CODE (decl) != VAR_DECL | |
133 | && TREE_CODE (decl) != FUNCTION_DECL) | |
134 | return 0; | |
135 | exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl)); | |
136 | if (exp) | |
137 | return 1; | |
138 | ||
ac478ac0 JM |
139 | /* Class members get the dllexport status of their class. */ |
140 | if (associated_type (decl)) | |
27da1b4d | 141 | { |
ac478ac0 JM |
142 | exp = lookup_attribute ("dllexport", |
143 | TYPE_ATTRIBUTES (associated_type (decl))); | |
144 | if (exp) | |
27da1b4d MK |
145 | return 1; |
146 | } | |
27da1b4d MK |
147 | |
148 | return 0; | |
149 | } | |
150 | ||
151 | /* Return non-zero if DECL is a dllimport'd object. */ | |
152 | ||
153 | int | |
154 | i386_pe_dllimport_p (decl) | |
155 | tree decl; | |
156 | { | |
157 | tree imp; | |
158 | ||
159 | if (TREE_CODE (decl) == FUNCTION_DECL | |
160 | && TARGET_NOP_FUN_DLLIMPORT) | |
161 | return 0; | |
162 | ||
163 | if (TREE_CODE (decl) != VAR_DECL | |
164 | && TREE_CODE (decl) != FUNCTION_DECL) | |
165 | return 0; | |
166 | imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl)); | |
167 | if (imp) | |
168 | return 1; | |
169 | ||
ac478ac0 JM |
170 | /* Class members get the dllimport status of their class. */ |
171 | if (associated_type (decl)) | |
27da1b4d | 172 | { |
ac478ac0 JM |
173 | imp = lookup_attribute ("dllimport", |
174 | TYPE_ATTRIBUTES (associated_type (decl))); | |
175 | if (imp) | |
27da1b4d MK |
176 | return 1; |
177 | } | |
27da1b4d MK |
178 | |
179 | return 0; | |
180 | } | |
181 | ||
182 | /* Return non-zero if SYMBOL is marked as being dllexport'd. */ | |
183 | ||
184 | int | |
185 | i386_pe_dllexport_name_p (symbol) | |
79f96374 | 186 | const char *symbol; |
27da1b4d MK |
187 | { |
188 | return symbol[0] == '@' && symbol[1] == 'e' && symbol[2] == '.'; | |
189 | } | |
190 | ||
191 | /* Return non-zero if SYMBOL is marked as being dllimport'd. */ | |
192 | ||
193 | int | |
194 | i386_pe_dllimport_name_p (symbol) | |
79f96374 | 195 | const char *symbol; |
27da1b4d MK |
196 | { |
197 | return symbol[0] == '@' && symbol[1] == 'i' && symbol[2] == '.'; | |
198 | } | |
199 | ||
200 | /* Mark a DECL as being dllexport'd. | |
201 | Note that we override the previous setting (eg: dllimport). */ | |
202 | ||
203 | void | |
204 | i386_pe_mark_dllexport (decl) | |
205 | tree decl; | |
206 | { | |
79f96374 DB |
207 | const char *oldname; |
208 | char *newname; | |
27da1b4d MK |
209 | rtx rtlname; |
210 | tree idp; | |
211 | ||
212 | rtlname = XEXP (DECL_RTL (decl), 0); | |
213 | if (GET_CODE (rtlname) == SYMBOL_REF) | |
214 | oldname = XSTR (rtlname, 0); | |
215 | else if (GET_CODE (rtlname) == MEM | |
216 | && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF) | |
217 | oldname = XSTR (XEXP (rtlname, 0), 0); | |
218 | else | |
219 | abort (); | |
220 | if (i386_pe_dllimport_name_p (oldname)) | |
221 | oldname += 9; | |
222 | else if (i386_pe_dllexport_name_p (oldname)) | |
223 | return; /* already done */ | |
224 | ||
225 | newname = alloca (strlen (oldname) + 4); | |
226 | sprintf (newname, "@e.%s", oldname); | |
227 | ||
228 | /* We pass newname through get_identifier to ensure it has a unique | |
229 | address. RTL processing can sometimes peek inside the symbol ref | |
230 | and compare the string's addresses to see if two symbols are | |
231 | identical. */ | |
232 | idp = get_identifier (newname); | |
233 | ||
234 | XEXP (DECL_RTL (decl), 0) = | |
235 | gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp)); | |
236 | } | |
237 | ||
238 | /* Mark a DECL as being dllimport'd. */ | |
239 | ||
240 | void | |
241 | i386_pe_mark_dllimport (decl) | |
242 | tree decl; | |
243 | { | |
79f96374 DB |
244 | const char *oldname; |
245 | char *newname; | |
27da1b4d MK |
246 | tree idp; |
247 | rtx rtlname, newrtl; | |
248 | ||
249 | rtlname = XEXP (DECL_RTL (decl), 0); | |
250 | if (GET_CODE (rtlname) == SYMBOL_REF) | |
251 | oldname = XSTR (rtlname, 0); | |
252 | else if (GET_CODE (rtlname) == MEM | |
253 | && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF) | |
254 | oldname = XSTR (XEXP (rtlname, 0), 0); | |
255 | else | |
256 | abort (); | |
257 | if (i386_pe_dllexport_name_p (oldname)) | |
258 | { | |
259 | error ("`%s' declared as both exported to and imported from a DLL.", | |
260 | IDENTIFIER_POINTER (DECL_NAME (decl))); | |
261 | return; | |
262 | } | |
263 | else if (i386_pe_dllimport_name_p (oldname)) | |
264 | { | |
265 | /* Already done, but force correct linkage since the redeclaration | |
266 | might have omitted explicit extern. Sigh. */ | |
267 | if (TREE_CODE (decl) == VAR_DECL | |
268 | /* ??? Is this test for vtables needed? */ | |
269 | && !DECL_VIRTUAL_P (decl)) | |
270 | { | |
271 | DECL_EXTERNAL (decl) = 1; | |
272 | TREE_PUBLIC (decl) = 1; | |
273 | } | |
274 | return; | |
275 | } | |
276 | ||
277 | /* ??? One can well ask why we're making these checks here, | |
278 | and that would be a good question. */ | |
279 | ||
280 | /* Imported variables can't be initialized. Note that C++ classes | |
281 | are marked initial, so we need to check. */ | |
282 | if (TREE_CODE (decl) == VAR_DECL | |
283 | && !DECL_VIRTUAL_P (decl) | |
284 | && (DECL_INITIAL (decl) | |
285 | && ! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))) | |
286 | { | |
287 | error_with_decl (decl, "initialized variable `%s' is marked dllimport"); | |
288 | return; | |
289 | } | |
290 | /* Nor can they be static. */ | |
291 | if (TREE_CODE (decl) == VAR_DECL | |
292 | /* ??? Is this test for vtables needed? */ | |
293 | && !DECL_VIRTUAL_P (decl) | |
294 | && 0 /*???*/) | |
295 | { | |
296 | error_with_decl (decl, "static variable `%s' is marked dllimport"); | |
297 | return; | |
298 | } | |
299 | ||
300 | /* `extern' needn't be specified with dllimport. | |
301 | Specify `extern' now and hope for the best. Sigh. */ | |
302 | if (TREE_CODE (decl) == VAR_DECL | |
303 | /* ??? Is this test for vtables needed? */ | |
304 | && !DECL_VIRTUAL_P (decl)) | |
305 | { | |
306 | DECL_EXTERNAL (decl) = 1; | |
307 | TREE_PUBLIC (decl) = 1; | |
308 | } | |
309 | ||
310 | newname = alloca (strlen (oldname) + 11); | |
311 | sprintf (newname, "@i._imp__%s", oldname); | |
312 | ||
313 | /* We pass newname through get_identifier to ensure it has a unique | |
314 | address. RTL processing can sometimes peek inside the symbol ref | |
315 | and compare the string's addresses to see if two symbols are | |
316 | identical. */ | |
317 | idp = get_identifier (newname); | |
318 | ||
319 | newrtl = gen_rtx (MEM, Pmode, | |
320 | gen_rtx (SYMBOL_REF, Pmode, | |
321 | IDENTIFIER_POINTER (idp))); | |
322 | XEXP (DECL_RTL (decl), 0) = newrtl; | |
323 | ||
324 | /* Can't treat a pointer to this as a constant address */ | |
325 | DECL_NON_ADDR_CONST_P (decl) = 1; | |
326 | } | |
327 | ||
0ea6b275 RK |
328 | /* Return string which is the former assembler name modified with a |
329 | suffix consisting of an atsign (@) followed by the number of bytes of | |
330 | arguments */ | |
30c71308 | 331 | |
79f96374 | 332 | const char * |
0ea6b275 RK |
333 | gen_stdcall_suffix (decl) |
334 | tree decl; | |
30c71308 | 335 | { |
0ea6b275 | 336 | int total = 0; |
92d4501f JW |
337 | /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead |
338 | of DECL_ASSEMBLER_NAME. */ | |
79f96374 | 339 | const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); |
0ea6b275 | 340 | char *newsym; |
30c71308 | 341 | |
0ea6b275 RK |
342 | if (TYPE_ARG_TYPES (TREE_TYPE (decl))) |
343 | if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl)))) | |
344 | == void_type_node) | |
30c71308 | 345 | { |
3d5c883b | 346 | tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl)); |
30c71308 | 347 | |
3d5c883b SC |
348 | while (TREE_VALUE (formal_type) != void_type_node) |
349 | { | |
350 | int parm_size | |
351 | = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type))); | |
352 | /* Must round up to include padding. This is done the same | |
353 | way as in store_one_arg. */ | |
354 | parm_size = ((parm_size + PARM_BOUNDARY - 1) | |
355 | / PARM_BOUNDARY * PARM_BOUNDARY); | |
356 | total += parm_size; | |
357 | formal_type = TREE_CHAIN (formal_type); | |
358 | } | |
0ea6b275 | 359 | } |
30c71308 | 360 | |
0ea6b275 RK |
361 | newsym = xmalloc (strlen (asmname) + 10); |
362 | sprintf (newsym, "%s@%d", asmname, total/BITS_PER_UNIT); | |
363 | return IDENTIFIER_POINTER (get_identifier (newsym)); | |
30c71308 | 364 | } |
0ea6b275 | 365 | |
27da1b4d MK |
366 | /* Cover function to implement ENCODE_SECTION_INFO. */ |
367 | ||
368 | void | |
369 | i386_pe_encode_section_info (decl) | |
370 | tree decl; | |
371 | { | |
372 | /* This bit is copied from i386.h. */ | |
373 | if (optimize > 0 && TREE_CONSTANT (decl) | |
374 | && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST)) | |
375 | { | |
376 | rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' | |
377 | ? TREE_CST_RTL (decl) : DECL_RTL (decl)); | |
378 | SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; | |
379 | } | |
380 | ||
381 | if (TREE_CODE (decl) == FUNCTION_DECL) | |
382 | if (lookup_attribute ("stdcall", | |
383 | TYPE_ATTRIBUTES (TREE_TYPE (decl)))) | |
384 | XEXP (DECL_RTL (decl), 0) = | |
385 | gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl)); | |
386 | ||
387 | /* Mark the decl so we can tell from the rtl whether the object is | |
388 | dllexport'd or dllimport'd. */ | |
389 | ||
390 | if (i386_pe_dllexport_p (decl)) | |
391 | i386_pe_mark_dllexport (decl); | |
392 | else if (i386_pe_dllimport_p (decl)) | |
393 | i386_pe_mark_dllimport (decl); | |
394 | /* It might be that DECL has already been marked as dllimport, but a | |
395 | subsequent definition nullified that. The attribute is gone but | |
396 | DECL_RTL still has @i._imp__foo. We need to remove that. Ditto | |
397 | for the DECL_NON_ADDR_CONST_P flag. */ | |
398 | else if ((TREE_CODE (decl) == FUNCTION_DECL | |
399 | || TREE_CODE (decl) == VAR_DECL) | |
400 | && DECL_RTL (decl) != NULL_RTX | |
401 | && GET_CODE (DECL_RTL (decl)) == MEM | |
402 | && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM | |
403 | && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF | |
404 | && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0))) | |
405 | { | |
79f96374 | 406 | const char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0); |
27da1b4d MK |
407 | tree idp = get_identifier (oldname + 9); |
408 | rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp)); | |
409 | ||
410 | XEXP (DECL_RTL (decl), 0) = newrtl; | |
411 | ||
412 | DECL_NON_ADDR_CONST_P (decl) = 0; | |
413 | ||
414 | /* We previously set TREE_PUBLIC and DECL_EXTERNAL. | |
415 | We leave these alone for now. */ | |
416 | } | |
417 | } | |
418 | ||
b64deb96 JM |
419 | /* Cover function for UNIQUE_SECTION. */ |
420 | ||
516dd80f | 421 | void |
ad4ff310 | 422 | i386_pe_unique_section (decl, reloc) |
b64deb96 | 423 | tree decl; |
ad4ff310 | 424 | int reloc; |
b64deb96 JM |
425 | { |
426 | int len; | |
79f96374 DB |
427 | const char *name, *prefix; |
428 | char *string; | |
b64deb96 JM |
429 | |
430 | name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); | |
27da1b4d MK |
431 | /* Strip off any encoding in fnname. */ |
432 | STRIP_NAME_ENCODING (name, name); | |
b64deb96 JM |
433 | |
434 | /* The object is put in, for example, section .text$foo. | |
435 | The linker will then ultimately place them in .text | |
81023100 MK |
436 | (everything from the $ on is stripped). Don't put |
437 | read-only data in .rdata section to avoid a PE linker | |
438 | bug when .rdata$* grouped sections are used in code | |
439 | without a .rdata section. */ | |
b64deb96 JM |
440 | if (TREE_CODE (decl) == FUNCTION_DECL) |
441 | prefix = ".text$"; | |
e8c3586a | 442 | /* else if (DECL_INITIAL (decl) == 0 |
a56e7c08 | 443 | || DECL_INITIAL (decl) == error_mark_node) |
e8c3586a | 444 | prefix = ".bss"; */ |
ad4ff310 | 445 | else if (DECL_READONLY_SECTION (decl, reloc)) |
81023100 | 446 | #ifdef READONLY_DATA_SECTION |
b64deb96 | 447 | prefix = ".rdata$"; |
81023100 MK |
448 | #else |
449 | prefix = ".text$"; | |
450 | #endif | |
b64deb96 JM |
451 | else |
452 | prefix = ".data$"; | |
453 | len = strlen (name) + strlen (prefix); | |
454 | string = alloca (len + 1); | |
455 | sprintf (string, "%s%s", prefix, name); | |
456 | ||
516dd80f | 457 | DECL_SECTION_NAME (decl) = build_string (len, string); |
b64deb96 | 458 | } |
7c262518 RH |
459 | |
460 | /* Select a set of attributes for section NAME based on the properties | |
461 | of DECL and whether or not RELOC indicates that DECL's initializer | |
462 | might contain runtime relocations. | |
463 | ||
464 | We make the section read-only and executable for a function decl, | |
465 | read-only for a const data decl, and writable for a non-const data decl. | |
466 | ||
467 | If the section has already been defined, to not allow it to have | |
468 | different attributes, as (1) this is ambiguous since we're not seeing | |
469 | all the declarations up front and (2) some assemblers (e.g. SVR4) | |
470 | do not recoginize section redefinitions. */ | |
471 | /* ??? This differs from the "standard" PE implementation in that we | |
472 | handle the SHARED variable attribute. Should this be done for all | |
473 | PE targets? */ | |
474 | ||
475 | #define SECTION_PE_SHARED SECTION_MACH_DEP | |
476 | ||
477 | unsigned int | |
478 | i386_pe_section_type_flags (decl, name, reloc) | |
479 | tree decl; | |
480 | const char *name; | |
481 | int reloc; | |
482 | { | |
483 | static htab_t htab; | |
484 | unsigned int flags; | |
485 | unsigned int **slot; | |
486 | ||
487 | /* The names we put in the hashtable will always be the unique | |
488 | versions gived to us by the stringtable, so we can just use | |
489 | their addresses as the keys. */ | |
490 | if (!htab) | |
491 | htab = htab_create (31, htab_hash_pointer, htab_eq_pointer, NULL); | |
492 | ||
493 | if (decl && TREE_CODE (decl) == FUNCTION_DECL) | |
494 | flags = SECTION_CODE; | |
495 | else if (decl && DECL_READONLY_SECTION (decl, reloc)) | |
496 | flags = 0; | |
497 | else | |
498 | { | |
499 | flags = SECTION_WRITE; | |
500 | ||
501 | if (decl && TREE_CODE (decl) == VAR_DECL | |
502 | && lookup_attribute ("shared", DECL_MACHINE_ATTRIBUTES (decl))) | |
503 | flags |= SECTION_PE_SHARED; | |
504 | } | |
505 | ||
506 | if (decl && DECL_ONE_ONLY (decl)) | |
507 | flags |= SECTION_LINKONCE; | |
508 | ||
509 | /* See if we already have an entry for this section. */ | |
510 | slot = (unsigned int **) htab_find_slot (htab, name, INSERT); | |
511 | if (!*slot) | |
512 | { | |
513 | *slot = (unsigned int *) xmalloc (sizeof (unsigned int)); | |
514 | **slot = flags; | |
515 | } | |
516 | else | |
517 | { | |
518 | if (decl && **slot != flags) | |
519 | error_with_decl (decl, "%s causes a section type conflict"); | |
520 | } | |
521 | ||
522 | return flags; | |
523 | } | |
524 | ||
525 | void | |
715bdd29 | 526 | i386_pe_asm_named_section (name, flags) |
7c262518 RH |
527 | const char *name; |
528 | unsigned int flags; | |
7c262518 RH |
529 | { |
530 | char flagchars[8], *f = flagchars; | |
531 | ||
532 | if (flags & SECTION_CODE) | |
533 | *f++ = 'x'; | |
534 | if (flags & SECTION_WRITE) | |
535 | *f++ = 'w'; | |
536 | if (flags & SECTION_PE_SHARED) | |
537 | *f++ = 's'; | |
538 | *f = '\0'; | |
539 | ||
540 | fprintf (asm_out_file, "\t.section\t%s,\"%s\"\n", name, flagchars); | |
541 | ||
542 | if (flags & SECTION_LINKONCE) | |
543 | { | |
544 | /* Functions may have been compiled at various levels of | |
545 | optimization so we can't use `same_size' here. | |
546 | Instead, have the linker pick one. */ | |
547 | fprintf (asm_out_file, "\t.linkonce %s\n", | |
548 | (flags & SECTION_CODE ? "discard" : "same_size")); | |
549 | } | |
550 | } | |
9fa1246d JL |
551 | \f |
552 | /* The Microsoft linker requires that every function be marked as | |
cae21ae8 | 553 | DT_FCN. When using gas on cygwin, we must emit appropriate .type |
9fa1246d JL |
554 | directives. */ |
555 | ||
556 | #include "gsyms.h" | |
557 | ||
558 | /* Mark a function appropriately. This should only be called for | |
559 | functions for which we are not emitting COFF debugging information. | |
560 | FILE is the assembler output file, NAME is the name of the | |
561 | function, and PUBLIC is non-zero if the function is globally | |
562 | visible. */ | |
563 | ||
564 | void | |
565 | i386_pe_declare_function_type (file, name, public) | |
566 | FILE *file; | |
79f96374 | 567 | const char *name; |
9fa1246d JL |
568 | int public; |
569 | { | |
570 | fprintf (file, "\t.def\t"); | |
571 | assemble_name (file, name); | |
572 | fprintf (file, ";\t.scl\t%d;\t.type\t%d;\t.endef\n", | |
573 | public ? (int) C_EXT : (int) C_STAT, | |
574 | (int) DT_FCN << N_BTSHFT); | |
575 | } | |
576 | ||
577 | /* Keep a list of external functions. */ | |
578 | ||
579 | struct extern_list | |
580 | { | |
581 | struct extern_list *next; | |
79f96374 | 582 | const char *name; |
9fa1246d JL |
583 | }; |
584 | ||
585 | static struct extern_list *extern_head; | |
586 | ||
587 | /* Assemble an external function reference. We need to keep a list of | |
588 | these, so that we can output the function types at the end of the | |
589 | assembly. We can't output the types now, because we might see a | |
590 | definition of the function later on and emit debugging information | |
591 | for it then. */ | |
592 | ||
593 | void | |
594 | i386_pe_record_external_function (name) | |
79f96374 | 595 | const char *name; |
9fa1246d JL |
596 | { |
597 | struct extern_list *p; | |
598 | ||
599 | p = (struct extern_list *) permalloc (sizeof *p); | |
600 | p->next = extern_head; | |
601 | p->name = name; | |
602 | extern_head = p; | |
603 | } | |
604 | ||
8e260ba4 MK |
605 | /* Keep a list of exported symbols. */ |
606 | ||
607 | struct export_list | |
608 | { | |
609 | struct export_list *next; | |
79f96374 | 610 | const char *name; |
8e260ba4 MK |
611 | int is_data; /* used to type tag exported symbols. */ |
612 | }; | |
613 | ||
614 | static struct export_list *export_head; | |
e43f9c10 MK |
615 | |
616 | /* Assemble an export symbol entry. We need to keep a list of | |
617 | these, so that we can output the export list at the end of the | |
618 | assembly. We used to output these export symbols in each function, | |
619 | but that causes problems with GNU ld when the sections are | |
620 | linkonce. */ | |
621 | ||
622 | void | |
8e260ba4 | 623 | i386_pe_record_exported_symbol (name, is_data) |
79f96374 | 624 | const char *name; |
8e260ba4 | 625 | int is_data; |
e43f9c10 | 626 | { |
8e260ba4 | 627 | struct export_list *p; |
e43f9c10 | 628 | |
8e260ba4 MK |
629 | p = (struct export_list *) permalloc (sizeof *p); |
630 | p->next = export_head; | |
e43f9c10 | 631 | p->name = name; |
8e260ba4 MK |
632 | p->is_data = is_data; |
633 | export_head = p; | |
e43f9c10 MK |
634 | } |
635 | ||
9fa1246d | 636 | /* This is called at the end of assembly. For each external function |
e43f9c10 MK |
637 | which has not been defined, we output a declaration now. We also |
638 | output the .drectve section. */ | |
9fa1246d JL |
639 | |
640 | void | |
641 | i386_pe_asm_file_end (file) | |
642 | FILE *file; | |
643 | { | |
644 | struct extern_list *p; | |
645 | ||
4cf12e7e RH |
646 | ix86_asm_file_end (file); |
647 | ||
9fa1246d JL |
648 | for (p = extern_head; p != NULL; p = p->next) |
649 | { | |
650 | tree decl; | |
651 | ||
652 | decl = get_identifier (p->name); | |
653 | ||
654 | /* Positively ensure only one declaration for any given symbol. */ | |
6ece2487 | 655 | if (! TREE_ASM_WRITTEN (decl) && TREE_SYMBOL_REFERENCED (decl)) |
9fa1246d JL |
656 | { |
657 | TREE_ASM_WRITTEN (decl) = 1; | |
658 | i386_pe_declare_function_type (file, p->name, TREE_PUBLIC (decl)); | |
659 | } | |
660 | } | |
e43f9c10 | 661 | |
8e260ba4 | 662 | if (export_head) |
e43f9c10 | 663 | { |
8e260ba4 MK |
664 | struct export_list *q; |
665 | drectve_section (); | |
666 | for (q = export_head; q != NULL; q = q->next) | |
667 | { | |
668 | fprintf (file, "\t.ascii \" -export:%s%s\"\n", | |
669 | I386_PE_STRIP_ENCODING (q->name), | |
670 | (q->is_data) ? ",data" : ""); | |
671 | } | |
e43f9c10 | 672 | } |
9fa1246d | 673 | } |
e43f9c10 | 674 |