Răsfoiți Sursa

Custom entry points on Windows (DllMain; WinMain)

Ginger Bill 8 ani în urmă
părinte
comite
0d69dfcde6
9 a modificat fișierele cu 215 adăugiri și 114 ștergeri
  1. 1 1
      build.bat
  2. 2 0
      code/demo.odin
  3. 4 4
      core/mem.odin
  4. 30 19
      src/checker/decl.c
  5. 1 1
      src/checker/entity.c
  6. 3 3
      src/main.c
  7. 26 24
      src/parser.c
  8. 121 24
      src/ssa.c
  9. 27 38
      src/ssa_print.c

+ 1 - 1
build.bat

@@ -48,8 +48,8 @@ rem pushd %build_dir%
 
 	cl %compiler_settings% "src\main.c" ^
 		/link %linker_settings% -OUT:%exe_name% ^
+	&& odin build_dll code/example.odin ^
 	&& odin run code/demo.odin
-	rem && odin build_dll code/example.odin ^
 	rem && odin run code/demo.odin
 
 

+ 2 - 0
code/demo.odin

@@ -18,6 +18,7 @@ main :: proc() {
 	}
 	defer win32.FreeLibrary(lib)
 
+
 	proc_handle := get_proc(lib, "some_thing")
 	if proc_handle == nil {
 		fmt.println("Could not load 'some_thing'")
@@ -25,5 +26,6 @@ main :: proc() {
 	}
 
 	some_thing := (proc_handle as proc())
+	fmt.println(some_thing)
 	some_thing()
 }

+ 4 - 4
core/mem.odin

@@ -1,7 +1,7 @@
 #import "fmt.odin"
 #import "os.odin"
 
-set :: proc(data: rawptr, value: i32, len: int) -> rawptr #export "__mem_set" {
+set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
 	llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
 	llvm_memset_64bit(data, value as byte, len, 1, false)
 	return data
@@ -11,14 +11,14 @@ zero :: proc(data: rawptr, len: int) -> rawptr {
 	return set(data, 0, len)
 }
 
-copy :: proc(dst, src: rawptr, len: int) -> rawptr #export "__mem_copy" {
+copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
 	// NOTE(bill): This _must_ implemented like C's memmove
 	llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
 	llvm_memmove_64bit(dst, src, len, 1, false)
 	return dst
 }
 
-copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #export "__mem_copy_non_overlapping" {
+copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
 	// NOTE(bill): This _must_ implemented like C's memcpy
 	llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
 	llvm_memcpy_64bit(dst, src, len, 1, false)
@@ -26,7 +26,7 @@ copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #export "__me
 }
 
 
-compare :: proc(dst, src: rawptr, n: int) -> int #export "__mem_compare" {
+compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
 	// Translation of http://mgronhol.github.io/fast-strcmp/
 	a := slice_ptr(dst as ^byte, n)
 	b := slice_ptr(src as ^byte, n)

+ 30 - 19
src/checker/decl.c

@@ -309,7 +309,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 	check_procedure_type(c, proc_type, pd->type);
 
 	bool is_foreign      = (pd->tags & ProcTag_foreign)   != 0;
-	bool is_export  = (pd->tags & ProcTag_export) != 0;
+	bool is_link_name    = (pd->tags & ProcTag_link_name) != 0;
+	bool is_export       = (pd->tags & ProcTag_export)    != 0;
 	bool is_inline       = (pd->tags & ProcTag_inline)    != 0;
 	bool is_no_inline    = (pd->tags & ProcTag_no_inline) != 0;
 
@@ -330,10 +331,13 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 		error_node(pd->type, "You cannot apply both `inline` and `no_inline` to a procedure");
 	}
 
