about summary refs log tree commit diff stats
path: root/wrapperhelper/src
diff options
context:
space:
mode:
authorrajdakin <rajdakin@gmail.com>2024-09-20 17:06:25 +0200
committerGitHub <noreply@github.com>2024-09-20 17:06:25 +0200
commite18846fac57c6b75fe9d918034159415e73c20cd (patch)
tree68513d9973e59ec2a606ab0acd0a8b980ac105f9 /wrapperhelper/src
parent4aeb8ea1b037f8db84837f723253133277d0995b (diff)
downloadbox64-e18846fac57c6b75fe9d918034159415e73c20cd.tar.gz
box64-e18846fac57c6b75fe9d918034159415e73c20cd.zip
[WRAPPERHELPER] Fixed some bugs, added partial multiarch support (#1847)
Diffstat (limited to 'wrapperhelper/src')
-rw-r--r--wrapperhelper/src/generator.c83
-rw-r--r--wrapperhelper/src/generator.h6
-rw-r--r--wrapperhelper/src/lang.c1
-rw-r--r--wrapperhelper/src/machine.c94
-rw-r--r--wrapperhelper/src/machine.h9
-rw-r--r--wrapperhelper/src/parse.c65
6 files changed, 189 insertions, 69 deletions
diff --git a/wrapperhelper/src/generator.c b/wrapperhelper/src/generator.c
index 8839f484..cf4d1851 100644
--- a/wrapperhelper/src/generator.c
+++ b/wrapperhelper/src/generator.c
@@ -964,8 +964,12 @@ static int convert_type_post(string_t *dest, type_t *typ, string_t *obj_name) {
 	}
 }
 
