More work for C++ mode:
[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 ident          *id_imp;
36 static symbol_t       *sym_C;
37 static symbol_t       *sym_stdcall;
38 static struct obstack  obst;
39
40 static void mangle_type(type_t *type);
41
42 static const char *get_atomic_type_mangle(atomic_type_kind_t kind)
43 {
44         switch (kind) {
45         case ATOMIC_TYPE_INVALID: break;
46         case ATOMIC_TYPE_VOID:        return "v";
47         case ATOMIC_TYPE_BOOL:        return "b";
48         case ATOMIC_TYPE_CHAR:        return "c";
49         case ATOMIC_TYPE_SCHAR:       return "a";
50         case ATOMIC_TYPE_UCHAR:       return "h";
51         case ATOMIC_TYPE_INT:         return "i";
52         case ATOMIC_TYPE_UINT:        return "j";
53         case ATOMIC_TYPE_SHORT:       return "s";
54         case ATOMIC_TYPE_USHORT:      return "t";
55         case ATOMIC_TYPE_LONG:        return "l";
56         case ATOMIC_TYPE_ULONG:       return "m";
57         case ATOMIC_TYPE_LONGLONG:    return "x";
58         case ATOMIC_TYPE_ULONGLONG:   return "y";
59         case ATOMIC_TYPE_LONG_DOUBLE: return "e";
60         case ATOMIC_TYPE_FLOAT:       return "f";
61         case ATOMIC_TYPE_DOUBLE:      return "d";
62         }
63         panic("invalid atomic type in mangler");
64 }
65
66 static void mangle_atomic_type(const atomic_type_t *type)
67 {
68         obstack_printf(&obst, "%s", get_atomic_type_mangle(type->akind));
69 }
70
71 static void mangle_pointer_type(const pointer_type_t *type)
72 {
73         obstack_printf(&obst, "P");
74         mangle_type(type->points_to);
75 }
76
77 static void mangle_function_type(const function_type_t *type)
78 {
79         obstack_printf(&obst, "F");
80         if (type->linkage == sym_C) {
81                 obstack_printf(&obst, "Y");
82         }
83
84         mangle_type(type->return_type);
85
86         function_parameter_t *parameter = type->parameters;
87         for ( ; parameter != NULL; parameter = parameter->next) {
88                 mangle_type(parameter->type);
89         }
90         if (type->variadic) {
91                 obstack_printf(&obst, "z");
92         }
93         if (type->unspecified_parameters)
94                 panic("can't mangle unspecified parameter types");
95         if (type->kr_style_parameters)
96                 panic("can't mangle kr_style_parameters type");
97
98         obstack_printf(&obst, "E");
99 }
100
101 static void mangle_qualifiers(type_qualifiers_t qualifiers)
102 {
103         if (qualifiers & TYPE_QUALIFIER_CONST)
104                 obstack_printf(&obst, "K");
105         if (qualifiers & TYPE_QUALIFIER_VOLATILE)
106                 obstack_printf(&obst, "V");
107         if (qualifiers & TYPE_QUALIFIER_RESTRICT)
108                 obstack_printf(&obst, "r");
109
110         /* handle MS extended qualifiers? */
111 }
112
113 static void mangle_type(type_t *orig_type)
114 {
115         type_t *type = skip_typeref(orig_type);
116
117         mangle_qualifiers(type->base.qualifiers);
118
119         switch (type->kind) {
120         case TYPE_ATOMIC:
121                 mangle_atomic_type(&type->atomic);
122                 return;
123         case TYPE_POINTER:
124                 mangle_pointer_type(&type->pointer);
125                 return;
126         case TYPE_FUNCTION:
127                 mangle_function_type(&type->function);
128                 return;
129         case TYPE_INVALID:
130                 panic("invalid type encountered while mangling");
131         case TYPE_ERROR:
132                 panic("error type encountered while mangling");
133         case TYPE_BUILTIN:
134         case TYPE_TYPEDEF:
135         case TYPE_TYPEOF:
136                 panic("typeref not resolved while manging?!?");
137
138         case TYPE_BITFIELD:
139         case TYPE_COMPLEX:
140         case TYPE_IMAGINARY:
141         case TYPE_COMPOUND_STRUCT:
142         case TYPE_COMPOUND_UNION:
143         case TYPE_ENUM:
144         case TYPE_ARRAY:
145                 panic("no mangling for this type implemented yet");
146                 break;
147         }
148         panic("invalid type encountered while mangling");
149 }
150
151
152 /**
153  * Mangles an entity linker (ld) name for win32 usage.
154  *
155  * @param ent          the entity to be mangled
156  * @param declaration  the declaration
157  */
158 ident *create_name_win32(entity_t *entity)
159 {
160         ident *id = new_id_from_str(entity->base.symbol->string);
161
162         if (entity->kind == ENTITY_FUNCTION) {
163                 if (entity->declaration.type->function.linkage == sym_stdcall) {
164                         char     buf[16];
165                         ir_type *irtype = get_ir_type(entity->declaration.type);
166                         size_t   size   = 0;
167                         for (int i = get_method_n_params(irtype) - 1; i >= 0; --i) {
168                                 size += get_type_size_bytes(get_method_param_type(irtype, i));
169                         }
170
171                         snprintf(buf, sizeof(buf), "@%d", size);
172                         return id_mangle3("_", id, buf);
173                 }
174         } else {
175                 /* always add an underscore in win32 */
176                 id = id_mangle(id_underscore, id);
177         }
178
179         assert(is_declaration(entity));
180         decl_modifiers_t decl_modifiers = entity->declaration.modifiers;
181         if (decl_modifiers & DM_DLLIMPORT) {
182                 /* add prefix for imported symbols */
183                 id = id_mangle(id_imp, id);
184         }
185         return id;
186 }
187
188 static void mangle_entity(entity_t *entity)
189 {
190         assert(obstack_object_size(&obst) == 0);
191         obstack_printf(&obst, "_Z");
192
193         /* TODO: mangle scope */
194
195         symbol_t *symbol = entity->base.symbol;
196         obstack_printf(&obst, "%u%s", strlen(symbol->string), symbol->string);
197
198         if (entity->kind == ENTITY_FUNCTION) {
199                 mangle_type(entity->declaration.type);
200         }
201 }
202
203 /**
204  * Mangles an entity linker (ld) name for Linux ELF usage.
205  *
206  * @param ent          the entity to be mangled
207  * @param declaration  the declaration
208  */
209 ident *create_name_linux_elf(entity_t *entity)
210 {
211         bool needs_mangling = false;
212
213         if (entity->kind == ENTITY_FUNCTION && (c_mode & _CXX)) {
214                 symbol_t *linkage = entity->declaration.type->function.linkage;
215
216                 if (linkage == NULL) {
217                         needs_mangling = true;
218                 } else if (linkage != sym_C) {
219                         errorf(&entity->base.source_position,
220                                "Unknown linkage type \"%Y\" found\n", linkage);
221                 }
222         }
223
224         if (needs_mangling) {
225                 mangle_entity(entity);
226                 obstack_1grow(&obst, '\0');
227                 char *str = obstack_finish(&obst);
228
229                 ident *id = new_id_from_str(str);
230                 obstack_free(&obst, str);
231
232                 return id;
233         }
234
235         return new_id_from_str(entity->base.symbol->string);
236 }
237
238 /**
239  * Mangles an entity linker (ld) name for Mach-O usage.
240  *
241  * @param ent          the entity to be mangled
242  * @param declaration  the declaration
243  */
244 ident *create_name_macho(entity_t *entity)
245 {
246         ident *id = new_id_from_str(entity->base.symbol->string);
247         return id_mangle(id_underscore, id);
248 }
249
250 void init_mangle(void)
251 {
252         id_underscore = new_id_from_chars("_", 1);
253         id_imp        = new_id_from_chars("__imp_", 6);
254         sym_C         = symbol_table_insert("C");
255         sym_stdcall   = symbol_table_insert("stdcall");
256
257         obstack_init(&obst);
258 }
259
260 void exit_mangle(void)
261 {
262         obstack_free(&obst, NULL);
263 }