-	if (is_foreign && is_export) {
-		error_node(pd->type, "You cannot apply both `foreign` and `export_name` to a procedure");
+	if (is_foreign && is_link_name) {
+		error_node(pd->type, "You cannot apply both `foreign` and `link_name` to a procedure");
+	} else if (is_foreign && is_export) {
+		error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
 	}
 
+
 	if (pd->body != NULL) {
 		if (is_foreign) {
 			error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
@@ -372,24 +376,31 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
 		} else {
 			map_entity_set(fp, key, e);
 		}
-	} else if (is_export) {
-		MapEntity *fp = &c->info.foreign_procs;
-		AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
-		String name = proc_decl->export_name;
+	} else {
+		String name = e->token.string;
+		if (is_link_name) {
+			AstNodeProcDecl *proc_decl = &d->proc_decl->ProcDecl;
+			name = proc_decl->link_name;
+		}
 
-		e->Procedure.export_name = name;
+		if (is_link_name || is_export) {
+			MapEntity *fp = &c->info.foreign_procs;
 
-		HashKey key = hash_string(name);
-		Entity **found = map_entity_get(fp, key);
-		if (found) {
-			Entity *f = *found;
-			TokenPos pos = f->token.pos;
-			error_node(d->proc_decl,
-			           "Non unique #export name for procedure `%.*s`\n"
-			           "\tother at %.*s(%td:%td)",
-			           LIT(name), LIT(pos.file), pos.line, pos.column);
-		} else {
-			map_entity_set(fp, key, e);
+			e->Procedure.link_name = name;
+
+			HashKey key = hash_string(name);
+			Entity **found = map_entity_get(fp, key);
+			if (found) {
+				Entity *f = *found;
+				TokenPos pos = f->token.pos;
+				// TODO(bill): Better error message?
+				error_node(d->proc_decl,
+				           "Non unique linking name for procedure `%.*s`\n"
+				           "\tother at %.*s(%td:%td)",
+				           LIT(name), LIT(pos.file), pos.line, pos.column);
+			} else {
+				map_entity_set(fp, key, e);
+			}
 		}
 	}
 

+ 1 - 1
src/checker/entity.c

@@ -62,7 +62,7 @@ struct Entity {
 		struct {
 			bool   is_foreign;
 			String foreign_name;
-			String export_name;
+			String link_name;
 			u64    tags;
 		} Procedure;
 		struct {

+ 3 - 3
src/main.c

@@ -29,8 +29,8 @@ i32 win32_exec_command_line_app(char *name, bool is_silent, char *fmt, ...) {
 	start_info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
 	start_info.wShowWindow = SW_SHOW;
 	start_info.hStdInput   = GetStdHandle(STD_INPUT_HANDLE);
-	start_info.hStdOutput  = is_silent ? NULL : GetStdHandle(STD_OUTPUT_HANDLE);
-	start_info.hStdError   = is_silent ? NULL : GetStdHandle(STD_ERROR_HANDLE);
+	start_info.hStdOutput  = GetStdHandle(STD_OUTPUT_HANDLE);
+	start_info.hStdError   = GetStdHandle(STD_ERROR_HANDLE);
 
 	va_start(va, fmt);
 	cmd_len = gb_snprintf_va(cmd_line, gb_size_of(cmd_line), fmt, va);
@@ -232,7 +232,7 @@ int main(int argc, char **argv) {
 	exit_code = win32_exec_command_line_app("msvc-link", true,
 		"link %.*s.obj -OUT:%.*s.%s %s "
 		"/defaultlib:libcmt "
-		"/nologo /incremental:no /opt:ref /subsystem:console "
+		"/nologo /incremental:no /opt:ref /subsystem:WINDOWS "
 		" %.*s "
 		" %s "
 		"",

+ 26 - 24
src/parser.c

@@ -66,10 +66,11 @@ typedef enum ProcTag {
 
 	ProcTag_foreign         = GB_BIT(10),
 	ProcTag_export          = GB_BIT(11),
-	ProcTag_inline          = GB_BIT(12),
-	ProcTag_no_inline       = GB_BIT(13),
-	ProcTag_dll_import      = GB_BIT(14),
-	ProcTag_dll_export      = GB_BIT(15),
+	ProcTag_link_name       = GB_BIT(12),
+	ProcTag_inline          = GB_BIT(13),
+	ProcTag_no_inline       = GB_BIT(14),
+	ProcTag_dll_import      = GB_BIT(15),
+	// ProcTag_dll_export      = GB_BIT(16),
 
 	ProcTag_stdcall         = GB_BIT(20),
 	ProcTag_fastcall        = GB_BIT(21),
@@ -106,7 +107,7 @@ AstNodeArray make_ast_node_array(AstFile *f) {
 		AstNode *body;         \
 		u64      tags;         \
 		String   foreign_name; \
-		String   export_name;    \
+		String   link_name;    \
 	}) \
 	AST_NODE_KIND(CompoundLit, "compound literal", struct { \
 		AstNode *type; \
@@ -246,7 +247,7 @@ AST_NODE_KIND(_DeclBegin,      "", i32) \
 			AstNode *body;         \
 			u64      tags;         \
 			String   foreign_name; \
-			String   export_name;    \
+			String   link_name;    \
 			AstNode *note;         \
 	}) \
 	AST_NODE_KIND(TypeDecl,   "type declaration",   struct { \
@@ -686,13 +687,13 @@ AstNode *make_ellipsis(AstFile *f, Token token, AstNode *expr) {
 }
 
 
-AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags, String foreign_name, String export_name) {
+AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags, String foreign_name, String link_name) {
 	AstNode *result = make_node(f, AstNode_ProcLit);
 	result->ProcLit.type = type;
 	result->ProcLit.body = body;
 	result->ProcLit.tags = tags;
 	result->ProcLit.foreign_name = foreign_name;
-	result->ProcLit.export_name = export_name;
+	result->ProcLit.link_name = link_name;
 	return result;
 }
 
@@ -926,14 +927,14 @@ AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArr
 	return result;
 }
 
-AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, u64 tags, String foreign_name, String export_name) {
+AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, u64 tags, String foreign_name, String link_name) {
 	AstNode *result = make_node(f, AstNode_ProcDecl);
 	result->ProcDecl.name = name;
 	result->ProcDecl.type = proc_type;
 	result->ProcDecl.body = body;
 	result->ProcDecl.tags = tags;
 	result->ProcDecl.foreign_name = foreign_name;
-	result->ProcDecl.export_name = export_name;
+	result->ProcDecl.link_name = link_name;
 	return result;
 }
 
@@ -1364,10 +1365,10 @@ bool is_foreign_name_valid(String name) {
 	return true;
 }
 
-void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *export_name) {
+void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_name) {
 	// TODO(bill): Add this to procedure literals too
 	GB_ASSERT(foreign_name != NULL);
-	GB_ASSERT(export_name    != NULL);
+	GB_ASSERT(link_name    != NULL);
 
 	while (f->curr_token.kind == Token_Hash) {
 		AstNode *tag_expr = parse_tag_expr(f, NULL);
@@ -1390,13 +1391,13 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *export
 
 				next_token(f);
 			}
-		} else if (str_eq(tag_name, str_lit("export"))) {
-			check_proc_add_tag(f, tag_expr, tags, ProcTag_export, tag_name);
+		} else if (str_eq(tag_name, str_lit("link_name"))) {
+			check_proc_add_tag(f, tag_expr, tags, ProcTag_link_name, tag_name);
 			if (f->curr_token.kind == Token_String) {
-				*export_name = f->curr_token.string;
+				*link_name = f->curr_token.string;
 				// TODO(bill): Check if valid string
-				if (!is_foreign_name_valid(*export_name)) {
-					syntax_error_node(tag_expr, "Invalid alternative link procedure name `%.*s`", LIT(*export_name));
+				if (!is_foreign_name_valid(*link_name)) {
+					syntax_error_node(tag_expr, "Invalid alternative link procedure name `%.*s`", LIT(*link_name));
 				}
 
 				next_token(f);
@@ -1404,12 +1405,13 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *export
 				expect_token(f, Token_String);
 			}
 		}
+		ELSE_IF_ADD_TAG(export)
 		ELSE_IF_ADD_TAG(bounds_check)
 		ELSE_IF_ADD_TAG(no_bounds_check)
 		ELSE_IF_ADD_TAG(inline)
 		ELSE_IF_ADD_TAG(no_inline)
 		ELSE_IF_ADD_TAG(dll_import)
-		ELSE_IF_ADD_TAG(dll_export)
+		// ELSE_IF_ADD_TAG(dll_export)
 		ELSE_IF_ADD_TAG(stdcall)
 		ELSE_IF_ADD_TAG(fastcall)
 		// ELSE_IF_ADD_TAG(cdecl)
@@ -1534,8 +1536,8 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 
 		u64 tags = 0;
 		String foreign_name = {0};
-		String export_name = {0};
-		parse_proc_tags(f, &tags, &foreign_name, &export_name);
+		String link_name = {0};
+		parse_proc_tags(f, &tags, &foreign_name, &link_name);
 		if (tags & ProcTag_foreign) {
 			syntax_error(f->curr_token, "#foreign cannot be applied to procedure literals");
 		}
@@ -1551,7 +1553,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 			}
 
 			body = parse_body(f);
-			type = make_proc_lit(f, type, body, tags, foreign_name, export_name);
+			type = make_proc_lit(f, type, body, tags, foreign_name, link_name);
 		} else if (type != NULL && type->kind == AstNode_ProcType) {
 			type->ProcType.tags = tags;
 		}
@@ -2426,9 +2428,9 @@ AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) {
 	AstNode *body = NULL;
 	u64 tags = 0;
 	String foreign_name = {0};
-	String export_name = {0};
+	String link_name = {0};
 
-	parse_proc_tags(f, &tags, &foreign_name, &export_name);
+	parse_proc_tags(f, &tags, &foreign_name, &link_name);
 
 	AstNode *curr_proc = f->curr_proc;
 	f->curr_proc = proc_type;
@@ -2443,7 +2445,7 @@ AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) {
 	}
 
 	f->curr_proc = curr_proc;
-	return make_proc_decl(f, name, proc_type, body, tags, foreign_name, export_name);
+	return make_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
 }
 
 AstNode *parse_if_stmt(AstFile *f) {

+ 121 - 24
src/ssa.c

@@ -39,6 +39,8 @@ typedef struct ssaModule {
 	i32             global_string_index;
 	i32             global_array_index; // For ConstantSlice
 
+	Entity *        entry_point_entity;
+
 	Array(ssaProcedure *) procs;             // NOTE(bill): All procedures with bodies
 	ssaValueArray         procs_to_generate; // NOTE(bill): Procedures to generate
 } ssaModule;
@@ -97,7 +99,6 @@ typedef struct ssaDefer {
 	};
 } ssaDefer;
 
-typedef struct ssaProcedure ssaProcedure;
 struct ssaProcedure {
 	ssaProcedure *        parent;
 	Array(ssaProcedure *) children;
@@ -110,7 +111,7 @@ struct ssaProcedure {
 	AstNode *             body;
 	u64                   tags;
 
-	ssaValueArray     params;
+	ssaValueArray         params;
 	Array(ssaDefer)       defer_stmts;
 	Array(ssaBlock *)     blocks;
 	i32                   scope_index;
@@ -118,7 +119,7 @@ struct ssaProcedure {
 	ssaBlock *            entry_block;
 	ssaBlock *            curr_block;
 	ssaTargetList *       target_list;
-	ssaValueArray     referrers;
+	ssaValueArray         referrers;
 
 	i32                   local_count;
 	i32                   instr_count;
@@ -3930,8 +3931,8 @@ void ssa_build_stmt_internal(ssaProcedure *proc, AstNode *node) {
 			// parent.name-guid
 			String original_name = pd->name->Ident.string;
 			String pd_name = original_name;
-			if (pd->export_name.len > 0) {
-				pd_name = pd->export_name;
+			if (pd->link_name.len > 0) {
+				pd_name = pd->link_name;
 			}
 
 			isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1;
@@ -4571,8 +4572,11 @@ void ssa_begin_procedure_body(ssaProcedure *proc) {
 		TypeTuple *params = &proc->type->Proc.params->Tuple;
 		for (isize i = 0; i < params->variable_count; i++) {
 			Entity *e = params->variables[i];
-			ssaValue *param = ssa_add_param(proc, e);
-			array_add(&proc->params, param);
+			if (!str_eq(e->token.string, str_lit("")) &&
+			    !str_eq(e->token.string, str_lit("_"))) {
+				ssaValue *param = ssa_add_param(proc, e);
+				array_add(&proc->params, param);
+			}
 		}
 	}
 }
@@ -4857,6 +4861,8 @@ void ssa_gen_tree(ssaGen *s) {
 
 	isize global_variable_max_count = 0;
 	Entity *entry_point = NULL;
+	bool has_dll_main = false;
+	bool has_win_main = false;
 
 	for_array(i, info->entities.entries) {
 		MapDeclInfoEntry *entry = &info->entities.entries.e[i];
@@ -4864,10 +4870,18 @@ void ssa_gen_tree(ssaGen *s) {
 		String name = e->token.string;
 		if (e->kind == Entity_Variable) {
 			global_variable_max_count++;
-		} else if (e->kind == Entity_Procedure) {
+		} else if (e->kind == Entity_Procedure && !e->scope->is_global) {
 			if (e->scope->is_init && str_eq(name, str_lit("main"))) {
 				entry_point = e;
-				break;
+			}
+			if ((e->Procedure.tags & ProcTag_export) != 0 ||
+			    (e->Procedure.link_name.len > 0) ||
+			    (e->scope->is_file && e->Procedure.link_name.len > 0)) {
+				if (!has_dll_main && str_eq(name, str_lit("DllMain"))) {
+					has_dll_main = true;
+				} else if (!has_win_main && str_eq(name, str_lit("WinMain"))) {
+					has_win_main = true;
+				}
 			}
 		}
 	}
@@ -4879,6 +4893,7 @@ void ssa_gen_tree(ssaGen *s) {
 	Array(ssaGlobalVariable) global_variables;
 	array_init_reserve(&global_variables, m->tmp_allocator, global_variable_max_count);
 
+	m->entry_point_entity = entry_point;
 	m->min_dep_map = generate_minimum_dependency_map(info, entry_point);
 
 	for_array(i, info->entities.entries) {
@@ -4897,8 +4912,13 @@ void ssa_gen_tree(ssaGen *s) {
 			continue;
 		}
 
-		if (!scope->is_global && !scope->is_init) {
-			name = ssa_mangle_name(s, e->token.pos.file, name);
+		if (!scope->is_global) {
+			if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) {
+			} else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
+			} else if (scope->is_init && e->kind == Entity_Procedure && str_eq(name, str_lit("main"))) {
+			} else {
+				name = ssa_mangle_name(s, e->token.pos.file, name);
+			}
 		}
 
 
@@ -4947,8 +4967,8 @@ void ssa_gen_tree(ssaGen *s) {
 			}
 			if (pd->foreign_name.len > 0) {
 				name = pd->foreign_name;
-			} else if (pd->export_name.len > 0) {
-				name = pd->export_name;
+			} else if (pd->link_name.len > 0) {
+				name = pd->link_name;
 			}
 
 			ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
@@ -4999,7 +5019,93 @@ void ssa_gen_tree(ssaGen *s) {
 		}
 	}
 
+#if defined(GB_SYSTEM_WINDOWS)
+	if (m->build_context->is_dll && !has_dll_main) {
+		// DllMain :: proc(inst: rawptr, reason: u32, reserved: rawptr) -> i32
+		String name = str_lit("DllMain");
+		Type *proc_params = make_type_tuple(a);
+		Type *proc_results = make_type_tuple(a);
+
+		Scope *proc_scope = gb_alloc_item(a, Scope);
+
+		proc_params->Tuple.variables = gb_alloc_array(a, Entity *, 3);
+		proc_params->Tuple.variable_count = 3;
+
+		proc_results->Tuple.variables = gb_alloc_array(a, Entity *, 1);
+		proc_results->Tuple.variable_count = 1;
+
+		proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
+		proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, blank_token, t_u32,    false);
+		proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
+
+		proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false);
+
+
+		Type *proc_type = make_type_proc(a, proc_scope,
+		                                 proc_params, 3,
+		                                 proc_results, 1, false);
+
+		AstNode *body = gb_alloc_item(a, AstNode);
+		Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0);
+		ssaValue *p = ssa_make_value_procedure(a, m, e, proc_type, NULL, body, name);
+
+		map_ssa_value_set(&m->values, hash_pointer(e), p);
+		map_ssa_value_set(&m->members, hash_string(name), p);
+
+		ssaProcedure *proc = &p->Proc;
+		proc->tags = ProcTag_no_inline | ProcTag_stdcall; // TODO(bill): is no_inline a good idea?
+		e->Procedure.link_name = name;
+
+		ssa_begin_procedure_body(proc);
+		ssa_emit_global_call(proc, "main", NULL, 0);
+		ssa_emit_return(proc, v_one32);
+		ssa_end_procedure_body(proc);
+	}
+#endif
+#if defined(GB_SYSTEM_WINDOWS)
+	if (!m->build_context->is_dll && !has_win_main) {
+		// WinMain :: proc(inst, prev: rawptr, cmd_line: ^byte, cmd_show: i32) -> i32
+		String name = str_lit("WinMain");
+		Type *proc_params = make_type_tuple(a);
+		Type *proc_results = make_type_tuple(a);
+
+		Scope *proc_scope = gb_alloc_item(a, Scope);
+
+		proc_params->Tuple.variables = gb_alloc_array(a, Entity *, 4);
+		proc_params->Tuple.variable_count = 4;
+
+		proc_results->Tuple.variables = gb_alloc_array(a, Entity *, 1);
+		proc_results->Tuple.variable_count = 1;
+
+		proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
+		proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
+		proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_u8_ptr, false);
+		proc_params->Tuple.variables[3] = make_entity_param(a, proc_scope, blank_token, t_i32,    false);
+
+		proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false);
+
+
+		Type *proc_type = make_type_proc(a, proc_scope,
+		                                 proc_params, 4,
+		                                 proc_results, 1, false);
+
+		AstNode *body = gb_alloc_item(a, AstNode);
+		Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0);
+		ssaValue *p = ssa_make_value_procedure(a, m, e, proc_type, NULL, body, name);
+
+		map_ssa_value_set(&m->values, hash_pointer(e), p);
+		map_ssa_value_set(&m->members, hash_string(name), p);
+
+		ssaProcedure *proc = &p->Proc;
+		proc->tags = ProcTag_no_inline | ProcTag_stdcall; // TODO(bill): is no_inline a good idea?
+		e->Procedure.link_name = name;
 
+		ssa_begin_procedure_body(proc);
+		ssa_emit_global_call(proc, "main", NULL, 0);
+		ssa_emit_return(proc, v_one32);
+		ssa_end_procedure_body(proc);
+	}
+#endif
 	{ // Startup Runtime
 		// Cleanup(bill): probably better way of doing code insertion
 		String name = str_lit(SSA_STARTUP_RUNTIME_PROC_NAME);
@@ -5007,10 +5113,8 @@ void ssa_gen_tree(ssaGen *s) {
 		                                 NULL, 0,
 		                                 NULL, 0, false);
 		AstNode *body = gb_alloc_item(a, AstNode);
-		ssaValue *p = ssa_make_value_procedure(a, m, NULL, proc_type, NULL, body, name);
-		Token token = {0};
-		token.string = name;
-		Entity *e = make_entity_procedure(a, NULL, token, proc_type, 0);
+		Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0);
+		ssaValue *p = ssa_make_value_procedure(a, m, e, proc_type, NULL, body, name);
 
 		map_ssa_value_set(&m->values, hash_pointer(e), p);
 		map_ssa_value_set(&m->members, hash_string(name), p);
@@ -5431,13 +5535,6 @@ void ssa_gen_tree(ssaGen *s) {
 		ssa_build_proc(m->procs_to_generate.e[i], m->procs_to_generate.e[i]->Proc.parent);
 	}
 
-	// {
-	// 	DWORD old_protect = 0;
-	// 	DWORD new_protect = PAGE_READONLY;
-	// 	BOOL ok = VirtualProtect(m->arena.physical_start, m->arena.total_size, new_protect, &old_protect);
-	// }
-
-
 
 	// m->layout = str_lit("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
 }

+ 27 - 38
src/ssa_print.c

@@ -127,9 +127,9 @@ void ssa_print_encoded_local(ssaFileBuffer *f, String name) {
 	ssa_print_escape_string(f, name, true);
 }
 
-void ssa_print_encoded_global(ssaFileBuffer *f, String name, bool global_scope) {
+void ssa_print_encoded_global(ssaFileBuffer *f, String name, bool remove_prefix) {
 	ssa_fprintf(f, "@");
-	if (!global_scope && str_ne(name, str_lit("main"))) {
+	if (!remove_prefix) {
 		ssa_fprintf(f, ".");
 	}
 	ssa_print_escape_string(f, name, true);
@@ -567,6 +567,20 @@ void ssa_print_block_name(ssaFileBuffer *f, ssaBlock *b) {
 	}
 }
 
+bool ssa_print_is_proc_global(ssaModule *m, ssaProcedure *proc) {
+	if (proc->entity != NULL &&
+	    proc->entity->kind == Entity_Procedure) {
+		if (m->entry_point_entity == proc->entity) {
+			// TODO(bill): This may not be needed during windows
+			return true;
+		}
+		if (proc->entity->Procedure.link_name.len > 0) {
+		    return true;
+		}
+	}
+	return (proc->tags & (ProcTag_foreign|ProcTag_export)) != 0;
+}
+
 void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type_hint) {
 	if (value == NULL) {
 		ssa_fprintf(f, "!!!NULL_VALUE");
@@ -623,7 +637,7 @@ void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type
 		ssa_print_encoded_local(f, value->Param.entity->token.string);
 		break;
 	case ssaValue_Proc:
-		ssa_print_encoded_global(f, value->Proc.name, (value->Proc.tags & (ProcTag_foreign|ProcTag_export)) != 0);
+		ssa_print_encoded_global(f, value->Proc.name, ssa_print_is_proc_global(m, &value->Proc));
 		break;
 	case ssaValue_Instr:
 		ssa_fprintf(f, "%%%d", value->index);
@@ -1229,10 +1243,11 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 	} else {
 		ssa_fprintf(f, "\n");
 		ssa_fprintf(f, "define ");
-		if (proc->tags & ProcTag_export) {
-			ssa_fprintf(f, "dllexport ");
-		} else if (proc->tags & ProcTag_dll_export) {
-			ssa_fprintf(f, "dllexport ");
+		if (m->build_context->is_dll) {
+			// if (proc->tags & (ProcTag_export|ProcTag_dll_export)) {
+			if (proc->tags & (ProcTag_export)) {
+				ssa_fprintf(f, "dllexport ");
+			}
 		}
 	}
 
@@ -1251,7 +1266,7 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 	}
 
 	ssa_fprintf(f, " ");
-	ssa_print_encoded_global(f, proc->name, (proc->tags & (ProcTag_foreign|ProcTag_export)) != 0);
+	ssa_print_encoded_global(f, proc->name, ssa_print_is_proc_global(m, proc));
 	ssa_fprintf(f, "(");
 
 	if (proc_type->param_count > 0) {
@@ -1263,7 +1278,10 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 			}
 			ssa_print_type(f, m, e->type);
 			if (proc->body != NULL) {
-				ssa_fprintf(f, " %%%.*s", LIT(e->token.string));
+				if (!str_eq(e->token.string, str_lit("")) &&
+				    !str_eq(e->token.string, str_lit("_"))) {
+					ssa_fprintf(f, " %%%.*s", LIT(e->token.string));
+				}
 			}
 		}
 	}
@@ -1369,12 +1387,6 @@ void ssa_print_llvm_ir(ssaGen *ssa) {
 			continue;
 		}
 
-#if defined(GB_SYSTEM_WINDOWS)
-		if (str_eq(v->Proc.name, str_lit("DllMain"))) {
-			dll_main_found = true;
-		}
-#endif
-
 		if (v->Proc.body == NULL) {
 			ssa_print_proc(f, m, &v->Proc);
 		}
@@ -1387,34 +1399,11 @@ void ssa_print_llvm_ir(ssaGen *ssa) {
 			continue;
 		}
 
-#if defined(GB_SYSTEM_WINDOWS)
-		if (str_eq(v->Proc.name, str_lit("DllMain"))) {
-			dll_main_found = true;
-		}
-#endif
-
 		if (v->Proc.body != NULL) {
 			ssa_print_proc(f, m, &v->Proc);
 		}
 	}
 
-	if (m->build_context->is_dll) {
-#if !defined(GB_SYSTEM_WINDOWS)
-#error Setup dll initialization on linux if appropriate
-#else
-		if (!dll_main_found) {
-			ssa_fprintf(f,
-			"define i32 @DllMain(%%..rawptr %%inst, i32 %%reason, %%..rawptr %%reserved) {\n"
-			"entry:\n"
-			"	call void @main()\n"
-			"	ret i32 1\n"
-			"}\n"
-			);
-		}
-#endif
-	}
-
-
 	for_array(member_index, m->members.entries) {
 		MapSsaValueEntry *entry = &m->members.entries.e[member_index];
 		ssaValue *v = entry->value;