]>
Commit | Line | Data |
---|---|---|
3c8348d3 NC |
1 | /* Routines for GCC for a Symbian OS targeted SH backend, shared by |
2 | both the C and C++ compilers. | |
d8a07487 | 3 | Copyright (C) 2004, 2005, 2007, 2009, 2010 Free Software Foundation, Inc. |
3c8348d3 NC |
4 | Contributed by RedHat. |
5 | Most of this code is stolen from i386/winnt.c. | |
6 | ||
7 | This file is part of GCC. | |
8 | ||
9 | GCC is free software; you can redistribute it and/or modify it | |
10 | under the terms of the GNU General Public License as published | |
11 | by the Free Software Foundation; either version 3, or (at your | |
12 | option) any later version. | |
13 | ||
14 | GCC is distributed in the hope that it will be useful, but WITHOUT | |
15 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
16 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
17 | License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with GCC; see the file COPYING3. If not see | |
21 | <http://www.gnu.org/licenses/>. */ | |
22 | ||
23 | #include "config.h" | |
24 | #include "system.h" | |
25 | #include "coretypes.h" | |
26 | #include "tm.h" | |
27 | #include "rtl.h" | |
28 | #include "output.h" | |
29 | #include "flags.h" | |
30 | #include "tree.h" | |
31 | #include "expr.h" | |
32 | #include "tm_p.h" | |
718f9c0f | 33 | #include "diagnostic-core.h" |
3c8348d3 NC |
34 | #include "sh-symbian.h" |
35 | ||
36 | /* Return nonzero if SYMBOL is marked as being dllexport'd. */ | |
37 | ||
38 | bool | |
39 | sh_symbian_is_dllexported_name (const char *symbol) | |
40 | { | |
41 | return strncmp (DLL_EXPORT_PREFIX, symbol, | |
42 | strlen (DLL_EXPORT_PREFIX)) == 0; | |
43 | } | |
44 | ||
45 | /* Return nonzero if SYMBOL is marked as being dllimport'd. */ | |
46 | ||
47 | static bool | |
48 | sh_symbian_is_dllimported_name (const char *symbol) | |
49 | { | |
50 | return strncmp (DLL_IMPORT_PREFIX, symbol, | |
51 | strlen (DLL_IMPORT_PREFIX)) == 0; | |
52 | } | |
53 | ||
54 | /* Return nonzero if DECL is a dllexport'd object. */ | |
55 | ||
56 | bool | |
57 | sh_symbian_is_dllexported (tree decl) | |
58 | { | |
59 | tree exp; | |
60 | ||
61 | if ( TREE_CODE (decl) != VAR_DECL | |
62 | && TREE_CODE (decl) != FUNCTION_DECL) | |
63 | return false; | |
64 | ||
65 | exp = lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)); | |
66 | ||
67 | /* Class members get the dllexport status of their class. */ | |
68 | if (exp == NULL) | |
69 | { | |
70 | tree class = sh_symbian_associated_type (decl); | |
71 | ||
72 | if (class) | |
73 | exp = lookup_attribute ("dllexport", TYPE_ATTRIBUTES (class)); | |
74 | } | |
75 | #if SYMBIAN_DEBUG | |
76 | if (exp) | |
77 | { | |
78 | print_node_brief (stderr, "dllexport:", decl, 0); | |
79 | fprintf (stderr, "\n"); | |
80 | } | |
81 | else | |
82 | #if SYMBIAN_DEBUG < 2 | |
83 | if (TREE_CODE (decl) != FUNCTION_DECL) | |
84 | #endif | |
85 | { | |
86 | print_node_brief (stderr, "no dllexport:", decl, 0); | |
87 | fprintf (stderr, "\n"); | |
88 | } | |
89 | #endif | |
90 | return exp ? true : false; | |
91 | } | |
92 | ||
93 | /* Mark a DECL as being dllimport'd. */ | |
94 | ||
95 | static void | |
96 | sh_symbian_mark_dllimport (tree decl) | |
97 | { | |
98 | const char *oldname; | |
99 | char *newname; | |
100 | tree idp; | |
101 | rtx rtlname; | |
102 | rtx newrtl; | |
103 | ||
104 | rtlname = XEXP (DECL_RTL (decl), 0); | |
105 | if (MEM_P (rtlname)) | |
106 | rtlname = XEXP (rtlname, 0); | |
107 | gcc_assert (GET_CODE (rtlname) == SYMBOL_REF); | |
108 | oldname = XSTR (rtlname, 0); | |
109 | ||
110 | if (sh_symbian_is_dllexported_name (oldname)) | |
111 | { | |
112 | error ("%qE declared as both exported to and imported from a DLL", | |
113 | DECL_NAME (decl)); | |
114 | } | |
115 | else if (sh_symbian_is_dllimported_name (oldname)) | |
116 | { | |
117 | /* Already done, but do a sanity check to prevent assembler errors. */ | |
118 | if (!DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl)) | |
d8a07487 | 119 | error ("failure in redeclaration of %q+D: dllimport%'d symbol lacks external linkage", |
3c8348d3 NC |
120 | decl); |
121 | } | |
122 | else | |
123 | { | |
124 | newname = (char *) alloca (strlen (DLL_IMPORT_PREFIX) + strlen (oldname) + 1); | |
125 | sprintf (newname, "%s%s", DLL_IMPORT_PREFIX, oldname); | |
126 | ||
127 | /* We pass newname through get_identifier to ensure it has a unique | |
128 | address. RTL processing can sometimes peek inside the symbol ref | |
129 | and compare the string's addresses to see if two symbols are | |
130 | identical. */ | |
131 | idp = get_identifier (newname); | |
132 | newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); | |
133 | XEXP (DECL_RTL (decl), 0) = newrtl; | |
134 | } | |
135 | } | |
136 | ||
137 | /* Mark a DECL as being dllexport'd. | |
138 | Note that we override the previous setting (e.g.: dllimport). */ | |
139 | ||
140 | static void | |
141 | sh_symbian_mark_dllexport (tree decl) | |
142 | { | |
143 | const char *oldname; | |
144 | char *newname; | |
145 | rtx rtlname; | |
146 | tree idp; | |
147 | ||
148 | rtlname = XEXP (DECL_RTL (decl), 0); | |
149 | if (MEM_P (rtlname)) | |
150 | rtlname = XEXP (rtlname, 0); | |
151 | gcc_assert (GET_CODE (rtlname) == SYMBOL_REF); | |
152 | oldname = XSTR (rtlname, 0); | |
153 | ||
154 | if (sh_symbian_is_dllimported_name (oldname)) | |
155 | { | |
156 | /* Remove DLL_IMPORT_PREFIX. | |
157 | Note - we do not issue a warning here. In Symbian's environment it | |
158 | is legitimate for a prototype to be marked as dllimport and the | |
159 | corresponding definition to be marked as dllexport. The prototypes | |
160 | are in headers used everywhere and the definition is in a translation | |
161 | unit which has included the header in order to ensure argument | |
162 | correctness. */ | |
163 | oldname += strlen (DLL_IMPORT_PREFIX); | |
164 | DECL_DLLIMPORT_P (decl) = 0; | |
165 | } | |
166 | else if (sh_symbian_is_dllexported_name (oldname)) | |
167 | return; /* Already done. */ | |
168 | ||
169 | newname = (char *) alloca (strlen (DLL_EXPORT_PREFIX) + strlen (oldname) + 1); | |
170 | sprintf (newname, "%s%s", DLL_EXPORT_PREFIX, oldname); | |
171 | ||
172 | /* We pass newname through get_identifier to ensure it has a unique | |
173 | address. RTL processing can sometimes peek inside the symbol ref | |
174 | and compare the string's addresses to see if two symbols are | |
175 | identical. */ | |
176 | idp = get_identifier (newname); | |
177 | ||
178 | XEXP (DECL_RTL (decl), 0) = | |
179 | gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); | |
180 | } | |
181 | ||
182 | void | |
183 | sh_symbian_encode_section_info (tree decl, rtx rtl, int first) | |
184 | { | |
185 | default_encode_section_info (decl, rtl, first); | |
186 | ||
187 | /* Mark the decl so we can tell from the rtl whether | |
188 | the object is dllexport'd or dllimport'd. */ | |
189 | if (sh_symbian_is_dllexported (decl)) | |
190 | sh_symbian_mark_dllexport (decl); | |
191 | else if (sh_symbian_is_dllimported (decl)) | |
192 | sh_symbian_mark_dllimport (decl); | |
193 | /* It might be that DECL has already been marked as dllimport, but a | |
194 | subsequent definition nullified that. The attribute is gone but | |
195 | DECL_RTL still has (DLL_IMPORT_PREFIX) prefixed. We need to remove | |
196 | that. Ditto for the DECL_DLLIMPORT_P flag. */ | |
197 | else if ( (TREE_CODE (decl) == FUNCTION_DECL | |
198 | || TREE_CODE (decl) == VAR_DECL) | |
199 | && DECL_RTL (decl) != NULL_RTX | |
200 | && MEM_P (DECL_RTL (decl)) | |
201 | && MEM_P (XEXP (DECL_RTL (decl), 0)) | |
202 | && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF | |
203 | && sh_symbian_is_dllimported_name (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0))) | |
204 | { | |
205 | const char * oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0); | |
206 | /* Remove DLL_IMPORT_PREFIX. */ | |
207 | tree idp = get_identifier (oldname + strlen (DLL_IMPORT_PREFIX)); | |
208 | rtx newrtl = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp)); | |
209 | ||
210 | warning (0, "%s %q+D %s after being referenced with dllimport linkage", | |
211 | TREE_CODE (decl) == VAR_DECL ? "variable" : "function", | |
212 | decl, (DECL_INITIAL (decl) || !DECL_EXTERNAL (decl)) | |
213 | ? "defined locally" : "redeclared without dllimport attribute"); | |
214 | ||
215 | XEXP (DECL_RTL (decl), 0) = newrtl; | |
216 | ||
217 | DECL_DLLIMPORT_P (decl) = 0; | |
218 | } | |
219 | } | |
220 | ||
221 | /* Return the length of a function name prefix | |
222 | that starts with the character 'c'. */ | |
223 | ||
224 | static int | |
225 | sh_symbian_get_strip_length (int c) | |
226 | { | |
227 | /* XXX Assumes strlen (DLL_EXPORT_PREFIX) == strlen (DLL_IMPORT_PREFIX). */ | |
228 | return (c == SH_SYMBIAN_FLAG_CHAR[0]) ? strlen (DLL_EXPORT_PREFIX) : 0; | |
229 | } | |
230 | ||
231 | /* Return a pointer to a function's name with any | |
232 | and all prefix encodings stripped from it. */ | |
233 | ||
234 | const char * | |
235 | sh_symbian_strip_name_encoding (const char *name) | |
236 | { | |
237 | int skip; | |
238 | ||
239 | while ((skip = sh_symbian_get_strip_length (*name))) | |
240 | name += skip; | |
241 | ||
242 | return name; | |
243 | } | |
244 |