about summary refs log tree commit diff stats
path: root/wrapperhelper/src
diff options
context:
space:
mode:
authorrajdakin <rajdakin@gmail.com>2024-09-08 22:26:35 +0200
committerGitHub <noreply@github.com>2024-09-08 22:26:35 +0200
commit26b7a49d8279984a01ea5dc19b05cefff0693e35 (patch)
tree3ff9f05a2fb11b0e21ad7cf1829c5a9992ce7728 /wrapperhelper/src
parentfa8a5a20336a64e5b53ea9a151c23941073381c4 (diff)
downloadbox64-26b7a49d8279984a01ea5dc19b05cefff0693e35.tar.gz
box64-26b7a49d8279984a01ea5dc19b05cefff0693e35.zip
[WRAPPERHELPER] Fixed preprocessor logic, moved type validation to machine (#1808)
Diffstat (limited to 'wrapperhelper/src')
-rw-r--r--wrapperhelper/src/generator.c3
-rw-r--r--wrapperhelper/src/lang.c98
-rw-r--r--wrapperhelper/src/lang.h8
-rw-r--r--wrapperhelper/src/machine.c214
-rw-r--r--wrapperhelper/src/machine.h4
-rw-r--r--wrapperhelper/src/parse.c244
-rw-r--r--wrapperhelper/src/preproc.c29
7 files changed, 302 insertions, 298 deletions
diff --git a/wrapperhelper/src/generator.c b/wrapperhelper/src/generator.c
index e162d0e4..63102f48 100644
--- a/wrapperhelper/src/generator.c
+++ b/wrapperhelper/src/generator.c
@@ -626,7 +626,8 @@ VECTOR(references) *references_from_file(const char *filename, FILE *f) {
 			tok = pre_next_token(prep, 0);
 			if (tok.tokt == PPTOK_NUM) {
 				num_constant_t cst;
-				if (!num_constant_convert(tok.tokv.str, &cst)) {
+				// Assume target is 64 bits (box64)
+				if (!num_constant_convert(tok.tokv.str, &cst, 0)) {
 					printf("Error: invalid reference file: invalid DATA line %d (num conversion)\n", lineno);
 					string_del(req.obj_name);
 					preproc_token_del(&tok);
diff --git a/wrapperhelper/src/lang.c b/wrapperhelper/src/lang.c
index ddc711fe..78cc66c1 100644
--- a/wrapperhelper/src/lang.c
+++ b/wrapperhelper/src/lang.c
@@ -394,7 +394,8 @@ void del_str2kw(void) {
 	kh_destroy(str2kw, str2kw);
 }
 
-int num_constant_convert(string_t *str, num_constant_t *cst) {
+// ptr_is_32bits is actially long_is_32bits
+int num_constant_convert(string_t *str, num_constant_t *cst, int ptr_is_32bits) {
 	if (string_len(str) == 0) return 0; // Should never happen
 #define contains(c) strchr(string_content(str), c)
 	if (contains('.')
@@ -486,10 +487,10 @@ int num_constant_convert(string_t *str, num_constant_t *cst) {
 		// If base == 10, keep the signness; in any case, try 32 bits if available else use 64 bits
 		cst->typ =
 			((suffix_type & SUFFIX_SGN) == SUFFIX_U) ?
-				((suffix_type & SUFFIX_SZ) == SUFFIX_L) ? LONG_IS_32BITS ? NCT_UINT32 : NCT_UINT64 :
+				((suffix_type & SUFFIX_SZ) == SUFFIX_L) ? ptr_is_32bits ? NCT_UINT32 : NCT_UINT64 :
 				((suffix_type & SUFFIX_SZ) == SUFFIX_LL) ? NCT_UINT64 :
 					NCT_UINT32 :
-				((suffix_type & SUFFIX_SZ) == SUFFIX_L) ? LONG_IS_32BITS ? NCT_INT32 : NCT_INT64 :
+				((suffix_type & SUFFIX_SZ) == SUFFIX_L) ? ptr_is_32bits ? NCT_INT32 : NCT_INT64 :
 				((suffix_type & SUFFIX_SZ) == SUFFIX_LL) ? NCT_INT64 :
 					NCT_INT32;
 		if (cst->typ == NCT_INT32) {
@@ -795,7 +796,6 @@ struct_t *struct_new(int is_struct, string_t *tag) {
 	return ret;
 }
 
-_Static_assert(sizeof(type_t*) == sizeof(khint64_t), "Not a 64-bits machine");
 khint_t type_t_hash(type_t *typ) {
 	switch (typ->typ) {
 	case TYPE_BUILTIN: return kh_int_hash_func(typ->val.builtin);
@@ -1043,49 +1043,7 @@ void struct_print(const struct_t *st) {
 	}
 }
 
-// TODO: per-arch array
-size_t sizeof_btt[LAST_BUILTIN + 1] = {
-	[BTT_VOID] = 0,
-	[BTT_BOOL] = 1,
-	[BTT_CHAR] = 1,
-	[BTT_SCHAR] = 1,
-	[BTT_UCHAR] = 1,
-	[BTT_SHORT] = 2,
-	[BTT_SSHORT] = 2,
-	[BTT_USHORT] = 2,
-	[BTT_INT] = 4,
-	[BTT_SINT] = 4,
-	[BTT_UINT] = 4,
-	[BTT_LONG] = LONG_IS_32BITS ? 4 : 8,
-	[BTT_SLONG] = LONG_IS_32BITS ? 4 : 8,
-	[BTT_ULONG] = LONG_IS_32BITS ? 4 : 8,
-	[BTT_LONGLONG] = 8,
-	[BTT_SLONGLONG] = 8,
-	[BTT_ULONGLONG] = 8,
-	[BTT_INT128] = 16,
-	[BTT_SINT128] = 16,
-	[BTT_UINT128] = 16,
-	[BTT_S8] = 1,
-	[BTT_U8] = 1,
-	[BTT_S16] = 2,
-	[BTT_U16] = 2,
-	[BTT_S32] = 4,
-	[BTT_U32] = 4,
-	[BTT_S64] = 8,
-	[BTT_U64] = 8,
-	[BTT_FLOAT] = 4,
-	[BTT_CFLOAT] = 8,
-	[BTT_IFLOAT] = 4,
-	[BTT_DOUBLE] = 8,
-	[BTT_CDOUBLE] = 16,
-	[BTT_IDOUBLE] = 8,
-	[BTT_LONGDOUBLE] = 16,
-	[BTT_CLONGDOUBLE] = 32,
-	[BTT_ILONGDOUBLE] = 16,
-	[BTT_VA_LIST] = LONG_IS_32BITS ? 0 : 24, // TODO
-};
-// The following assumes sizeof(unsigned long) == sizeof(void*)
-file_t *file_new(void) {
+file_t *file_new(machine_t *target) {
 	file_t *ret = malloc(sizeof *ret);
 	if (!ret) {
 		printf("Failed to create a new translation unit structure (init)\n");
@@ -1140,7 +1098,7 @@ file_t *file_new(void) {
 	// Now fill in the builtin types
 	int iret; khiter_t it;
 	for (enum type_builtin_e i = 0; i < LAST_BUILTIN + 1; ++i) {
-		type_t *t = malloc(sizeof *t);
+		type_t *t = type_new();
 		if (!t) {
 			printf("Failed to create a new translation unit structure (builtin type)\n");
 			for (; i--;) {
@@ -1155,14 +1113,11 @@ file_t *file_new(void) {
 			free(ret);
 			return NULL;
 		}
-		t->is_atomic = t->is_const = t->is_restrict = t->is_volatile = t->_internal_use = 0;
 		t->is_incomplete = (i == BTT_VOID);
-		t->converted = NULL; // Maybe should be something else?
-		t->is_validated = 1;
 		t->nrefs = 2;
 		t->typ = TYPE_BUILTIN;
 		t->val.builtin = i;
-		t->szinfo.align = t->szinfo.size = sizeof_btt[i];
+		validate_type(target, t);
 		ret->builtins[i] = t;
 		kh_put(type_set, ret->type_set, t, &iret);
 		if (iret < 0) {
@@ -1196,26 +1151,25 @@ file_t *file_new(void) {
 	char *sdup;
 #define ADD_TYPEDEF(name, btt) \
 	sdup = strdup(#name);                                                                               \
-	if (!sdup) {                                                                                        \
-		printf("Failed to create a new translation unit structure (" #name " name)\n");                 \
-		file_del(ret);                                                                                  \
-		return NULL;                                                                                    \
-	}                                                                                                   \
-	it = kh_put(type_map, ret->type_map, sdup, &iret);                                                  \
-	if (iret < 0) {                                                                                     \
-		printf("Failed to create a new translation unit structure (add " #name " typedef)\n");          \
-		free(sdup);                                                                                     \
-		file_del(ret);                                                                                  \
-		return NULL;                                                                                    \
-	} else if (iret == 0) {                                                                             \
-		printf("Failed to create a new translation unit structure (" #name " is already a typedef)\n"); \
-		free(sdup);                                                                                     \
-		file_del(ret);                                                                                  \
-		return NULL;                                                                                    \
-	}                                                                                                   \
-	kh_val(ret->type_map, it) = ret->builtins[BTT_ ## btt];                                             \
-	++ret->builtins[BTT_ ## btt]->nrefs;
-	
+		if (!sdup) {                                                                                        \
+			printf("Failed to create a new translation unit structure (" #name " name)\n");                 \
+			file_del(ret);                                                                                  \
+			return NULL;                                                                                    \
+		}                                                                                                   \
+		it = kh_put(type_map, ret->type_map, sdup, &iret);                                                  \
+		if (iret < 0) {                                                                                     \
+			printf("Failed to create a new translation unit structure (add " #name " typedef)\n");          \
+			free(sdup);                                                                                     \
+			file_del(ret);                                                                                  \
+			return NULL;                                                                                    \
+		} else if (iret == 0) {                                                                             \
+			printf("Failed to create a new translation unit structure (" #name " is already a typedef)\n"); \
+			free(sdup);                                                                                     \
+			file_del(ret);                                                                                  \
+			return NULL;                                                                                    \
+		}                                                                                                   \
+		kh_val(ret->type_map, it) = ret->builtins[BTT_ ## btt];                                             \
+		++ret->builtins[BTT_ ## btt]->nrefs;
 	ADD_TYPEDEF(__builtin_va_list, VA_LIST)
 	ADD_TYPEDEF(__int128_t, INT128)
 	ADD_TYPEDEF(__uint128_t, UINT128)
diff --git a/wrapperhelper/src/lang.h b/wrapperhelper/src/lang.h
index 682bbdda..f5807f97 100644
--- a/wrapperhelper/src/lang.h
+++ b/wrapperhelper/src/lang.h
@@ -5,10 +5,9 @@
 
 #include "cstring.h"
 #include "khash.h"
+#include "machine.h"
 #include "vector.h"
 
-#define LONG_IS_32BITS 0
-
 enum token_sym_type_e {
 	SYM_LBRACKET,
 	SYM_RBRACKET,
@@ -191,7 +190,7 @@ typedef struct num_constant_s {
 		uint64_t u64;
 	} val;
 } num_constant_t;
-int num_constant_convert(string_t *str, num_constant_t *cst);
+int num_constant_convert(string_t *str, num_constant_t *cst, int ptr_is_32bits);
 KHASH_MAP_DECLARE_STR(const_map, num_constant_t)
 
 typedef struct expr_s {
@@ -381,6 +380,7 @@ typedef struct st_member_s {
 	type_t *typ;
 	_Bool is_bitfield;
 	size_t bitfield_width;
+	// TODO: add byte_offset then check in generator against both archs for every named members
 } st_member_t;
 typedef struct struct_s {
 	string_t *tag;
@@ -421,7 +421,7 @@ typedef struct file_s {
 	khash_t(const_map) *const_map;
 	khash_t(type_set) *type_set;
 } file_t;
-file_t *file_new(void);
+file_t *file_new(machine_t *target);
 void file_del(file_t *f);
 
 extern const char *sym2str[LAST_SYM + 1];
diff --git a/wrapperhelper/src/machine.c b/wrapperhelper/src/machine.c
index 7637a5d3..d20c3e1f 100644
--- a/wrapperhelper/src/machine.c
+++ b/wrapperhelper/src/machine.c
@@ -102,6 +102,8 @@ int init_machines(size_t npaths, const char *const *extra_include_path) {
 #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
 #define CUR_MACHINE x86_64
 	machine_x86_64.size_long = 8;
+	machine_x86_64.align_valist = 8;
+	machine_x86_64.size_valist = 24;
 	INIT_PATHS
 #define DO_PATH INCR_NPATHS
 #include "machine.gen"
@@ -182,3 +184,215 @@ static void machine_del(machine_t *m) {
 void del_machines(void) {
 	machine_del(&machine_x86_64);
 }
+
+int validate_type(machine_t *target, type_t *typ) {
+	if (typ->is_validated) return 1;
+	typ->is_validated = 1;
+	if (typ->is_restrict) {
+		if (typ->typ != TYPE_PTR) {
+			printf("Error: only pointers to object types may be restrict-qualified\n");
+			return 0;
+		}
+		if (typ->val.typ->typ == TYPE_FUNCTION) {
+			printf("Error: only pointers to object types may be restrict-qualified\n");
+			return 0;
+		}
+	}
+	if (typ->is_atomic) {
+		if ((typ->typ == TYPE_ARRAY) || (typ->typ == TYPE_FUNCTION)) {
+			printf("Error: array types and function types may not be atomic-qualified\n");
+			return 0;
+		}
+	}
+	switch (typ->typ) {
+	case TYPE_BUILTIN:
+		switch (typ->val.builtin) {
+		case BTT_VOID:        typ->szinfo.align = typ->szinfo.size = 0; break;
+		case BTT_BOOL:        typ->szinfo.align = typ->szinfo.size = 1; break;
+		case BTT_CHAR:        typ->szinfo.align = typ->szinfo.size = 1; break;
+		case BTT_SCHAR:       typ->szinfo.align = typ->szinfo.size = 1; break;
+		case BTT_UCHAR:       typ->szinfo.align = typ->szinfo.size = 1; break;
+		case BTT_SHORT:       typ->szinfo.align = typ->szinfo.size = 2; break;
+		case BTT_SSHORT:      typ->szinfo.align = typ->szinfo.size = 2; break;
+		case BTT_USHORT:      typ->szinfo.align = typ->szinfo.size = 2; break;
+		case BTT_INT:         typ->szinfo.align = typ->szinfo.size = 4; break;
+		case BTT_SINT:        typ->szinfo.align = typ->szinfo.size = 4; break;
+		case BTT_UINT:        typ->szinfo.align = typ->szinfo.size = 4; break;
+		case BTT_LONG:        typ->szinfo.align = typ->szinfo.size = target->size_long; break;
+		case BTT_SLONG:       typ->szinfo.align = typ->szinfo.size = target->size_long; break;
+		case BTT_ULONG:       typ->szinfo.align = typ->szinfo.size = target->size_long; break;
+		case BTT_LONGLONG:    typ->szinfo.align = typ->szinfo.size = 8; break;
+		case BTT_SLONGLONG:   typ->szinfo.align = typ->szinfo.size = 8; break;
+		case BTT_ULONGLONG:   typ->szinfo.align = typ->szinfo.size = 8; break;
+		case BTT_INT128:      typ->szinfo.align = typ->szinfo.size = 16; break;
+		case BTT_SINT128:     typ->szinfo.align = typ->szinfo.size = 16; break;
+		case BTT_UINT128:     typ->szinfo.align = typ->szinfo.size = 16; break;
+		case BTT_S8:          typ->szinfo.align = typ->szinfo.size = 1; break;
+		case BTT_U8:          typ->szinfo.align = typ->szinfo.size = 1; break;
+		case BTT_S16:         typ->szinfo.align = typ->szinfo.size = 2; break;
+		case BTT_U16:         typ->szinfo.align = typ->szinfo.size = 2; break;
+		case BTT_S32:         typ->szinfo.align = typ->szinfo.size = 4; break;
+		case BTT_U32:         typ->szinfo.align = typ->szinfo.size = 4; break;
+		case BTT_S64:         typ->szinfo.align = typ->szinfo.size = 8; break;
+		case BTT_U64:         typ->szinfo.align = typ->szinfo.size = 8; break;
+		case BTT_FLOAT:       typ->szinfo.align = typ->szinfo.size = 4; break;
+		case BTT_CFLOAT:      typ->szinfo.align = typ->szinfo.size = 8; break;
+		case BTT_IFLOAT:      typ->szinfo.align = typ->szinfo.size = 4; break;
+		case BTT_DOUBLE:      typ->szinfo.align = typ->szinfo.size = 8; break;
+		case BTT_CDOUBLE:     typ->szinfo.align = typ->szinfo.size = 16; break;
+		case BTT_IDOUBLE:     typ->szinfo.align = typ->szinfo.size = 8; break;
+		case BTT_LONGDOUBLE:  typ->szinfo.align = typ->szinfo.size = 16; break;
+		case BTT_CLONGDOUBLE: typ->szinfo.align = typ->szinfo.size = 32; break;
+		case BTT_ILONGDOUBLE: typ->szinfo.align = typ->szinfo.size = 16; break;
+		case BTT_VA_LIST:     typ->szinfo.align = target->align_valist; typ->szinfo.size = target->size_valist; break;
+		default:
+			printf("Unknown builtin %u, cannot fill size info\n", typ->val.builtin);
+			return 0;
+		}
+		return 1;
+	case TYPE_ARRAY:
+		if (typ->val.array.typ->is_incomplete || (typ->val.array.typ->typ == TYPE_FUNCTION)) {
+			printf("Error: array types must point to complete object types\n");
+			return 0;
+		}
+		if ((typ->val.array.typ->typ == TYPE_STRUCT_UNION) && typ->val.array.typ->val.st->has_incomplete) {
+			printf("Error: array types may not (inductively) point to structures which last element is incomplete\n");
+			return 0;
+		}
+		if ((typ->is_atomic) || (typ->is_const) || (typ->is_restrict) || (typ->is_volatile)) {
+			// qualifier-type-list in array declaration is only allowed in function argument declaration under certain circumstances
+			printf("Error: array types may not be qualified\n");
+			return 0;
+		}
+		if (!validate_type(target, typ->val.array.typ)) return 0;
+		if (typ->val.array.array_sz == (size_t)-1) {
+			typ->szinfo.size = 0;
+			typ->szinfo.align = (typ->val.array.typ->szinfo.align < 16) ? 16 : typ->val.array.typ->szinfo.align;
+		} else {
+			typ->szinfo.size = typ->val.array.array_sz * typ->val.array.typ->szinfo.size;
+			typ->szinfo.align =
+				((typ->szinfo.size >= 16) && (typ->val.array.typ->szinfo.align < 16)) ?
+				16 :
+				typ->val.array.typ->szinfo.align;
+		}
+		return 1;
+	case TYPE_PTR:
+		typ->szinfo.size = target->size_long;
+		typ->szinfo.align = target->size_long;
+		return validate_type(target, typ->val.typ);
+	case TYPE_FUNCTION:
+		if ((typ->val.fun.ret->typ == TYPE_FUNCTION) || (typ->val.fun.ret->typ == TYPE_ARRAY)) {
+			printf("Error: function types may not return function or array types\n");
+			return 0;
+		}
+		if (typ->val.fun.nargs != (size_t)-1) {
+			for (size_t i = 0; i < typ->val.fun.nargs; ++i) {
+				// Adjust the argument if necessary
+				if (typ->val.fun.args[i]->typ == TYPE_ARRAY) {
+					// Adjustment to pointer
+					typ->val.fun.args[i]->typ = TYPE_PTR;
+					typ->val.fun.args[i]->val.typ = typ->val.fun.args[i]->val.array.typ;
+				} else if (typ->val.fun.args[i]->typ == TYPE_FUNCTION) {
+					// Adjustment to pointer
+					type_t *t2 = type_new_ptr(typ->val.fun.args[i]);
+					if (!t2) {
+						printf("Error: failed to adjust type of argument from function to pointer\n");
+						return 0;
+					}
+					typ->val.fun.args[i] = t2;
+				}
+				if (!validate_type(target, typ->val.fun.args[i])) return 0;
+			}
+		}
+		typ->szinfo.size = 0;
+		typ->szinfo.align = 0;
+		return validate_type(target, typ->val.fun.ret);
+	case TYPE_STRUCT_UNION: {
+		if (!typ->val.st->is_defined) return typ->is_incomplete;
+		size_t max_align = 1, cur_sz = 0, cur_bit = 0;
+		for (size_t i = 0; i < typ->val.st->nmembers; ++i) {
+			// Adjust the argument if necessary
+			st_member_t *mem = &typ->val.st->members[i];
+			if (mem->typ->typ == TYPE_FUNCTION) {
+				printf("Error: structures may not contain function members\n");
+				return 0;
+			}
+			if (mem->typ->is_incomplete) {
+				if ((i != typ->val.st->nmembers - 1) || !typ->val.st->is_struct || (mem->typ->typ != TYPE_ARRAY)) {
+					// The last element of a structure may be a VLA
+					printf("Error: structures may not contain incomplete members\n");
+					return 0;
+				}
+				typ->val.st->has_incomplete = 1;
+			}
+			if (!validate_type(target, mem->typ)) return 0;
+			if (!typ->val.st->is_struct && (mem->typ->typ == TYPE_STRUCT_UNION)) {
+				typ->val.st->has_incomplete |= mem->typ->val.st->has_incomplete;
+			}
+			if (mem->is_bitfield) {
+				if (!typ->val.st->is_struct) {
+					printf("Error: TODO: bitfield in union\n");
+					return 0;
+				}
+				if (mem->typ->is_atomic) {
+					printf("Error: atomic bitfields are not supported\n");
+					return 0;
+				}
+				if (mem->typ->typ != TYPE_BUILTIN) {
+					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)) {
+					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);
+					return 0;
+				}
+				if (mem->bitfield_width) {
+					if (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) {
+						cur_bit += mem->bitfield_width;
+						cur_sz += cur_bit / 8;
+						cur_bit %= 8;
+					} else {
+						cur_sz = ((cur_sz + mem->typ->szinfo.align - 1) & ~(mem->typ->szinfo.align - 1)) + (mem->bitfield_width / 8);
+						cur_bit = mem->bitfield_width % 8;
+					}
+				} else {
+					if (max_align < mem->typ->szinfo.align) max_align = mem->typ->szinfo.align;
+					cur_sz = ((cur_sz + mem->typ->szinfo.align - 1) & ~(mem->typ->szinfo.align - 1)) + mem->typ->szinfo.size;
+					printf("Error: TODO: unnamed zero-width bitfield member\n");
+					return 0;
+				}
+			} else {
+				if (max_align < mem->typ->szinfo.align) max_align = mem->typ->szinfo.align;
+				if (typ->val.st->is_struct) {
+					if (cur_bit) {
+						cur_bit = 0;
+						++cur_sz;
+					}
+					cur_sz = ((cur_sz + mem->typ->szinfo.align - 1) & ~(mem->typ->szinfo.align - 1)) + mem->typ->szinfo.size;
+				} else {
+					if (cur_sz < mem->typ->szinfo.size) cur_sz = mem->typ->szinfo.size;
+				}
+			}
+		}
+		if (cur_bit) {
+			cur_bit = 0;
+			++cur_sz;
+		}
+		typ->szinfo.align = max_align;
+		typ->szinfo.size = (cur_sz + max_align - 1) & ~(max_align - 1);
+		return 1; }
+	case TYPE_ENUM:
+		if (typ->val.typ->typ != TYPE_BUILTIN) return 0;
+		typ->szinfo = typ->val.typ->szinfo;
+		return 1;
+	}
+	return 0;
+}
diff --git a/wrapperhelper/src/machine.h b/wrapperhelper/src/machine.h
index 0f850fef..5570a4af 100644
--- a/wrapperhelper/src/machine.h
+++ b/wrapperhelper/src/machine.h
@@ -8,6 +8,7 @@
 #include "vector.h"
 
 struct macro_s; // preproc_private.h
+struct type_s;  // lang.h
 
 typedef struct machine_s {
 	// Preprocessor
@@ -20,6 +21,7 @@ typedef struct machine_s {
 	
 	// Parsing
 	size_t size_long;
+	size_t align_valist, size_valist;
 	// TODO: also have info on unnamed bitfields, etc
 } machine_t;
 
@@ -30,4 +32,6 @@ extern machine_t machine_x86_64;
 int init_machines(size_t npaths, const char *const *extra_include_path);
 void del_machines(void);
 
+int validate_type(machine_t *target, struct type_s *typ);
+
 #endif // MACHINE_H
diff --git a/wrapperhelper/src/parse.c b/wrapperhelper/src/parse.c
index 379df988..8b56cb15 100644
--- a/wrapperhelper/src/parse.c
+++ b/wrapperhelper/src/parse.c
@@ -79,179 +79,10 @@ VECTOR_IMPL_STATIC(size_t, (void))
 #define VALIDATION_DECL 1
 #define VALIDATION_LAST_DECL 2
 #define VALIDATION_FUN 3
-// Assumes sizeof(void*) == sizeof(unsigned long)
-static int validate_type(type_t *typ, type_t *(*builtins)[LAST_BUILTIN + 1]) {
-	if (typ->is_validated) return 1;
-	typ->is_validated = 1;
-	if (typ->is_restrict) {
-		if (typ->typ != TYPE_PTR) {
-			printf("Error: only pointers to object types may be restrict-qualified\n");
-			return 0;
-		}
-		if (typ->val.typ->typ == TYPE_FUNCTION) {
-			printf("Error: only pointers to object types may be restrict-qualified\n");
-			return 0;
-		}
-	}
-	if (typ->is_atomic) {
-		if ((typ->typ == TYPE_ARRAY) || (typ->typ == TYPE_FUNCTION)) {
-			printf("Error: array types and function types may not be atomic-qualified\n");
-			return 0;
-		}
-	}
-	switch (typ->typ) {
-	case TYPE_BUILTIN:
-		typ->szinfo = (*builtins)[typ->val.builtin]->szinfo;
-		return 1;
-	case TYPE_ARRAY:
-		if (typ->val.array.typ->is_incomplete || (typ->val.array.typ->typ == TYPE_FUNCTION)) {
-			printf("Error: array types must point to complete object types\n");
-			return 0;
-		}
-		if ((typ->val.array.typ->typ == TYPE_STRUCT_UNION) && typ->val.array.typ->val.st->has_incomplete) {
-			printf("Error: array types may not (inductively) point to structures which last element is incomplete\n");
-			return 0;
-		}
-		if ((typ->is_atomic) || (typ->is_const) || (typ->is_restrict) || (typ->is_volatile)) {
-			// qualifier-type-list in array declaration is only allowed in function argument declaration under certain circumstances
-			printf("Error: array types may not be qualified\n");
-			return 0;
-		}
-		if (!validate_type(typ->val.array.typ, builtins)) return 0;
-		if (typ->val.array.array_sz == (size_t)-1) {
-			typ->szinfo.size = 0;
-			typ->szinfo.align = (typ->val.array.typ->szinfo.align < 16) ? 16 : typ->val.array.typ->szinfo.align;
-		} else {
-			typ->szinfo.size = typ->val.array.array_sz * typ->val.array.typ->szinfo.size;
-			typ->szinfo.align =
-				((typ->szinfo.size >= 16) && (typ->val.array.typ->szinfo.align < 16)) ?
-				16 :
-				typ->val.array.typ->szinfo.align;
-		}
-		return 1;
-	case TYPE_PTR:
-		typ->szinfo.size = LONG_IS_32BITS ? 4 : 8;
-		typ->szinfo.align = LONG_IS_32BITS ? 4 : 8;
-		return validate_type(typ->val.typ, builtins);
-	case TYPE_FUNCTION:
-		if ((typ->val.fun.ret->typ == TYPE_FUNCTION) || (typ->val.fun.ret->typ == TYPE_ARRAY)) {
-			printf("Error: function types may not return function or array types\n");
-			return 0;
-		}
-		if (typ->val.fun.nargs != (size_t)-1) {
-			for (size_t i = 0; i < typ->val.fun.nargs; ++i) {
-				// Adjust the argument if necessary
-				if (typ->val.fun.args[i]->typ == TYPE_ARRAY) {
-					// Adjustment to pointer
-					typ->val.fun.args[i]->typ = TYPE_PTR;
-					typ->val.fun.args[i]->val.typ = typ->val.fun.args[i]->val.array.typ;
-				} else if (typ->val.fun.args[i]->typ == TYPE_FUNCTION) {
-					// Adjustment to pointer
-					type_t *t2 = type_new_ptr(typ->val.fun.args[i]);
-					if (!t2) {
-						printf("Error: failed to adjust type of argument from function to pointer\n");
-						return 0;
-					}
-					typ->val.fun.args[i] = t2;
-				}
-				if (!validate_type(typ->val.fun.args[i], builtins)) return 0;
-			}
-		}
-		typ->szinfo.size = 0;
-		typ->szinfo.align = 0;
-		return validate_type(typ->val.fun.ret, builtins);
-	case TYPE_STRUCT_UNION: {
-		if (!typ->val.st->is_defined) return typ->is_incomplete;
-		size_t max_align = 1, cur_sz = 0, cur_bit = 0;
-		for (size_t i = 0; i < typ->val.st->nmembers; ++i) {
-			// Adjust the argument if necessary
-			st_member_t *mem = &typ->val.st->members[i];
-			if (mem->typ->typ == TYPE_FUNCTION) {
-				printf("Error: structures may not contain function members\n");
-				return 0;
-			}
-			if (mem->typ->is_incomplete) {
-				if ((i != typ->val.st->nmembers - 1) || !typ->val.st->is_struct || (mem->typ->typ != TYPE_ARRAY)) {
-					// The last element of a structure may be a VLA
-					printf("Error: structures may not contain incomplete members\n");
-					return 0;
-				}
-				typ->val.st->has_incomplete = 1;
-			}
-			if (!validate_type(mem->typ, builtins)) return 0;
-			if (!typ->val.st->is_struct && (mem->typ->typ == TYPE_STRUCT_UNION)) {
-				typ->val.st->has_incomplete |= mem->typ->val.st->has_incomplete;
-			}
-			if (mem->is_bitfield) {
-				if (!typ->val.st->is_struct) {
-					printf("Error: TODO: bitfield in union\n");
-					return 0;
-				}
-				if (mem->typ->is_atomic) {
-					printf("Error: atomic bitfields are not supported\n");
-					return 0;
-				}
-				if (mem->typ->typ != TYPE_BUILTIN) {
-					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)) {
-					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);
-					return 0;
-				}
-				if (mem->bitfield_width) {
-					if (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) {
-						cur_bit += mem->bitfield_width;
-						cur_sz += cur_bit / 8;
-						cur_bit %= 8;
-					} else {
-						cur_sz = ((cur_sz + mem->typ->szinfo.align - 1) & ~(mem->typ->szinfo.align - 1)) + (mem->bitfield_width / 8);
-						cur_bit = mem->bitfield_width % 8;
-					}
-				} else {
-					if (max_align < mem->typ->szinfo.align) max_align = mem->typ->szinfo.align;
-					cur_sz = ((cur_sz + mem->typ->szinfo.align - 1) & ~(mem->typ->szinfo.align - 1)) + mem->typ->szinfo.size;
-					printf("Error: TODO: unnamed zero-width bitfield member\n");
-					return 0;
-				}
-			} else {
-				if (max_align < mem->typ->szinfo.align) max_align = mem->typ->szinfo.align;
-				if (typ->val.st->is_struct) {
-					if (cur_bit) {
-						cur_bit = 0;
-						++cur_sz;
-					}
-					cur_sz = ((cur_sz + mem->typ->szinfo.align - 1) & ~(mem->typ->szinfo.align - 1)) + mem->typ->szinfo.size;
-				} else {
-					if (cur_sz < mem->typ->szinfo.size) cur_sz = mem->typ->szinfo.size;
-				}
-			}
-		}
-		if (cur_bit) {
-			cur_bit = 0;
-			++cur_sz;
-		}
-		typ->szinfo.align = max_align;
-		typ->szinfo.size = (cur_sz + max_align - 1) & ~(max_align - 1);
-		return 1; }
-	case TYPE_ENUM:
-		if (typ->val.typ->typ != TYPE_BUILTIN) return 0;
-		typ->szinfo = typ->val.typ->szinfo;
-		return 1;
-	}
-	return 0;
-}
-static int validate_storage_type(enum decl_storage storage, type_t *(*builtins)[LAST_BUILTIN + 1], type_t *typ, enum token_sym_type_e sym) {
+static int validate_storage_type(machine_t *target, enum decl_storage storage,
+                                 type_t *typ, enum token_sym_type_e sym) {
 	// We may still do adjustments here
-	if (!validate_type(typ, builtins)) return 0;
+	if (!validate_type(target, typ)) return 0;
 	if (typ->typ == TYPE_FUNCTION) {
 		if ((storage == STORAGE_TLS) || (storage == STORAGE_TLS_EXTERN) || (storage == STORAGE_TLS_STATIC)) {
 			printf("Error: functions cannot be thread local\n");
@@ -459,12 +290,12 @@ struct parse_declarator_dest_s {
 #define PDECL_TYPE_SET ((is_init && is_list) ? dest->f->type_set : (!is_init && is_list) ? dest->structms.type_set : dest->argt.type_set)
 #define PDECL_BUILTINS ((is_init && is_list) ? &dest->f->builtins : (!is_init && is_list) ? dest->structms.builtins : dest->argt.builtins)
 #define PDECL_CONST_MAP ((is_init && is_list) ? dest->f->const_map : (!is_init && is_list) ? dest->structms.const_map : dest->argt.const_map)
-static int parse_declarator(struct parse_declarator_dest_s *dest, preproc_t *prep, proc_token_t *tok, enum decl_storage storage, enum fun_spec fspec,
-      type_t *base_type, int is_init, int is_list, int allow_decl, int allow_abstract);
+static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *dest, preproc_t *prep, proc_token_t *tok, enum decl_storage storage,
+      enum fun_spec fspec, type_t *base_type, int is_init, int is_list, int allow_decl, int allow_abstract);
 
 // declaration-specifier with storage != NULL
 // specifier-qualifier-list + static_assert-declaration with storage == NULL
-static int parse_declaration_specifier(khash_t(struct_map) *struct_map, khash_t(type_map) *type_map, khash_t(type_map) *enum_map,
+static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *struct_map, khash_t(type_map) *type_map, khash_t(type_map) *enum_map,
         type_t *(*builtins)[LAST_BUILTIN + 1], khash_t(const_map) *const_map,
         khash_t(type_set) *type_set, preproc_t *prep, proc_token_t *tok, enum decl_storage *storage, enum fun_spec *fspec, enum decl_spec *spec, type_t *typ);
 
@@ -584,17 +415,17 @@ static int is_type_spec_qual_kw(enum token_keyword_type_e kw) {
 #define IS_BEGIN_TYPE_NAME \
 	(((tok->tokt == PTOK_KEYWORD) && is_type_spec_qual_kw(tok->tokv.kw)) || \
 	 ((tok->tokt == PTOK_IDENT) && ((it = kh_get(type_map, type_map, string_content(tok->tokv.str))) != kh_end(type_map))))
-static int parse_type_name(khash_t(struct_map) *struct_map, khash_t(type_map) *type_map, khash_t(type_map) *enum_map,
+static int parse_type_name(machine_t *target, khash_t(struct_map) *struct_map, khash_t(type_map) *type_map, khash_t(type_map) *enum_map,
         type_t *(*builtins)[LAST_BUILTIN + 1], khash_t(const_map) *const_map,
         khash_t(type_set) *type_set, preproc_t *prep, proc_token_t *tok, enum token_sym_type_e end_sym, type_t **typ) {
 	enum decl_spec spec = SPEC_NONE;
-	if (!parse_declaration_specifier(struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, NULL, NULL, &spec, *typ)) {
+	if (!parse_declaration_specifier(target, struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, NULL, NULL, &spec, *typ)) {
 		type_del(*typ);
 		goto failed;
 	}
 	*typ = type_try_merge(*typ, type_set);
 	if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == end_sym)) {
-		return validate_type(*typ, builtins);
+		return validate_type(target, *typ);
 	}
 	struct parse_declarator_dest_s dest2;
 	dest2.argt.dest = NULL;
@@ -604,7 +435,7 @@ static int parse_type_name(khash_t(struct_map) *struct_map, khash_t(type_map) *t
 	dest2.argt.type_set = type_set;
 	dest2.argt.builtins = builtins;
 	dest2.argt.const_map = const_map;
-	if (!parse_declarator(&dest2, prep, tok, STORAGE_NONE, FSPEC_NONE, *typ, 0, 0, 0, 1)) {
+	if (!parse_declarator(target, &dest2, prep, tok, STORAGE_NONE, FSPEC_NONE, *typ, 0, 0, 0, 1)) {
 		// Token is deleted
 		type_del(*typ);
 		goto failed;
@@ -622,13 +453,13 @@ static int parse_type_name(khash_t(struct_map) *struct_map, khash_t(type_map) *t
 	}
 	*typ = dest2.argt.dest;
 	*typ = type_try_merge(*typ, type_set);
-	return validate_type(*typ, builtins);
+	return validate_type(target, *typ);
 	
 failed:
 	return 0;
 }
 
-static expr_t *parse_expression(khash_t(struct_map) *struct_map, khash_t(type_map) *type_map, khash_t(type_map) *enum_map,
+static expr_t *parse_expression(machine_t *target, khash_t(struct_map) *struct_map, khash_t(type_map) *type_map, khash_t(type_map) *enum_map,
         type_t *(*builtins)[LAST_BUILTIN + 1], khash_t(const_map) *const_map,
         khash_t(type_set) *type_set, preproc_t *prep, proc_token_t *tok, int expr_level) {
 	// Note that expr_level >= 1; expr_level = 0 doesn't appear in the grammar
@@ -684,7 +515,7 @@ expr_new_token:
 			goto failed;
 		}
 		e->typ = ETY_CONST;
-		if (!num_constant_convert(tok->tokv.str, &e->val.cst)) {
+		if (!num_constant_convert(tok->tokv.str, &e->val.cst, target->size_long == 4)) {
 			string_del(tok->tokv.str);
 			goto failed;
 		}
@@ -919,7 +750,7 @@ expr_new_token:
 				proc_token_del(tok);
 				goto failed;
 			}
-			if (!parse_type_name(struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, SYM_RPAREN, &typ)) {
+			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) {
@@ -1032,7 +863,7 @@ expr_new_token:
 					proc_token_del(tok);
 					goto failed;
 				}
-				if (!parse_type_name(struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, SYM_RPAREN, &typ)) {
+				if (!parse_type_name(target, struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, SYM_RPAREN, &typ)) {
 					type_del(typ);
 					proc_token_del(tok);
 					goto failed;
@@ -1525,7 +1356,7 @@ static int eval_expression(expr_t *e, khash_t(const_map) *const_map, num_constan
 
 // declaration-specifier with storage != NULL
 // specifier-qualifier-list + static_assert-declaration with storage == NULL
-static int parse_declaration_specifier(khash_t(struct_map) *struct_map, khash_t(type_map) *type_map, khash_t(type_map) *enum_map,
+static int parse_declaration_specifier(machine_t *target, khash_t(struct_map) *struct_map, khash_t(type_map) *type_map, khash_t(type_map) *enum_map,
         type_t *(*builtins)[LAST_BUILTIN + 1], khash_t(const_map) *const_map,
         khash_t(type_set) *type_set, preproc_t *prep, proc_token_t *tok, enum decl_storage *storage,
         enum fun_spec *fspec, enum decl_spec *spec, type_t *typ) {
@@ -1540,7 +1371,7 @@ static int parse_declaration_specifier(khash_t(struct_map) *struct_map, khash_t(
 		}
 		// Empty destructor
 		*tok = proc_next_token(prep);
-		expr_t *e = parse_expression(struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, 14);
+		expr_t *e = parse_expression(target, struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, 14);
 		if (!e) {
 			goto failed;
 		}
@@ -2010,7 +1841,8 @@ parse_cur_token_decl:
 			*tok = proc_next_token(prep);
 			while (!proc_token_isend(tok) && ((tok->tokt != PTOK_SYM) || (tok->tokv.sym != SYM_RBRACKET))) {
 				enum decl_spec spec2 = SPEC_NONE;
-				if (!parse_declaration_specifier(struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, NULL, NULL, &spec2, typ2)) {
+				if (!parse_declaration_specifier(target, struct_map, type_map, enum_map, builtins,
+				                                 const_map, type_set, prep, tok, NULL, NULL, &spec2, typ2)) {
 					vector_del(st_members, members);
 					type_del(typ2);
 					goto failed;
@@ -2057,7 +1889,7 @@ parse_cur_token_decl:
 				dest2.structms.builtins = builtins;
 				dest2.structms.const_map = const_map;
 				dest2.structms.dest = members;
-				if (!parse_declarator(&dest2, prep, tok, STORAGE_NONE, FSPEC_NONE, typ2, 0, 1, 1, 1)) {
+				if (!parse_declarator(target, &dest2, prep, tok, STORAGE_NONE, FSPEC_NONE, typ2, 0, 1, 1, 1)) {
 					printf("Error parsing struct-declarator-list\n");
 					vector_del(st_members, members);
 					type_del(typ2);
@@ -2215,7 +2047,7 @@ parse_cur_token_decl:
 			} else if ((tok->tokt == PTOK_SYM) && (tok->tokv.sym == SYM_EQ)) {
 				// Empty destructor
 				*tok = proc_next_token(prep);
-				expr_t *e = parse_expression(struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, 14);
+				expr_t *e = parse_expression(target, struct_map, type_map, enum_map, builtins, const_map, type_set, prep, tok, 14);
 				if (!e) {
 					goto failed;
 				}
@@ -2330,7 +2162,7 @@ parse_cur_token_decl:
 			typ->val.typ = new_typ->val.typ = (*builtins)[btt];
 			typ->val.typ->nrefs += 2;
 			new_typ = type_try_merge(new_typ, type_set);
-			validate_type(new_typ, builtins); // Assume it returns 1
+			validate_type(target, new_typ); // Assume it returns 1
 			kh_val(enum_map, it) = new_typ;
 		} else {
 			typ->typ = TYPE_ENUM;
@@ -2366,8 +2198,8 @@ failed:
 	return 0;
 }
 
-static int parse_declarator(struct parse_declarator_dest_s *dest, preproc_t *prep, proc_token_t *tok, enum decl_storage storage, enum fun_spec fspec,
-      type_t *base_type, int is_init, int is_list, int allow_decl, int allow_abstract) {
+static int parse_declarator(machine_t *target, struct parse_declarator_dest_s *dest, preproc_t *prep, proc_token_t *tok, enum decl_storage storage,
+      enum fun_spec fspec, type_t *base_type, int is_init, int is_list, int allow_decl, int allow_abstract) {
 	int has_list = 0, has_ident = 0;
 	// TODO: allow_abstract and 'direct-abstract-declarator(opt) ( parameter-type-list(opt) )'
 	
@@ -2476,8 +2308,8 @@ static int parse_declarator(struct parse_declarator_dest_s *dest, preproc_t *pre
 							}
 							enum decl_storage storage2 = STORAGE_NONE;
 							enum decl_spec spec2 = SPEC_NONE;
-							if (!parse_declaration_specifier(PDECL_STRUCT_MAP, PDECL_TYPE_MAP, PDECL_ENUM_MAP, PDECL_BUILTINS,
-							         PDECL_CONST_MAP, PDECL_TYPE_SET, prep, tok, &storage2, NULL, &spec2, typ2)) {
+							if (!parse_declaration_specifier(target, PDECL_STRUCT_MAP, PDECL_TYPE_MAP, PDECL_ENUM_MAP, PDECL_BUILTINS,
+							                                 PDECL_CONST_MAP, PDECL_TYPE_SET, prep, tok, &storage2, NULL, &spec2, typ2)) {
 								// Token is deleted
 								vector_del(types, args);
 								type_del(typ2);
@@ -2522,7 +2354,7 @@ static int parse_declarator(struct parse_declarator_dest_s *dest, preproc_t *pre
 							dest2.argt.type_set = PDECL_TYPE_SET;
 							dest2.argt.builtins = PDECL_BUILTINS;
 							dest2.argt.const_map = PDECL_CONST_MAP;
-							if (!parse_declarator(&dest2, prep, tok, STORAGE_NONE, FSPEC_NONE, typ2, 0, 0, 1, 1)) {
+							if (!parse_declarator(target, &dest2, prep, tok, STORAGE_NONE, FSPEC_NONE, typ2, 0, 0, 1, 1)) {
 								// Token is deleted
 								vector_del(types, args);
 								type_del(typ2);
@@ -2644,7 +2476,8 @@ static int parse_declarator(struct parse_declarator_dest_s *dest, preproc_t *pre
 				} else {
 					// Constant expression, followed by ']'
 					is_incomplete = 0;
-					expr_t *e = parse_expression(PDECL_STRUCT_MAP, PDECL_TYPE_MAP, PDECL_ENUM_MAP, PDECL_BUILTINS, PDECL_CONST_MAP, PDECL_TYPE_SET, prep, tok, 15);
+					expr_t *e = parse_expression(target, PDECL_STRUCT_MAP, PDECL_TYPE_MAP, PDECL_ENUM_MAP, PDECL_BUILTINS,
+					                             PDECL_CONST_MAP, PDECL_TYPE_SET, prep, tok, 15);
 					if (!e) {
 						goto failed;
 					}
@@ -2767,7 +2600,7 @@ static int parse_declarator(struct parse_declarator_dest_s *dest, preproc_t *pre
 				// Try to free some redundant types
 				typ = type_try_merge(typ, PDECL_TYPE_SET);
 				
-				int validation = validate_storage_type(storage, PDECL_BUILTINS, typ, tok->tokv.sym);
+				int validation = validate_storage_type(target, storage, typ, tok->tokv.sym);
 				if (!validation) {
 					// Empty destructor
 					goto failed;
@@ -2921,7 +2754,8 @@ static int parse_declarator(struct parse_declarator_dest_s *dest, preproc_t *pre
 							goto failed;
 						}
 					} else {
-						expr_t *e = parse_expression(PDECL_STRUCT_MAP, PDECL_TYPE_MAP, PDECL_ENUM_MAP, PDECL_BUILTINS, PDECL_CONST_MAP, PDECL_TYPE_SET, prep, tok, 15);
+						expr_t *e = parse_expression(target, PDECL_STRUCT_MAP, PDECL_TYPE_MAP, PDECL_ENUM_MAP, PDECL_BUILTINS,
+						                             PDECL_CONST_MAP, PDECL_TYPE_SET, prep, tok, 15);
 						if (!e) {
 							printf("Error: invalid declaration initializer\n");
 							goto failed;
@@ -2955,7 +2789,7 @@ static int parse_declarator(struct parse_declarator_dest_s *dest, preproc_t *pre
 				
 				// storage == STORAGE_NONE
 				*tok = proc_next_token(prep);
-				expr_t *e = parse_expression(dest->structms.struct_map, dest->structms.type_map, dest->structms.enum_map,
+				expr_t *e = parse_expression(target, dest->structms.struct_map, dest->structms.type_map, dest->structms.enum_map,
 				                             dest->structms.builtins, dest->structms.const_map, dest->structms.type_set,
 				                             prep, tok, 14);
 				if (!e) {
@@ -2975,7 +2809,7 @@ static int parse_declarator(struct parse_declarator_dest_s *dest, preproc_t *pre
 				}
 				expr_del(e);
 				
-				int validation = validate_storage_type(storage, PDECL_BUILTINS, typ, tok->tokv.sym);
+				int validation = validate_storage_type(target, storage, typ, tok->tokv.sym);
 				if (!validation) {
 					// Empty destructor
 					goto failed;
@@ -3146,7 +2980,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 		if (dirname) free(dirname);
 		return NULL;
 	}
-	file_t *ret = file_new();
+	file_t *ret = file_new(target);
 	if (!ret) {
 		printf("Failed to create the file structure\n");
 		preproc_del(prep);
@@ -3201,7 +3035,7 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 					goto failed;
 				}
 				tok = proc_next_token(prep);
-				if (!parse_type_name(ret->struct_map, ret->type_map, ret->enum_map, &ret->builtins, ret->const_map, ret->type_set,
+				if (!parse_type_name(target, ret->struct_map, ret->type_map, ret->enum_map, &ret->builtins, ret->const_map, ret->type_set,
 				                     prep, &tok, SYM_SEMICOLON, &typ2)) {
 					string_del(converted);
 					goto failed;
@@ -3226,16 +3060,16 @@ file_t *parse_file(machine_t *target, const char *filename, FILE *file) {
 			enum decl_storage storage = STORAGE_NONE;
 			enum fun_spec fspec = FSPEC_NONE;
 			enum decl_spec spec = SPEC_NONE;
-			if (!parse_declaration_specifier(ret->struct_map, ret->type_map, ret->enum_map, &ret->builtins, ret->const_map,
+			if (!parse_declaration_specifier(target, ret->struct_map, ret->type_map, ret->enum_map, &ret->builtins, ret->const_map,
 			                                 ret->type_set, prep, &tok, &storage, &fspec, &spec, typ)) {
 				goto failed;
 			}
 			if (spec == SPEC_NONE) continue; // Declaration was an assert, typ is unchanged
 			typ = type_try_merge(typ, ret->type_set);
 			if ((tok.tokt != PTOK_SYM) || (tok.tokv.sym != SYM_SEMICOLON)) {
-			    if (!parse_declarator(&(struct parse_declarator_dest_s){.f = ret}, prep, &tok, storage, fspec, typ, 1, 1, 1, 0)) goto failed;
+				if (!parse_declarator(target, &(struct parse_declarator_dest_s){.f = ret}, prep, &tok, storage, fspec, typ, 1, 1, 1, 0)) goto failed;
 			} else {
-				if (validate_storage_type(storage, &ret->builtins, typ, tok.tokv.sym) != VALIDATION_LAST_DECL) goto failed;
+				if (validate_storage_type(target, storage, typ, tok.tokv.sym) != VALIDATION_LAST_DECL) goto failed;
 				if (fspec != FSPEC_NONE) {
 					printf("Error: unexpected function specifier\n");
 					// Empty destructor
diff --git a/wrapperhelper/src/preproc.c b/wrapperhelper/src/preproc.c
index 00b34e4d..f402d82a 100644
--- a/wrapperhelper/src/preproc.c
+++ b/wrapperhelper/src/preproc.c
@@ -1063,7 +1063,7 @@ typedef struct preproc_eval_aux_s {
 } preproc_eval_aux_t;
 VECTOR_DECLARE_STATIC(ppeaux, preproc_eval_aux_t)
 VECTOR_IMPL_STATIC(ppeaux, (void))
-static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
+static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret, int ptr_is_32bits) {
 	VECTOR(ppeaux) *stack = vector_new_cap(ppeaux, 1);
 	if (!stack) {
 		printf("Failed to allocate #if evaluation stack vector\n");
@@ -1083,7 +1083,7 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 			// Evaluate token as an integer if st0 == 0, error otherwise
 			if (vector_last(ppeaux, stack).st0 == 0) {
 				num_constant_t cst;
-				if (!num_constant_convert(tok->tokv.str, &cst)) {
+				if (!num_constant_convert(tok->tokv.str, &cst, ptr_is_32bits)) {
 					goto eval_fail;
 				}
 				switch (cst.typ) {
@@ -1106,7 +1106,6 @@ static int64_t preproc_eval(const VECTOR(preproc) *cond, int *aux_ret) {
 		} else if ((tok->tokt == PPTOK_IDENT) || (tok->tokt == PPTOK_IDENT_UNEXP)) {
 			// Evaluate token as 0 if st0 == 0, error otherwise
 			if (vector_last(ppeaux, stack).st0 == 0) {
-				is_unsigned = 0;
 				acc = 0;
 				goto push_acc_to_st0;
 			} else {
@@ -2021,7 +2020,7 @@ check_if_depth:
 							
 							// Now we need to compute what is pointed by expanded, and increase cond_depth and ok_depth as needed
 							int st;
-							int64_t res = preproc_eval(expanded, &st);
+							int64_t res = preproc_eval(expanded, &st, src->target->size_long == 4);
 							vector_del(preproc, expanded);
 							if (!st) {
 								printf("Error: failed to evaluate #elif condition in (%s)\n", src->cur_file);
@@ -2029,7 +2028,6 @@ check_if_depth:
 								return (proc_token_t){ .tokt = PTOK_INVALID, .tokv = {.c = '\0'} };
 							}
 							if (res) {
-								vector_last(ppsource, src->prep).srcv.prep.entered_next_ok_cond = 1;
 								++vector_last(ppsource, src->prep).srcv.prep.ok_depth;
 								if (tok.tokt == PPTOK_NEWLINE) {
 									src->st = PPST_NL;
@@ -2064,8 +2062,8 @@ check_if_depth:
 							// We may enter the following block, check it
 							khiter_t it = kh_get(macros_map, src->macros_map, string_content(tok.tokv.str));
 							if (it != kh_end(src->macros_map)) {
-								ppsrc->srcv.prep.entered_next_ok_cond = 1;
 								++ppsrc->srcv.prep.ok_depth;
+								goto preproc_ignore_remaining_goto;
 							}
 							goto preproc_ignore_remaining;
 						}
@@ -2080,13 +2078,14 @@ check_if_depth:
 							// We may enter the following block, check it
 							khiter_t it = kh_get(macros_map, src->macros_map, string_content(tok.tokv.str));
 							if (it == kh_end(src->macros_map)) {
-								ppsrc->srcv.prep.entered_next_ok_cond = 1;
 								++ppsrc->srcv.prep.ok_depth;
+								goto preproc_ignore_remaining_goto;
 							}
 							goto preproc_ignore_remaining;
 						}
 					} else if (!strcmp(string_content(tok.tokv.str), "else")) {
 						// Maybe increase ok_depth if ok_depth = cond_depth - 1; also goto check_if_depth
+						// Also, we only need to goto check_if_depth if we actually update ok_depth
 						// Note that this (very naive) approach allows code such as:
 						/* #ifdef M
 						 * ... // Not preprocessed                       *** Preprocessed
@@ -2098,10 +2097,8 @@ check_if_depth:
 						 * ... // Preprocessed                           *** Not preprocessed
 						 * #endif
 						 */
-						// Forbidding this code would require another 64-bits bitfield, which is redundant, thus not implemented.
-						// Also, we only need to goto check_if_depth if we actually update ok_depth
+						// Forbidding this code would require a 256-bits bitfield, which is big, thus not implemented.
 						if ((ppsrc->srcv.prep.ok_depth == ppsrc->srcv.prep.cond_depth - 1) && !ppsrc->srcv.prep.entered_next_ok_cond) {
-							vector_last(ppsource, src->prep).srcv.prep.entered_next_ok_cond = 1;
 							++ppsrc->srcv.prep.ok_depth;
 							goto preproc_ignore_remaining_goto;
 						} else goto preproc_ignore_remaining;
@@ -2852,11 +2849,10 @@ start_cur_token:
 							printf("Invalid pragma wrappers explicit_simple directive, skipping until EOL\n");
 							goto preproc_hash_err;
 						}
-						string_t *id = tok.tokv.str;
 						src->st = PPST_PRAGMA_EXPLICIT;
 						ret.tokt = PTOK_PRAGMA;
 						ret.tokv.pragma.typ = PRAGMA_EXPLICIT_CONV;
-						ret.tokv.pragma.val = id;
+						ret.tokv.pragma.val = tok.tokv.str;
 						return ret;
 					} else {
 						printf("Unknown pragma wrappers directive '%s', skipping until EOL\n", string_content(tok.tokv.str));
@@ -2919,7 +2915,7 @@ start_cur_token:
 				
 				// Now we need to compute what is pointed by expanded, and increase cond_depth and ok_depth as needed
 				int st;
-				int64_t res = preproc_eval(expanded, &st);
+				int64_t res = preproc_eval(expanded, &st, src->target->size_long == 4);
 				vector_del(preproc, expanded);
 				if (!st) {
 					printf("Error: failed to evaluate #if condition (%s)\n", src->cur_file);
@@ -2930,7 +2926,6 @@ start_cur_token:
 				}
 				++vector_last(ppsource, src->prep).srcv.prep.cond_depth;
 				if (res) {
-					vector_last(ppsource, src->prep).srcv.prep.entered_next_ok_cond = 1;
 					++vector_last(ppsource, src->prep).srcv.prep.ok_depth;
 					if (tok.tokt == PPTOK_NEWLINE) goto check_next_token;
 					else goto start_cur_token;
@@ -2963,7 +2958,6 @@ start_cur_token:
 				// TODO: check iret, error if needed
 				++vector_last(ppsource, src->prep).srcv.prep.cond_depth;
 				if (it != kh_end(src->macros_map)) {
-					vector_last(ppsource, src->prep).srcv.prep.entered_next_ok_cond = 1;
 					++vector_last(ppsource, src->prep).srcv.prep.ok_depth;
 					goto preproc_hash_err;
 				} else {
@@ -2994,7 +2988,6 @@ start_cur_token:
 				// TODO: check iret, error if needed
 				++vector_last(ppsource, src->prep).srcv.prep.cond_depth;
 				if (it == kh_end(src->macros_map)) {
-					vector_last(ppsource, src->prep).srcv.prep.entered_next_ok_cond = 1;
 					++vector_last(ppsource, src->prep).srcv.prep.ok_depth;
 					goto preproc_hash_err;
 				} else {
@@ -3008,6 +3001,7 @@ start_cur_token:
 					goto preproc_hash_err;
 				}
 				if (vector_last(ppsource, src->prep).srcv.prep.ok_depth) {
+					vector_last(ppsource, src->prep).srcv.prep.entered_next_ok_cond = 1;
 					--vector_last(ppsource, src->prep).srcv.prep.ok_depth;
 					goto preproc_hash_err_goto;
 				} else {
@@ -3033,6 +3027,7 @@ start_cur_token:
 				// We don't care about iret(?)
 				// TODO: check iret, error if needed
 				if (vector_last(ppsource, src->prep).srcv.prep.ok_depth) {
+					vector_last(ppsource, src->prep).srcv.prep.entered_next_ok_cond = 1;
 					--vector_last(ppsource, src->prep).srcv.prep.ok_depth;
 					goto preproc_hash_err_goto;
 				} else {
@@ -3058,6 +3053,7 @@ start_cur_token:
 				// We don't care about iret(?)
 				// TODO: check iret, error if needed
 				if (vector_last(ppsource, src->prep).srcv.prep.ok_depth) {
+					vector_last(ppsource, src->prep).srcv.prep.entered_next_ok_cond = 1;
 					--vector_last(ppsource, src->prep).srcv.prep.ok_depth;
 					goto preproc_hash_err_goto;
 				} else {
@@ -3071,6 +3067,7 @@ start_cur_token:
 					goto preproc_hash_err;
 				}
 				if (vector_last(ppsource, src->prep).srcv.prep.ok_depth) {
+					// We can safely ignore setting entered_next_ok since two #else is illegal (though this parser doesn't actually detect this)
 					--vector_last(ppsource, src->prep).srcv.prep.ok_depth;
 					goto preproc_hash_err_goto;
 				} else {