Improve linkage specification
[cparser] / mangle.c
1 /*
2  * This file is part of cparser.
3  * Copyright (C) 2007-2008 Matthias Braun <matze@braunis.de>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18  * 02111-1307, USA.
19  */
20 #include <config.h>
21
22 #include <libfirm/firm.h>
23 #include <string.h>
24
25 #include "entity_t.h"
26 #include "type_t.h"
27 #include "symbol_t.h"
28 #include "mangle.h"
29 #include "diagnostic.h"
30 #include "ast2firm.h"
31 #include "lang_features.h"
32 #include "adt/error.h"
33
34 static ident          *id_underscore;
35 static struct obstack  obst;
36
37 static void mangle_type(type_t *type);
38
39 static char get_atomic_type_mangle(atomic_type_kind_t kind)
40 {
41         switch (kind) {
42         case ATOMIC_TYPE_INVALID: break;
43         case ATOMIC_TYPE_VOID:        return 'v';
44         case ATOMIC_TYPE_BOOL:        return 'b';
45         case ATOMIC_TYPE_CHAR:        return 'c';
46         case ATOMIC_TYPE_SCHAR:       return 'a';
47         case ATOMIC_TYPE_UCHAR:       return 'h';
48         case ATOMIC_TYPE_INT:         return 'i';
49         case ATOMIC_TYPE_UINT:        return 'j';
50         case ATOMIC_TYPE_SHORT:       return 's';
51         case ATOMIC_TYPE_USHORT:      return 't';
52         case ATOMIC_TYPE_LONG:        return 'l';
53         case ATOMIC_TYPE_ULONG:       return 'm';
54         case ATOMIC_TYPE_LONGLONG:    return 'x';
55         case ATOMIC_TYPE_ULONGLONG:   return 'y';
56         case ATOMIC_TYPE_LONG_DOUBLE: return 'e';
57         case ATOMIC_TYPE_FLOAT:       return 'f';
58         case ATOMIC_TYPE_DOUBLE:      return 'd';
59         }
60         panic("invalid atomic type in mangler");
61 }
62
63 static void mangle_atomic_type(const atomic_type_t *type)
64 {
65         obstack_1grow(&obst, get_atomic_type_mangle(type->akind));
66 }
67
68 static void mangle_pointer_type(const pointer_type_t *type)
69 {
70         obstack_1grow(&obst, 'P');
71         mangle_type(type->points_to);
72 }
73
74 static void mangle_function_type(const function_type_t *type)
75 {
76         obstack_1grow(&obst, 'F');
77         if (type->linkage == LINKAGE_C) {
78                 obstack_1grow(&obst, 'Y');
79         }
80
81         mangle_type(type->return_type);
82
83         function_parameter_t *parameter = type->parameters;
84         for ( ; parameter != NULL; parameter = parameter->next) {
85                 mangle_type(parameter->type);
86         }
87         if (type->variadic) {
88                 obstack_1grow(&obst, 'z');
89         }
90         if (type->unspecified_parameters)
91                 panic("can't mangle unspecified parameter types");
92         if (type->kr_style_parameters)
93                 panic("can't mangle kr_style_parameters type");
94
95         obstack_1grow(&obst, 'E');
96 }
97
98 static void mangle_qualifiers(type_qualifiers_t qualifiers)
99 {
100         if (qualifiers & TYPE_QUALIFIER_CONST)
101                 obstack_1grow(&obst, 'K');
102         if (qualifiers & TYPE_QUALIFIER_VOLATILE)
103                 obstack_1grow(&obst, 'V');
104         if (qualifiers & TYPE_QUALIFIER_RESTRICT)
105                 obstack_1grow(&obst, 'r');
106
107         /* handle MS extended qualifiers? */
108 }
109
110 static void mangle_type(type_t *orig_type)
111 {
112         type_t *type = skip_typeref(orig_type);
113
114         mangle_qualifiers(type->base.qualifiers);
115
116         switch (type->kind) {
117         case TYPE_ATOMIC:
118                 mangle_atomic_type(&type->atomic);
119                 return;
120         case TYPE_POINTER:
121                 mangle_pointer_type(&type->pointer);
122                 return;
123         case TYPE_FUNCTION:
124                 mangle_function_type(&type->function);
125                 return;
126         case TYPE_INVALID:
127                 panic("invalid type encountered while mangling");
128         case TYPE_ERROR:
129                 panic("error type encountered while mangling");
130         case TYPE_BUILTIN:
131         case TYPE_TYPEDEF:
132         case TYPE_TYPEOF:
133                 panic("typeref not resolved while manging?!?");
134
135         case TYPE_BITFIELD:
136         case TYPE_COMPLEX:
137         case TYPE_IMAGINARY:
138         case TYPE_COMPOUND_STRUCT:
139         case TYPE_COMPOUND_UNION:
140         case TYPE_ENUM:
141         case TYPE_ARRAY:
142                 panic("no mangling for this type implemented yet");
143                 break;
144         }
145         panic("invalid type encountered while mangling");
146 }
147
148 static void mangle_entity(entity_t *entity)
149 {
150         obstack_1grow(&obst, '_');
151         obstack_1grow(&obst, 'Z');
152
153         /* TODO: mangle scope */
154
155         symbol_t *symbol = entity->base.symbol;
156         obstack_printf(&obst, "%u%s", strlen(symbol->string), symbol->string);
157
158         if (entity->kind == ENTITY_FUNCTION) {
159                 mangle_type(entity->declaration.type);
160         }
161 }
162
163 /**
164  * Mangles an entity linker (ld) name for win32 usage.
165  *
166  * @param ent          the entity to be mangled
167  * @param declaration  the declaration
168  */
169 ident *create_name_win32(entity_t *entity)
170 {
171         struct obstack *o = &obst;
172
173         assert(is_declaration(entity));
174
175         if (entity->declaration.modifiers & DM_DLLIMPORT) {
176                 /* add prefix for imported symbols */
177                 obstack_printf(o, "__imp_");
178         }
179
180         if (entity->kind == ENTITY_FUNCTION) {
181                 cc_kind_t cc = entity->declaration.type->function.calling_convention;
182
183                 /* calling convention prefix */
184                 switch (cc) {
185                         case CC_DEFAULT:
186                         case CC_CDECL:
187                         case CC_STDCALL:  obstack_1grow(o, '_'); break;
188                         case CC_FASTCALL: obstack_1grow(o, '@'); break;
189                         default:          panic("unhandled calling convention");
190                 }
191
192                 switch (entity->declaration.type->function.linkage) {
193                         case LINKAGE_INVALID:
194                                 break;
195
196                         case LINKAGE_C:
197                                 obstack_printf(o, "%s", entity->base.symbol->string);
198                                 break;
199
200                         case LINKAGE_CXX:
201                                 mangle_entity(entity);
202                                 break;
203                 }
204
205                 /* calling convention suffix */
206                 switch (cc) {
207                         case CC_DEFAULT:
208                         case CC_CDECL:
209                                 break;
210
211                         case CC_STDCALL:
212                         case CC_FASTCALL: {
213                                 ir_type *irtype = get_ir_type(entity->declaration.type);
214                                 size_t   size   = 0;
215                                 for (int i = get_method_n_params(irtype) - 1; i >= 0; --i) {
216                                         size += get_type_size_bytes(get_method_param_type(irtype, i));
217                                 }
218                                 obstack_printf(o, "@%zu\n", size);
219                                 break;
220                         }
221
222                         default:
223                                 panic("unhandled calling convention");
224                 }
225         } else {
226                 obstack_printf(o, "_%s", entity->base.symbol->string);
227         }
228
229         size_t  size = obstack_object_size(o);
230         char   *str  = obstack_finish(o);
231         ident  *id   = new_id_from_chars(str, size);
232         obstack_free(o, str);
233         return id;
234 }
235
236 /**
237  * Mangles an entity linker (ld) name for Linux ELF usage.
238  *
239  * @param ent          the entity to be mangled
240  * @param declaration  the declaration
241  */
242 ident *create_name_linux_elf(entity_t *entity)
243 {
244         bool needs_mangling = false;
245
246         if (entity->kind == ENTITY_FUNCTION) {
247                 switch (entity->declaration.type->function.linkage) {
248                         case LINKAGE_INVALID: break;
249                         case LINKAGE_C:       break;
250                         case LINKAGE_CXX:     needs_mangling = true; break;
251                 }
252         }
253
254         if (needs_mangling) {
255                 mangle_entity(entity);
256                 obstack_1grow(&obst, '\0');
257                 char *str = obstack_finish(&obst);
258
259                 ident *id = new_id_from_str(str);
260                 obstack_free(&obst, str);
261
262                 return id;
263         }
264
265         return new_id_from_str(entity->base.symbol->string);
266 }
267
268 /**
269  * Mangles an entity linker (ld) name for Mach-O usage.
270  *
271  * @param ent          the entity to be mangled
272  * @param declaration  the declaration
273  */
274 ident *create_name_macho(entity_t *entity)
275 {
276         ident *id = new_id_from_str(entity->base.symbol->string);
277         return id_mangle(id_underscore, id);
278 }
279
280 void init_mangle(void)
281 {
282         id_underscore = new_id_from_chars("_", 1);
283
284         obstack_init(&obst);
285 }
286
287 void exit_mangle(void)
288 {
289         obstack_free(&obst, NULL);
290 }