-int solve_request(request_t *req, type_t *typ, khash_t(conv_map) *conv_map) {
-	if (typ->typ == TYPE_FUNCTION) {
+int solve_request(request_t *req, type_t *emu_typ, type_t *target_typ, khash_t(conv_map) *conv_map) {
+	if (!type_t_equal(emu_typ, target_typ)) {
+		printf("Error: TODO: %s: emulated and target types are different\n", string_content(req->obj_name));
+		return 0;
+	}
+	if (emu_typ->typ == TYPE_FUNCTION) {
 		int needs_D = 0, needs_my = req->def.fun.typ && (req->def.rty == RQT_FUN_MY), needs_2 = 0;
 		int convert_post;
 		size_t idx_conv;
@@ -974,15 +978,15 @@ int solve_request(request_t *req, type_t *typ, khash_t(conv_map) *conv_map) {
 			printf("Error: failed to create function type string\n");
 			return 0;
 		}
-		if (!convert_type(req->val.fun.typ, typ->val.fun.ret, 1, &needs_D, &needs_my, conv_map, req->obj_name)) goto fun_fail;
+		if (!convert_type(req->val.fun.typ, emu_typ->val.fun.ret, 1, &needs_D, &needs_my, conv_map, req->obj_name)) goto fun_fail;
 		idx_conv = string_len(req->val.fun.typ);
 		if (!string_add_char(req->val.fun.typ, 'F')) {
 			printf("Error: failed to add convention char\n");
 			goto fun_fail;
 		}
-		convert_post = convert_type_post(req->val.fun.typ, typ->val.fun.ret, req->obj_name);
+		convert_post = convert_type_post(req->val.fun.typ, emu_typ->val.fun.ret, req->obj_name);
 		if (!convert_post) goto fun_fail;
-		if (typ->val.fun.nargs == (size_t)-1) {
+		if (emu_typ->val.fun.nargs == (size_t)-1) {
 			printf("Warning: assuming empty specification is void specification\n");
 			if (convert_post == 1) {
 				if (!string_add_char(req->val.fun.typ, 'v')) {
@@ -990,7 +994,7 @@ int solve_request(request_t *req, type_t *typ, khash_t(conv_map) *conv_map) {
 					goto fun_fail;
 				}
 			}
-		} else if (!typ->val.fun.nargs && !typ->val.fun.has_varargs) {
+		} else if (!emu_typ->val.fun.nargs && !emu_typ->val.fun.has_varargs) {
 			if (convert_post == 1) {
 				if (!string_add_char(req->val.fun.typ, 'v')) {
 					printf("Error: failed to add void specification char\n");
@@ -998,10 +1002,10 @@ int solve_request(request_t *req, type_t *typ, khash_t(conv_map) *conv_map) {
 				}
 			}
 		} else {
-			for (size_t i = 0; i < typ->val.fun.nargs; ++i) {
-				if (!convert_type(req->val.fun.typ, typ->val.fun.args[i], 0, &needs_D, &needs_my, conv_map, req->obj_name)) goto fun_fail;
+			for (size_t i = 0; i < emu_typ->val.fun.nargs; ++i) {
+				if (!convert_type(req->val.fun.typ, emu_typ->val.fun.args[i], 0, &needs_D, &needs_my, conv_map, req->obj_name)) goto fun_fail;
 			}
-			if (typ->val.fun.has_varargs) {
+			if (emu_typ->val.fun.has_varargs) {
 				if (req->def.fun.typ
 				      && (string_len(req->def.fun.typ) == string_len(req->val.fun.typ) + 1)
 				      && !strncmp(string_content(req->def.fun.typ), string_content(req->val.fun.typ), string_len(req->val.fun.typ))
@@ -1010,13 +1014,13 @@ int solve_request(request_t *req, type_t *typ, khash_t(conv_map) *conv_map) {
 					if (!string_add_char(req->val.fun.typ, string_content(req->def.fun.typ)[string_len(req->val.fun.typ)])) {
 						printf("Error: failed to add type char '%c' for %s\n",
 							string_content(req->def.fun.typ)[string_len(req->val.fun.typ)],
-							builtin2str[typ->val.builtin]);
+							builtin2str[emu_typ->val.builtin]);
 						goto fun_fail;
 					}
 				} else {
 					needs_my = 1;
 					if (!string_add_char(req->val.fun.typ, 'V')) {
-						printf("Error: failed to add type char 'V' for %s\n", builtin2str[typ->val.builtin]);
+						printf("Error: failed to add type char 'V' for %s\n", builtin2str[emu_typ->val.builtin]);
 						goto fun_fail;
 					}
 				}
@@ -1024,8 +1028,10 @@ int solve_request(request_t *req, type_t *typ, khash_t(conv_map) *conv_map) {
 		}
 		
 	// fun_succ:
-		// Add 'E' by default
-		if (needs_my) {
+		// Add 'E' by default, unless we have the same function as before
+		if (needs_my && (req->default_comment
+		                  || (req->def.rty != RQT_FUN_MY)
+		                  || strcmp(string_content(req->def.fun.typ), string_content(req->val.fun.typ)))) {
 			if (!string_add_char_at(req->val.fun.typ, 'E', idx_conv + 1)) {
 				printf("Error: failed to add emu char\n");
 				goto fun_fail;
@@ -1064,45 +1070,62 @@ int solve_request(request_t *req, type_t *typ, khash_t(conv_map) *conv_map) {
 		return 0;
 	} else {
 		int needs_D = 0, needs_my = req->def.dat.has_size && (req->def.rty == RQT_DATAM);
-		if (is_simple_type(typ, &needs_D, &needs_my, conv_map)) {
+		if (is_simple_type(emu_typ, &needs_D, &needs_my, conv_map)) {
 			// TODO: Hmm...
 			req->val.rty = needs_my ? RQT_DATAM : req->def.rty;
 			req->val.dat.has_size = 1;
-			req->val.dat.sz = typ->szinfo.size;
+			req->val.dat.sz = emu_typ->szinfo.size;
 			req->has_val = 1;
 			return 1;
 		} else {
 			printf("Error: TODO: solve_request for data %s with non-simple type ", string_content(req->obj_name));
-			type_print(typ);
+			type_print(emu_typ);
 			printf("\n");
 			return 0;
 		}
 	}
 }
-int solve_request_map(request_t *req, khash_t(decl_map) *decl_map, khash_t(conv_map) *conv_map) {
-	khiter_t it = kh_get(decl_map, decl_map, string_content(req->obj_name));
-	if (it == kh_end(decl_map)) {
-		if (string_content(req->obj_name)[0] != '_') {
-			printf("Error: %s was not declared\n", string_content(req->obj_name));
-		}
-		return 0;
+int solve_request_map(request_t *req, khash_t(decl_map) *emu_decl_map, khash_t(decl_map) *target_decl_map, khash_t(conv_map) *conv_map) {
+	int hasemu = 0, hastarget = 0;
+	khiter_t emuit, targetit;
+	emuit = kh_get(decl_map, emu_decl_map, string_content(req->obj_name));
+	if (emuit == kh_end(emu_decl_map)) {
+		goto failed;
+	}
+	if ((kh_val(emu_decl_map, emuit)->storage == STORAGE_STATIC) || (kh_val(emu_decl_map, emuit)->storage == STORAGE_TLS_STATIC)) {
+		goto failed;
+	}
+	targetit = kh_get(decl_map, target_decl_map, string_content(req->obj_name));
+	if (targetit == kh_end(target_decl_map)) {
+		goto failed;
 	}
-	if ((kh_val(decl_map, it)->storage == STORAGE_STATIC) || (kh_val(decl_map, it)->storage == STORAGE_TLS_STATIC)) {
-		if (string_content(req->obj_name)[0] != '_') {
-			printf("Error: %s was not declared\n", string_content(req->obj_name));
+	if ((kh_val(target_decl_map, targetit)->storage == STORAGE_STATIC) || (kh_val(target_decl_map, targetit)->storage == STORAGE_TLS_STATIC)) {
+		goto failed;
+	}
+	return solve_request(req, kh_val(emu_decl_map, emuit)->typ, kh_val(target_decl_map, targetit)->typ, conv_map);
+	
+failed:
+	if (string_content(req->obj_name)[0] != '_') {
+		if (!hasemu && !hastarget) {
+			printf("Error: %s was not declared in the emulated and target architectures\n", string_content(req->obj_name));
+		} else if (!hasemu) {
+			printf("Error: %s was not declared only in the emulated architecture\n", string_content(req->obj_name));
+		} else if (!hastarget) {
+			printf("Error: %s was not declared only in the target architecture\n", string_content(req->obj_name));
+		} else {
+			printf("Error: internal error: failed but found for %s\n", string_content(req->obj_name));
 		}
-		return 0;
 	}
-	return solve_request(req, kh_val(decl_map, it)->typ, conv_map);
+	return 0;
 }
-int solve_references(VECTOR(references) *refs, khash_t(decl_map) *decl_map, khash_t(conv_map) *conv_map) {
+int solve_references(VECTOR(references) *refs, khash_t(decl_map) *emu_decl_map, khash_t(decl_map) *target_decl_map, khash_t(conv_map) *conv_map) {
 	int ret = 1;
 	int cond_depth = 0, ok_depth = 0;
 	vector_for(references, ref, refs) {
 		switch (ref->typ) {
 		case REF_REQ:
 			if (ok_depth == cond_depth) {
-				if (!solve_request_map(&ref->req, decl_map, conv_map)) ret = 0;
+				if (!solve_request_map(&ref->req, emu_decl_map, target_decl_map, conv_map)) ret = 0;
 			} else {
 				ref->req.ignored = 1;
 			}
diff --git a/wrapperhelper/src/generator.h b/wrapperhelper/src/generator.h
index 59115eb0..4d8ef120 100644
--- a/wrapperhelper/src/generator.h
+++ b/wrapperhelper/src/generator.h
@@ -57,8 +57,8 @@ void references_print_check(const VECTOR(references) *refs);
 void output_from_references(FILE *f, const VECTOR(references) *reqs);
 
 VECTOR(references) *references_from_file(const char *filename, FILE *f); // Takes ownership of f
-int solve_request(request_t *req, type_t *typ, khash_t(conv_map) *conv_map);
-int solve_request_map(request_t *req, khash_t(decl_map) *decl_map, khash_t(conv_map) *conv_map);
-int solve_references(VECTOR(references) *reqs, khash_t(decl_map) *decl_map, khash_t(conv_map) *conv_map);
+int solve_request(request_t *req, type_t *emu_typ, type_t *target_typ, khash_t(conv_map) *conv_map);
+int solve_request_map(request_t *req, khash_t(decl_map) *emu_decl_map, khash_t(decl_map) *target_decl_map, khash_t(conv_map) *conv_map);
+int solve_references(VECTOR(references) *reqs, khash_t(decl_map) *emu_decl_map, khash_t(decl_map) *target_decl_map, khash_t(conv_map) *conv_map);
 
 #endif // GENERATOR_H
diff --git a/wrapperhelper/src/lang.c b/wrapperhelper/src/lang.c
index 8aaacc36..c3b5ca19 100644
--- a/wrapperhelper/src/lang.c
+++ b/wrapperhelper/src/lang.c
@@ -783,6 +783,7 @@ struct_t *struct_new(int is_struct, string_t *tag) {
 	ret->is_struct = is_struct;
 	ret->tag = tag;
 	ret->is_defined = 0;
+	ret->is_simple = 0;
 	ret->nrefs = 1;
 	return ret;
 }
diff --git a/wrapperhelper/src/machine.c b/wrapperhelper/src/machine.c
index 9b54df7a..b89a64ae 100644
--- a/wrapperhelper/src/machine.c
+++ b/wrapperhelper/src/machine.c
@@ -6,33 +6,34 @@
 
 machine_t machine_x86_64;
 // machine_t machine_x86;
-// machine_t machine_arm64;
+machine_t machine_aarch64;
 
 #define PASTE2(a, b) a ## b
 #define PASTE(a, b) PASTE2(a, b)
 #define STRINGIFY2(a) #a
 #define STRINGIFY(a) STRINGIFY2(a)
 #define MACHINE_STR STRINGIFY(CUR_MACHINE)
+#define MACHINE_VAL PASTE(machine_, CUR_MACHINE)
 
 #define PATHS_OFFSET_PRE 2 // There are two paths that are always included before any other
 #define ADD_PATH(path) \
-	if (!(PASTE(machine_, CUR_MACHINE).include_path[failure_id] = strdup(path))) { \
-		printf("Failed to add include path to " MACHINE_STR " platform\n");        \
-		goto PASTE(failed_, PASTE(CUR_MACHINE, _paths));                           \
-	}                                                                              \
+	if (!(MACHINE_VAL.include_path[failure_id] = strdup(path))) {           \
+		printf("Failed to add include path to " MACHINE_STR " platform\n"); \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _paths));                    \
+	}                                                                       \
 	++failure_id;
 #define INIT_PATHS \
-	PASTE(machine_, CUR_MACHINE).npaths = PATHS_OFFSET_PRE + npaths + paths_offset_post;                      \
-	if (!(PASTE(machine_, CUR_MACHINE).include_path =                                                         \
-	      malloc(PASTE(machine_, CUR_MACHINE).npaths * sizeof *PASTE(machine_, CUR_MACHINE).include_path))) { \
-		printf("Failed to add include path to " MACHINE_STR " platform\n");                                   \
-		goto PASTE(failed_, PASTE(CUR_MACHINE, _nopath));                                                     \
-	}                                                                                                         \
-	failure_id = 0;                                                                                           \
-	ADD_PATH("include-override/" MACHINE_STR)                                                                 \
-	ADD_PATH("include-override/common")                                                                       \
-	while (failure_id < PATHS_OFFSET_PRE + npaths) {                                                          \
-		ADD_PATH(extra_include_path[failure_id - PATHS_OFFSET_PRE])                                           \
+	MACHINE_VAL.npaths = PATHS_OFFSET_PRE + npaths + paths_offset_post;     \
+	if (!(MACHINE_VAL.include_path =                                        \
+	      malloc(MACHINE_VAL.npaths * sizeof *MACHINE_VAL.include_path))) { \
+		printf("Failed to add include path to " MACHINE_STR " platform\n"); \
+		goto PASTE(failed_, PASTE(CUR_MACHINE, _nopath));                   \
+	}                                                                       \
+	failure_id = 0;                                                         \
+	ADD_PATH("include-override/" MACHINE_STR)                               \
+	ADD_PATH("include-override/common")                                     \
+	while (failure_id < PATHS_OFFSET_PRE + npaths) {                        \
+		ADD_PATH(extra_include_path[failure_id - PATHS_OFFSET_PRE])         \
 	}
 
 int init_machines(size_t npaths, const char *const *extra_include_path) {
@@ -49,6 +50,23 @@ int init_machines(size_t npaths, const char *const *extra_include_path) {
 	machine_x86_64.size_long = 8;
 	machine_x86_64.align_valist = 8;
 	machine_x86_64.size_valist = 24;
+	machine_x86_64.unsigned_char = 1;
+	machine_x86_64.unnamed_bitfield_aligns = 0;
+	INIT_PATHS
+#define DO_PATH ADD_PATH
+#include "machine.gen"
+#undef DO_PATH
+#undef CUR_MACHINE
+#pragma GCC diagnostic pop
+	
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
+#define CUR_MACHINE aarch64
+	machine_aarch64.size_long = 8;
+	machine_aarch64.align_valist = 8;
+	machine_aarch64.size_valist = 32;
+	machine_aarch64.unsigned_char = 0;
+	machine_aarch64.unnamed_bitfield_aligns = 1;
 	INIT_PATHS
 #define DO_PATH ADD_PATH
 #include "machine.gen"
@@ -58,6 +76,13 @@ int init_machines(size_t npaths, const char *const *extra_include_path) {
 	
 	return 1;
 	
+failed_aarch64_paths:
+	while (failure_id--) {
+		free(machine_aarch64.include_path[failure_id]);
+	}
+	free(machine_aarch64.include_path);
+failed_aarch64_nopath:
+	failure_id = machine_x86_64.npaths;
 failed_x86_64_paths:
 	while (failure_id--) {
 		free(machine_x86_64.include_path[failure_id]);
@@ -71,10 +96,19 @@ static void machine_del(machine_t *m) {
 	for (size_t path_no = m->npaths; path_no--;) {
 		free(m->include_path[path_no]);
 	}
-	free(machine_x86_64.include_path);
+	free(m->include_path);
 }
 void del_machines(void) {
 	machine_del(&machine_x86_64);
+	machine_del(&machine_aarch64);
+}
+
+machine_t *convert_machine_name(const char *archname) {
+	if (!strcmp(archname, "x86_64"))
+		return &machine_x86_64;
+	if (!strcmp(archname, "aarch64"))
+		return &machine_aarch64;
+	return NULL;
 }
 
 int validate_type(machine_t *target, type_t *typ) {
@@ -238,17 +272,33 @@ int validate_type(machine_t *target, type_t *typ) {
 					printf("Error: bitfields can only have a specific subset of types\n");
 					return 0;
 				}
-				if ((mem->typ->val.builtin != BTT_BOOL) && (mem->typ->val.builtin != BTT_INT)
-				 && (mem->typ->val.builtin != BTT_SINT) && (mem->typ->val.builtin != BTT_UINT)) {
+				if ((mem->typ->val.builtin != BTT_BOOL) && (mem->typ->val.builtin != BTT_CHAR)
+				 && (mem->typ->val.builtin != BTT_SHORT) && (mem->typ->val.builtin != BTT_INT)
+				 && (mem->typ->val.builtin != BTT_LONG) && (mem->typ->val.builtin != BTT_LONGLONG)
+				 && (mem->typ->val.builtin != BTT_SCHAR) && (mem->typ->val.builtin != BTT_UCHAR)
+				 && (mem->typ->val.builtin != BTT_SSHORT) && (mem->typ->val.builtin != BTT_USHORT)
+				 && (mem->typ->val.builtin != BTT_SINT) && (mem->typ->val.builtin != BTT_UINT)
+				 && (mem->typ->val.builtin != BTT_SLONG) && (mem->typ->val.builtin != BTT_ULONG)
+				 && (mem->typ->val.builtin != BTT_S8) && (mem->typ->val.builtin != BTT_U8)
+				 && (mem->typ->val.builtin != BTT_S16) && (mem->typ->val.builtin != BTT_U16)
+				 && (mem->typ->val.builtin != BTT_S32) && (mem->typ->val.builtin != BTT_U32)
+				 && (mem->typ->val.builtin != BTT_S64) && (mem->typ->val.builtin != BTT_U64)) {
+					// C standard: allow _Bool, (s/u)int
+					// Implementation: also allow (u/s)char, (u/s)short, (u/s)long, (u/s)long long, [u]intx_t
 					printf("Error: bitfields can only have a specific subset of types\n");
 					return 0;
 				}
-				if (!mem->name && (mem->typ->szinfo.align > max_align)) {
-					printf("Error: TODO: unnamed bitfield member with greater alignment (width=%zu)\n", mem->bitfield_width);
+				if (mem->typ->szinfo.size < mem->bitfield_width / 8) {
+					printf("Error: bitfield member %c%s%c has width (%zu) greater than its container size (%zu * 8)\n",
+						mem->name ? '\'' : '<',
+						mem->name ? string_content(mem->name) : "unnamed",
+						mem->name ? '\'' : '>',
+						mem->bitfield_width,
+						mem->typ->szinfo.size);
 					return 0;
 				}
 				if (mem->bitfield_width) {
-					if (mem->name && (max_align < mem->typ->szinfo.align)) max_align = mem->typ->szinfo.align;
+					if ((target->unnamed_bitfield_aligns || mem->name) && (max_align < mem->typ->szinfo.align)) max_align = mem->typ->szinfo.align;
 					size_t cur_block = cur_sz / mem->typ->szinfo.align;
 					size_t end_block = (cur_sz + (cur_bit + mem->bitfield_width - 1) / 8) / mem->typ->szinfo.align;
 					if (cur_block == end_block) {
diff --git a/wrapperhelper/src/machine.h b/wrapperhelper/src/machine.h
index b5a5b0ea..566f1d43 100644
--- a/wrapperhelper/src/machine.h
+++ b/wrapperhelper/src/machine.h
@@ -17,15 +17,14 @@ typedef struct machine_s {
 	// Parsing
 	size_t size_long;
 	size_t align_valist, size_valist;
-	// TODO: also have info on unnamed bitfields, etc
+	_Bool unsigned_char;
+	// Structure parsing
+	_Bool unnamed_bitfield_aligns;
 } machine_t;
 
-extern machine_t machine_x86_64;
-// extern machine_t machine_x86;
-// extern machine_t machine_arm64;
-
 int init_machines(size_t npaths, const char *const *extra_include_path);
 void del_machines(void);
+machine_t *convert_machine_name(const char *archname);
 
 int validate_type(machine_t *target, struct type_s *typ);
 
diff --git a/wrapperhelper/src/parse.c b/wrapperhelper/src/parse.c
index 4b5b90b9..0254d8df 100644
--- a/wrapperhelper/src/parse.c
+++ b/wrapperhelper/src/parse.c
@@ -735,7 +735,7 @@ expr_new_token:
 	// expr2 ::= sizeof expr2
 	// which includes expr2 ::= sizeof ( expr16 )
 	// expr2 ::= sizeof ( type-name )
-	if ((has_level == -1) && (expr_level >= 2) && (tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw = KW_SIZEOF)) {
+	if ((has_level == -1) && (expr_level >= 2) && (tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_SIZEOF)) {
 		*tok = proc_next_token(prep);
 		if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LPAREN)) {
 			struct expr_partial_op pop = {
@@ -765,8 +765,8 @@ expr_new_token:
 			if (!parse_type_name(target, struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, SYM_RPAREN, &typ)) {
 				goto failed;
 			}
-			if (!typ->is_validated || typ->is_incomplete) {
-				printf("Error: cannot get the size of an incomplete type\n");
+			if (!typ->is_validated || typ->is_incomplete || (typ->typ == TYPE_FUNCTION)) {
+				printf("Error: cannot get the size of a function or incomplete type\n");
 				type_del(typ);
 				proc_token_del(tok);
 				goto failed;
@@ -817,6 +817,51 @@ expr_new_token:
 			goto pushed_expr;
 		}
 	}
+	// expr2 ::= _Alignof ( type-name )
+	if ((has_level == -1) && (expr_level >= 2) && (tok->tokt == PTOK_KEYWORD) && (tok->tokv.kw == KW_ALIGNOF)) {
+		*tok = proc_next_token(prep);
+		if ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_LPAREN)) {
+			printf("Error: invalid _Alignof expression\n");
+			proc_token_del(tok);
+			goto failed;
+		}
+		// Empty destructor
+		*tok = proc_next_token(prep);
+		type_t *typ = type_new();
+		if (!typ) {
+			printf("Error: failed to create new type info structure\n");
+			proc_token_del(tok);
+			goto failed;
+		}
+		if (!parse_type_name(target, struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, SYM_RPAREN, &typ)) {
+			goto failed;
+		}
+		if (!typ->is_validated || typ->is_incomplete || (typ->typ == TYPE_FUNCTION)) {
+			printf("Error: cannot get the alignment of a function or incomplete type\n");
+			type_del(typ);
+			proc_token_del(tok);
+			goto failed;
+		}
+		e = malloc(sizeof *e);
+		if (!e) {
+			printf("Error: failed to create new expression atom\n");
+			type_del(typ);
+			proc_token_del(tok);
+			goto failed;
+		}
+		e->typ = ETY_CONST;
+		e->val.cst.typ = NCT_UINT64;
+		e->val.cst.val.u64 = typ->szinfo.align;
+		has_level = 2;
+		type_del(typ);
+		if (!e->val.cst.val.u64) {
+			proc_token_del(tok);
+			goto failed;
+		}
+		// Empty destructor
+		*tok = proc_next_token(prep);
+		goto expr_new_token;
+	}
 	
 	// expr0 ::= ( expr16 )
 	// expr1 ::= expr1 ( )
@@ -1327,7 +1372,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 				return 1;
 			case BTT_VOID:
 			case BTT_BOOL:
-			case BTT_CHAR:
+			case BTT_CHAR: // May be signed or unsigned depending on the machine
 			case BTT_SCHAR:
 			case BTT_SHORT:
 			case BTT_SSHORT:
@@ -1960,6 +2005,7 @@ parse_cur_token_decl:
 			}
 			
 			typ->is_incomplete = 0;
+			typ->is_validated = 0;
 			typ->val.st->has_incomplete = 0; // Filled by the validate_type step
 			typ->val.st->nmembers = vector_size(st_members, members);
 			typ->val.st->members = vector_steal(st_members, members);
@@ -3178,14 +3224,14 @@ failed0:
 	return 0;
 }
 
-int finalize_file(file_t *file) {
+static int finalize_file(machine_t *target, file_t *file) {
 #define MARK_SIMPLE(sname) \
 	it = kh_get(struct_map, file->struct_map, #sname);                          \
 	if (it != kh_end(file->struct_map)) {                                       \
 		kh_val(file->struct_map, it)->is_simple = 1;                            \
 	} else {                                                                    \
 		it = kh_get(type_map, file->type_map, #sname);                          \
-		if (it != kh_end(file->struct_map)) {                                   \
+		if (it != kh_end(file->type_map)) {                                     \
 			type_t *typ2 = kh_val(file->type_map, it);                          \
 			if (typ2->typ != TYPE_STRUCT_UNION) {                               \
 				printf("Error: invalid typedef " #sname ": not a structure\n"); \
@@ -3195,6 +3241,7 @@ int finalize_file(file_t *file) {
 		}                                                                       \
 	}
 #define SET_WEAK(converted) \
+	validate_type(target, typ);                                              \
 	typ = type_try_merge(typ, file->type_set);                               \
 	it = kh_put(conv_map, file->relaxed_type_conversion, typ, &iret);        \
 	if (iret < 0) {                                                          \
@@ -3206,8 +3253,7 @@ int finalize_file(file_t *file) {
 		type_del(typ);                                                       \
 		return 0;                                                            \
 	}                                                                        \
-	kh_val(file->relaxed_type_conversion, it) = string_new_cstr(#converted); \
-	type_del(typ);
+	kh_val(file->relaxed_type_conversion, it) = string_new_cstr(#converted);
 #define SET_WEAK_PTR_TO(to_typ, converted) \
 	it = kh_get(type_map, file->type_map, #to_typ);         \
 	if (it != kh_end(file->type_map)) {                     \
@@ -3216,6 +3262,7 @@ int finalize_file(file_t *file) {
 			printf("Failed to create type " #to_typ "*\n"); \
 			return 0;                                       \
 		}                                                   \
+		++kh_val(file->type_map, it)->nrefs;                \
 		SET_WEAK(converted)                                 \
 	}
 	
@@ -3417,7 +3464,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 success:
 	preproc_del(prep);
 	type_del(typ);
-	if (!finalize_file(ret)) {
+	if (!finalize_file(target, ret)) {
 		printf("Error: failed to add builtin aliases\n");
 		file_del(ret);
 		return NULL;