Add support for arm-pe and thumb-pe
[official-gcc.git] / gcc / config / arm / pe.c
blob60d6c4b104535317d782ec665fdfd3fe0f298443
1 /* Routines for GCC for ARM/pe.
2 Copyright (C) 1995, 1996 Free Software Foundation, Inc.
3 Contributed by Doug Evans (dje@cygnus.com).
5 This file is part of GNU CC.
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.
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.
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
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 #include <stdio.h>
23 #include <string.h>
24 #include "config.h"
25 #include "rtl.h"
26 #include "output.h"
27 #include "flags.h"
28 #include "tree.h"
29 #include "expr.h"
31 extern int current_function_anonymous_args;
33 /* ARM/PE specific attribute support.
35 ARM/PE has three new attributes:
36 naked - for interrupt functions
37 dllexport - for exporting a function/variable that will live in a dll
38 dllimport - for importing a function/variable from a dll
40 Microsoft allows multiple declspecs in one __declspec, separating
41 them with spaces. We do NOT support this. Instead, use __declspec
42 multiple times.
45 /* Return nonzero if ATTR is a valid attribute for DECL.
46 ATTRIBUTES are any existing attributes and ARGS are the arguments
47 supplied with ATTR. */
49 int
50 arm_pe_valid_machine_decl_attribute (decl, attributes, attr, args)
51 tree decl;
52 tree attributes;
53 tree attr;
54 tree args;
56 if (args != NULL_TREE)
57 return 0;
59 if (is_attribute_p ("dllexport", attr))
60 return 1;
61 if (is_attribute_p ("dllimport", attr))
62 return 1;
64 return arm_valid_machine_decl_attribute (decl, attr, args);
67 /* Merge attributes in decls OLD and NEW.
69 This handles the following situation:
71 __declspec (dllimport) int foo;
72 int foo;
74 The second instance of `foo' nullifies the dllimport. */
76 tree
77 arm_pe_merge_machine_decl_attributes (old, new)
78 tree old, new;
80 tree a;
81 int delete_dllimport_p;
83 old = DECL_MACHINE_ATTRIBUTES (old);
84 new = DECL_MACHINE_ATTRIBUTES (new);
86 /* What we need to do here is remove from `old' dllimport if it doesn't
87 appear in `new'. dllimport behaves like extern: if a declaration is
88 marked dllimport and a definition appears later, then the object
89 is not dllimport'd. */
91 if (lookup_attribute ("dllimport", old) != NULL_TREE
92 && lookup_attribute ("dllimport", new) == NULL_TREE)
93 delete_dllimport_p = 1;
94 else
95 delete_dllimport_p = 0;
97 a = merge_attributes (old, new);
99 if (delete_dllimport_p)
101 tree prev,t;
103 /* Scan the list for dllimport and delete it. */
104 for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t))
106 if (is_attribute_p ("dllimport", TREE_PURPOSE (t)))
108 if (prev == NULL_TREE)
109 a = TREE_CHAIN (a);
110 else
111 TREE_CHAIN (prev) = TREE_CHAIN (t);
112 break;
117 return a;
120 /* Check a type that has a virtual table, and see if any virtual methods are
121 marked for import or export, and if so, arrange for the vtable to
122 be imported or exported. */
124 static int
125 arm_check_vtable_importexport (type)
126 tree type;
128 tree methods = TYPE_METHODS (type);
129 tree fndecl;
131 if (TREE_CODE (methods) == FUNCTION_DECL)
132 fndecl = methods;
133 else if (TREE_VEC_ELT (methods, 0) != NULL_TREE)
134 fndecl = TREE_VEC_ELT (methods, 0);
135 else
136 fndecl = TREE_VEC_ELT (methods, 1);
138 while (fndecl)
140 if (DECL_VIRTUAL_P (fndecl) || DECL_VINDEX (fndecl) != NULL_TREE)
142 tree exp = lookup_attribute ("dllimport",
143 DECL_MACHINE_ATTRIBUTES (fndecl));
144 if (exp == 0)
145 exp = lookup_attribute ("dllexport",
146 DECL_MACHINE_ATTRIBUTES (fndecl));
147 if (exp)
148 return 1;
151 fndecl = TREE_CHAIN (fndecl);
154 return 0;
157 /* Return non-zero if DECL is a dllexport'd object. */
159 tree current_class_type; /* FIXME */
162 arm_dllexport_p (decl)
163 tree decl;
165 tree exp;
167 if (TREE_CODE (decl) != VAR_DECL
168 && TREE_CODE (decl) != FUNCTION_DECL)
169 return 0;
170 exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl));
171 if (exp)
172 return 1;
174 #if 0 /* This was a hack to get vtable's exported or imported since only one
175 copy of them is ever output. Disabled pending better solution. */
176 /* For C++, the vtables might have to be marked. */
177 if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
179 if (TREE_PUBLIC (decl)
180 && DECL_EXTERNAL (decl) == 0
181 && (DECL_CONTEXT (decl)
182 ? arm_check_vtable_importexport (DECL_CONTEXT (decl))
183 : current_class_type
184 ? arm_check_vtable_importexport (current_class_type)
185 : 0)
187 return 1;
189 #endif
191 return 0;
194 /* Return non-zero if DECL is a dllimport'd object. */
197 arm_dllimport_p (decl)
198 tree decl;
200 tree imp;
202 if (TREE_CODE (decl) == FUNCTION_DECL
203 && TARGET_NOP_FUN_DLLIMPORT)
204 return 0;
206 if (TREE_CODE (decl) != VAR_DECL
207 && TREE_CODE (decl) != FUNCTION_DECL)
208 return 0;
209 imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl));
210 if (imp)
211 return 1;
213 #if 0 /* This was a hack to get vtable's exported or imported since only one
214 copy of them is ever output. Disabled pending better solution. */
215 /* For C++, the vtables might have to be marked. */
216 if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
218 if (TREE_PUBLIC (decl)
219 && DECL_EXTERNAL (decl)
220 && (DECL_CONTEXT (decl)
221 ? arm_check_vtable_importexport (DECL_CONTEXT (decl))
222 : current_class_type
223 ? arm_check_vtable_importexport (current_class_type)
224 : 0)
226 return 1;
228 #endif
230 return 0;
233 /* Return non-zero if SYMBOL is marked as being dllexport'd. */
236 arm_dllexport_name_p (symbol)
237 char * symbol;
239 return symbol[0] == '@' && symbol[1] == 'e' && symbol[2] == '.';
242 /* Return non-zero if SYMBOL is marked as being dllimport'd. */
245 arm_dllimport_name_p (symbol)
246 char * symbol;
248 return symbol[0] == '@' && symbol[1] == 'i' && symbol[2] == '.';
251 /* Mark a DECL as being dllexport'd.
252 Note that we override the previous setting (eg: dllimport). */
254 void
255 arm_mark_dllexport (decl)
256 tree decl;
258 char * oldname;
259 char * newname;
260 rtx rtlname;
261 tree idp;
263 rtlname = XEXP (DECL_RTL (decl), 0);
264 if (GET_CODE (rtlname) == SYMBOL_REF)
265 oldname = XSTR (rtlname, 0);
266 else if (GET_CODE (rtlname) == MEM
267 && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
268 oldname = XSTR (XEXP (rtlname, 0), 0);
269 else
270 abort ();
271 if (arm_dllimport_name_p (oldname))
272 oldname += 9;
273 else if (arm_dllexport_name_p (oldname))
274 return; /* already done */
276 newname = alloca (strlen (oldname) + 4);
277 sprintf (newname, "@e.%s", oldname);
279 /* We pass newname through get_identifier to ensure it has a unique
280 address. RTL processing can sometimes peek inside the symbol ref
281 and compare the string's addresses to see if two symbols are
282 identical. */
283 /* ??? At least I think that's why we do this. */
284 idp = get_identifier (newname);
286 XEXP (DECL_RTL (decl), 0) =
287 gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
290 /* Mark a DECL as being dllimport'd. */
292 void
293 arm_mark_dllimport (decl)
294 tree decl;
296 char * oldname;
297 char * newname;
298 tree idp;
299 rtx rtlname, newrtl;
301 rtlname = XEXP (DECL_RTL (decl), 0);
303 if (GET_CODE (rtlname) == SYMBOL_REF)
304 oldname = XSTR (rtlname, 0);
305 else if (GET_CODE (rtlname) == MEM
306 && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
307 oldname = XSTR (XEXP (rtlname, 0), 0);
308 else
309 abort ();
311 if (arm_dllexport_name_p (oldname))
312 abort (); /* this shouldn't happen */
313 else if (arm_dllimport_name_p (oldname))
314 return; /* already done */
316 /* ??? One can well ask why we're making these checks here,
317 and that would be a good question. */
319 /* Imported variables can't be initialized. */
320 if (TREE_CODE (decl) == VAR_DECL
321 && !DECL_VIRTUAL_P (decl)
322 && DECL_INITIAL (decl))
324 error_with_decl (decl, "initialized variable `%s' is marked dllimport");
325 return;
327 /* Nor can they be static. */
328 if (TREE_CODE (decl) == VAR_DECL
329 /* ??? Is this test for vtables needed? */
330 && !DECL_VIRTUAL_P (decl)
331 && 0 /*???*/)
333 error_with_decl (decl, "static variable `%s' is marked dllimport");
334 return;
337 /* `extern' needn't be specified with dllimport.
338 Specify `extern' now and hope for the best. Sigh. */
339 if (TREE_CODE (decl) == VAR_DECL
340 /* ??? Is this test for vtables needed? */
341 && !DECL_VIRTUAL_P (decl))
343 DECL_EXTERNAL (decl) = 1;
344 TREE_PUBLIC (decl) = 1;
347 newname = alloca (strlen (oldname) + 11);
348 sprintf (newname, "@i.__imp_%s", oldname);
350 /* We pass newname through get_identifier to ensure it has a unique
351 address. RTL processing can sometimes peek inside the symbol ref
352 and compare the string's addresses to see if two symbols are
353 identical. */
354 /* ??? At least I think that's why we do this. */
355 idp = get_identifier (newname);
357 newrtl = gen_rtx (MEM, Pmode,
358 gen_rtx (SYMBOL_REF, Pmode,
359 IDENTIFIER_POINTER (idp)));
360 XEXP (DECL_RTL (decl), 0) = newrtl;
363 /* Cover function to implement ENCODE_SECTION_INFO. */
365 void
366 arm_pe_encode_section_info (decl)
367 tree decl;
369 /* This bit is copied from arm.h. */
370 if (optimize > 0 && TREE_CONSTANT (decl)
371 && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST))
373 rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
374 ? TREE_CST_RTL (decl) : DECL_RTL (decl));
375 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
378 /* Mark the decl so we can tell from the rtl whether the object is
379 dllexport'd or dllimport'd. */
380 if (arm_dllexport_p (decl))
381 arm_mark_dllexport (decl);
382 else if (arm_dllimport_p (decl))
383 arm_mark_dllimport (decl);
384 /* It might be that DECL has already been marked as dllimport, but a
385 subsequent definition nullified that. The attribute is gone but
386 DECL_RTL still has @i.__imp_foo. We need to remove that. */
387 else if ((TREE_CODE (decl) == FUNCTION_DECL
388 || TREE_CODE (decl) == VAR_DECL)
389 && DECL_RTL (decl) != NULL_RTX
390 && GET_CODE (DECL_RTL (decl)) == MEM
391 && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
392 && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF
393 && arm_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0)))
395 char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
396 tree idp = get_identifier (oldname + 9);
397 rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
399 XEXP (DECL_RTL (decl), 0) = newrtl;
401 /* We previously set TREE_PUBLIC and DECL_EXTERNAL.
402 ??? We leave these alone for now. */
406 /* Cover function for UNIQUE_SECTION. */
408 void
409 arm_pe_unique_section (decl, reloc)
410 tree decl;
411 int reloc;
413 int len;
414 char * name;
415 char * string;
416 char * prefix;
418 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
419 /* Strip off any encoding in fnname. */
420 STRIP_NAME_ENCODING (name, name);
422 /* The object is put in, for example, section .text$foo.
423 The linker will then ultimately place them in .text
424 (everything from the $ on is stripped). */
425 if (TREE_CODE (decl) == FUNCTION_DECL)
426 prefix = ".text$";
427 else if (DECL_READONLY_SECTION (decl, reloc))
428 prefix = ".rdata$";
429 else
430 prefix = ".data$";
431 len = strlen (name) + strlen (prefix);
432 string = alloca (len + 1);
433 sprintf (string, "%s%s", prefix, name);
435 DECL_SECTION_NAME (decl) = build_string (len, string);
438 /* This is to better conform to the ARM PCS.
439 Richard Earnshaw hasn't put this into FSF sources yet so it's here. */
442 arm_pe_return_in_memory (type)
443 tree type;
445 if (TREE_CODE (type) == RECORD_TYPE)
447 tree field;
448 int num_fields = 0;
450 /* For a record containing just a single element, we can be a little
451 less restrictive. */
452 for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
454 if (TREE_CODE (field) == FIELD_DECL && ! TREE_STATIC (field))
456 if ((AGGREGATE_TYPE_P (TREE_TYPE (field))
457 && RETURN_IN_MEMORY (TREE_TYPE (field)))
458 || FLOAT_TYPE_P (TREE_TYPE (field)))
459 return 1;
460 num_fields++;
464 if (num_fields == 1)
465 return 0;
467 /* For a struct, we can return in a register if every element was a
468 bit-field and it all fits in one word. */
469 for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
471 if (TREE_CODE (field) == FIELD_DECL
472 && ! TREE_STATIC (field)
473 && (! DECL_BIT_FIELD_TYPE (field)
474 || (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field))
475 + TREE_INT_CST_LOW (DECL_SIZE (field))) > 32))
476 return 1;
478 return 0;
480 else if (TREE_CODE (type) == UNION_TYPE
481 || TREE_CODE (type) == QUAL_UNION_TYPE)
483 tree field;
485 /* Unions can be returned in registers if every element is
486 integral, or can be returned in an integer register. */
487 for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
489 if (TREE_CODE (field) == FIELD_DECL
490 && ! TREE_STATIC (field)
491 && ((AGGREGATE_TYPE_P (TREE_TYPE (field))
492 && RETURN_IN_MEMORY (TREE_TYPE (field)))
493 || FLOAT_TYPE_P (TREE_TYPE (field))))
494 return 1;
496 return 0;
498 /* XXX Not sure what should be done for other aggregates, so put them in
499 memory. */
500 return 1;