1 /* Routines for GCC for ARM/pe.
2 Copyright (C) 1995, 1996, 2000 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)
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. */
30 #include "arm-protos.h"
32 extern int current_function_anonymous_args
;
34 /* ARM/PE specific attribute support.
36 ARM/PE has three new attributes:
37 naked - for interrupt functions
38 dllexport - for exporting a function/variable that will live in a dll
39 dllimport - for importing a function/variable from a dll
41 Microsoft allows multiple declspecs in one __declspec, separating
42 them with spaces. We do NOT support this. Instead, use __declspec
46 /* Return nonzero if ATTR is a valid attribute for DECL.
47 ATTRIBUTES are any existing attributes and ARGS are the arguments
48 supplied with ATTR. */
51 arm_pe_valid_machine_decl_attribute (decl
, attributes
, attr
, args
)
53 tree attributes ATTRIBUTE_UNUSED
;
57 if (args
!= NULL_TREE
)
60 if (is_attribute_p ("dllexport", attr
))
62 if (is_attribute_p ("dllimport", attr
))
65 return arm_valid_machine_decl_attribute (decl
, attr
, args
);
68 /* Merge attributes in decls OLD and NEW.
70 This handles the following situation:
72 __declspec (dllimport) int foo;
75 The second instance of `foo' nullifies the dllimport. */
78 arm_pe_merge_machine_decl_attributes (old
, new)
82 int delete_dllimport_p
;
84 old
= DECL_MACHINE_ATTRIBUTES (old
);
85 new = DECL_MACHINE_ATTRIBUTES (new);
87 /* What we need to do here is remove from `old' dllimport if it doesn't
88 appear in `new'. dllimport behaves like extern: if a declaration is
89 marked dllimport and a definition appears later, then the object
90 is not dllimport'd. */
92 if (lookup_attribute ("dllimport", old
) != NULL_TREE
93 && lookup_attribute ("dllimport", new) == NULL_TREE
)
94 delete_dllimport_p
= 1;
96 delete_dllimport_p
= 0;
98 a
= merge_attributes (old
, new);
100 if (delete_dllimport_p
)
104 /* Scan the list for dllimport and delete it. */
105 for (prev
= NULL_TREE
, t
= a
; t
; prev
= t
, t
= TREE_CHAIN (t
))
107 if (is_attribute_p ("dllimport", TREE_PURPOSE (t
)))
109 if (prev
== NULL_TREE
)
112 TREE_CHAIN (prev
) = TREE_CHAIN (t
);
122 /* Check a type that has a virtual table, and see if any virtual methods are
123 marked for import or export, and if so, arrange for the vtable to
124 be imported or exported. */
127 arm_check_vtable_importexport (type
)
130 tree methods
= TYPE_METHODS (type
);
133 if (TREE_CODE (methods
) == FUNCTION_DECL
)
135 else if (TREE_VEC_ELT (methods
, 0) != NULL_TREE
)
136 fndecl
= TREE_VEC_ELT (methods
, 0);
138 fndecl
= TREE_VEC_ELT (methods
, 1);
142 if (DECL_VIRTUAL_P (fndecl
) || DECL_VINDEX (fndecl
) != NULL_TREE
)
144 tree exp
= lookup_attribute ("dllimport",
145 DECL_MACHINE_ATTRIBUTES (fndecl
));
147 exp
= lookup_attribute ("dllexport",
148 DECL_MACHINE_ATTRIBUTES (fndecl
));
153 fndecl
= TREE_CHAIN (fndecl
);
160 /* Return non-zero if DECL is a dllexport'd object. */
162 tree current_class_type
; /* FIXME */
165 arm_dllexport_p (decl
)
170 if (TREE_CODE (decl
) != VAR_DECL
171 && TREE_CODE (decl
) != FUNCTION_DECL
)
173 exp
= lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl
));
177 #if 0 /* This was a hack to get vtable's exported or imported since only one
178 copy of them is ever output. Disabled pending better solution. */
179 /* For C++, the vtables might have to be marked. */
180 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_VIRTUAL_P (decl
))
182 if (TREE_PUBLIC (decl
)
183 && DECL_EXTERNAL (decl
) == 0
184 && (DECL_CONTEXT (decl
)
185 ? arm_check_vtable_importexport (DECL_CONTEXT (decl
))
187 ? arm_check_vtable_importexport (current_class_type
)
197 /* Return non-zero if DECL is a dllimport'd object. */
200 arm_dllimport_p (decl
)
205 if (TREE_CODE (decl
) == FUNCTION_DECL
206 && TARGET_NOP_FUN_DLLIMPORT
)
209 if (TREE_CODE (decl
) != VAR_DECL
210 && TREE_CODE (decl
) != FUNCTION_DECL
)
212 imp
= lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl
));
216 #if 0 /* This was a hack to get vtable's exported or imported since only one
217 copy of them is ever output. Disabled pending better solution. */
218 /* For C++, the vtables might have to be marked. */
219 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_VIRTUAL_P (decl
))
221 if (TREE_PUBLIC (decl
)
222 && DECL_EXTERNAL (decl
)
223 && (DECL_CONTEXT (decl
)
224 ? arm_check_vtable_importexport (DECL_CONTEXT (decl
))
226 ? arm_check_vtable_importexport (current_class_type
)
236 /* Return non-zero if SYMBOL is marked as being dllexport'd. */
239 arm_dllexport_name_p (symbol
)
242 return symbol
[0] == ARM_PE_FLAG_CHAR
&& symbol
[1] == 'e' && symbol
[2] == '.';
245 /* Return non-zero if SYMBOL is marked as being dllimport'd. */
248 arm_dllimport_name_p (symbol
)
251 return symbol
[0] == ARM_PE_FLAG_CHAR
&& symbol
[1] == 'i' && symbol
[2] == '.';
254 /* Mark a DECL as being dllexport'd.
255 Note that we override the previous setting (eg: dllimport). */
258 arm_mark_dllexport (decl
)
266 rtlname
= XEXP (DECL_RTL (decl
), 0);
267 if (GET_CODE (rtlname
) == SYMBOL_REF
)
268 oldname
= XSTR (rtlname
, 0);
269 else if (GET_CODE (rtlname
) == MEM
270 && GET_CODE (XEXP (rtlname
, 0)) == SYMBOL_REF
)
271 oldname
= XSTR (XEXP (rtlname
, 0), 0);
274 if (arm_dllimport_name_p (oldname
))
276 else if (arm_dllexport_name_p (oldname
))
277 return; /* already done */
279 newname
= alloca (strlen (oldname
) + 4);
280 sprintf (newname
, "%ce.%s", ARM_PE_FLAG_CHAR
, oldname
);
282 /* We pass newname through get_identifier to ensure it has a unique
283 address. RTL processing can sometimes peek inside the symbol ref
284 and compare the string's addresses to see if two symbols are
286 /* ??? At least I think that's why we do this. */
287 idp
= get_identifier (newname
);
289 XEXP (DECL_RTL (decl
), 0) =
290 gen_rtx (SYMBOL_REF
, Pmode
, IDENTIFIER_POINTER (idp
));
293 /* Mark a DECL as being dllimport'd. */
296 arm_mark_dllimport (decl
)
304 rtlname
= XEXP (DECL_RTL (decl
), 0);
306 if (GET_CODE (rtlname
) == SYMBOL_REF
)
307 oldname
= XSTR (rtlname
, 0);
308 else if (GET_CODE (rtlname
) == MEM
309 && GET_CODE (XEXP (rtlname
, 0)) == SYMBOL_REF
)
310 oldname
= XSTR (XEXP (rtlname
, 0), 0);
314 if (arm_dllexport_name_p (oldname
))
315 abort (); /* this shouldn't happen */
316 else if (arm_dllimport_name_p (oldname
))
317 return; /* already done */
319 /* ??? One can well ask why we're making these checks here,
320 and that would be a good question. */
322 /* Imported variables can't be initialized. */
323 if (TREE_CODE (decl
) == VAR_DECL
324 && !DECL_VIRTUAL_P (decl
)
325 && DECL_INITIAL (decl
))
327 error_with_decl (decl
, "initialized variable `%s' is marked dllimport");
330 /* Nor can they be static. */
331 if (TREE_CODE (decl
) == VAR_DECL
332 /* ??? Is this test for vtables needed? */
333 && !DECL_VIRTUAL_P (decl
)
336 error_with_decl (decl
, "static variable `%s' is marked dllimport");
340 /* `extern' needn't be specified with dllimport.
341 Specify `extern' now and hope for the best. Sigh. */
342 if (TREE_CODE (decl
) == VAR_DECL
343 /* ??? Is this test for vtables needed? */
344 && !DECL_VIRTUAL_P (decl
))
346 DECL_EXTERNAL (decl
) = 1;
347 TREE_PUBLIC (decl
) = 1;
350 newname
= alloca (strlen (oldname
) + 11);
351 sprintf (newname
, "%ci.__imp_%s", ARM_PE_FLAG_CHAR
, oldname
);
353 /* We pass newname through get_identifier to ensure it has a unique
354 address. RTL processing can sometimes peek inside the symbol ref
355 and compare the string's addresses to see if two symbols are
357 /* ??? At least I think that's why we do this. */
358 idp
= get_identifier (newname
);
360 newrtl
= gen_rtx (MEM
, Pmode
,
361 gen_rtx (SYMBOL_REF
, Pmode
,
362 IDENTIFIER_POINTER (idp
)));
363 XEXP (DECL_RTL (decl
), 0) = newrtl
;
366 /* Cover function to implement ENCODE_SECTION_INFO. */
369 arm_pe_encode_section_info (decl
)
372 /* This bit is copied from arm.h. */
373 if (optimize
> 0 && TREE_CONSTANT (decl
)
374 && (!flag_writable_strings
|| TREE_CODE (decl
) != STRING_CST
))
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;
381 /* Mark the decl so we can tell from the rtl whether the object is
382 dllexport'd or dllimport'd. */
383 if (arm_dllexport_p (decl
))
384 arm_mark_dllexport (decl
);
385 else if (arm_dllimport_p (decl
))
386 arm_mark_dllimport (decl
);
387 /* It might be that DECL has already been marked as dllimport, but a
388 subsequent definition nullified that. The attribute is gone but
389 DECL_RTL still has @i.__imp_foo. We need to remove that. */
390 else if ((TREE_CODE (decl
) == FUNCTION_DECL
391 || TREE_CODE (decl
) == VAR_DECL
)
392 && DECL_RTL (decl
) != NULL_RTX
393 && GET_CODE (DECL_RTL (decl
)) == MEM
394 && GET_CODE (XEXP (DECL_RTL (decl
), 0)) == MEM
395 && GET_CODE (XEXP (XEXP (DECL_RTL (decl
), 0), 0)) == SYMBOL_REF
396 && arm_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl
), 0), 0), 0)))
398 char *oldname
= XSTR (XEXP (XEXP (DECL_RTL (decl
), 0), 0), 0);
399 tree idp
= get_identifier (oldname
+ 9);
400 rtx newrtl
= gen_rtx (SYMBOL_REF
, Pmode
, IDENTIFIER_POINTER (idp
));
402 XEXP (DECL_RTL (decl
), 0) = newrtl
;
404 /* We previously set TREE_PUBLIC and DECL_EXTERNAL.
405 ??? We leave these alone for now. */
409 /* Cover function for UNIQUE_SECTION. */
412 arm_pe_unique_section (decl
, reloc
)
421 name
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl
));
422 /* Strip off any encoding in fnname. */
423 STRIP_NAME_ENCODING (name
, name
);
425 /* The object is put in, for example, section .text$foo.
426 The linker will then ultimately place them in .text
427 (everything from the $ on is stripped). */
428 if (TREE_CODE (decl
) == FUNCTION_DECL
)
430 else if (DECL_READONLY_SECTION (decl
, reloc
))
434 len
= strlen (name
) + strlen (prefix
);
435 string
= alloca (len
+ 1);
436 sprintf (string
, "%s%s", prefix
, name
);
438 DECL_SECTION_NAME (decl
) = build_string (len
, string
);
441 /* This is to better conform to the ARM PCS.
442 Richard Earnshaw hasn't put this into FSF sources yet so it's here. */
445 arm_pe_return_in_memory (type
)
448 if (TREE_CODE (type
) == RECORD_TYPE
)
453 /* For a record containing just a single element, we can be a little
455 for (field
= TYPE_FIELDS (type
); field
; field
= TREE_CHAIN (field
))
457 if (TREE_CODE (field
) == FIELD_DECL
&& ! TREE_STATIC (field
))
459 if ((AGGREGATE_TYPE_P (TREE_TYPE (field
))
460 && RETURN_IN_MEMORY (TREE_TYPE (field
)))
461 || FLOAT_TYPE_P (TREE_TYPE (field
)))
470 /* For a struct, we can return in a register if every element was a
471 bit-field and it all fits in one word. */
472 for (field
= TYPE_FIELDS (type
); field
; field
= TREE_CHAIN (field
))
474 if (TREE_CODE (field
) == FIELD_DECL
475 && ! TREE_STATIC (field
)
476 && (! DECL_BIT_FIELD_TYPE (field
)
477 || (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field
))
478 + TREE_INT_CST_LOW (DECL_SIZE (field
))) > 32))
483 else if (TREE_CODE (type
) == UNION_TYPE
484 || TREE_CODE (type
) == QUAL_UNION_TYPE
)
488 /* Unions can be returned in registers if every element is
489 integral, or can be returned in an integer register. */
490 for (field
= TYPE_FIELDS (type
); field
; field
= TREE_CHAIN (field
))
492 if (TREE_CODE (field
) == FIELD_DECL
493 && ! TREE_STATIC (field
)
494 && ((AGGREGATE_TYPE_P (TREE_TYPE (field
))
495 && RETURN_IN_MEMORY (TREE_TYPE (field
)))
496 || FLOAT_TYPE_P (TREE_TYPE (field
))))
501 /* XXX Not sure what should be done for other aggregates, so put them in