Browse Source

windows i386 support

Jon Lipstate 1 month ago
parent
commit
231ce2da59

+ 6 - 1
base/runtime/core_builtin.odin

@@ -54,7 +54,12 @@ container_of :: #force_inline proc "contextless" (ptr: $P/^$Field_Type, $T: type
 
 
 when !NO_DEFAULT_TEMP_ALLOCATOR {
-	@thread_local global_default_temp_allocator_data: Default_Temp_Allocator
+	when ODIN_ARCH == .i386 && ODIN_OS == .Windows {
+		// Thread-local storage is problematic on Windows i386
+		global_default_temp_allocator_data: Default_Temp_Allocator
+	} else {
+		@thread_local global_default_temp_allocator_data: Default_Temp_Allocator
+	}
 }
 
 @(builtin, disabled=NO_DEFAULT_TEMP_ALLOCATOR)

+ 13 - 1
base/runtime/entry_windows.odin

@@ -28,7 +28,19 @@ when ODIN_BUILD_MODE == .Dynamic {
 		return true
 	}
 } else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
-	when ODIN_ARCH == .i386 || ODIN_NO_CRT {
+	when ODIN_ARCH == .i386 && !ODIN_NO_CRT {
+		// Windows i386 with CRT: libcmt provides mainCRTStartup which calls _main
+		// Note: "c" calling convention adds underscore prefix automatically on i386
+		@(link_name="main", linkage="strong", require)
+		main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 {
+			args__ = argv[:argc]
+			context = default_context()
+			#force_no_inline _startup_runtime()
+			intrinsics.__entry_point()
+			#force_no_inline _cleanup_runtime()
+			return 0
+		}
+	} else when ODIN_NO_CRT {
 		@(link_name="mainCRTStartup", linkage="strong", require)
 		mainCRTStartup :: proc "system" () -> i32 {
 			context = default_context()

+ 12 - 4
core/testing/signal_handler_libc.odin

@@ -24,10 +24,18 @@ import "core:terminal/ansi"
 @(private="file") stop_test_passed: libc.sig_atomic_t
 @(private="file") stop_test_alert:  libc.sig_atomic_t
 
-@(private="file", thread_local)
-local_test_index: libc.sig_atomic_t
-@(private="file", thread_local)
-local_test_index_set: bool
+when ODIN_ARCH == .i386 && ODIN_OS == .Windows {
+	// Thread-local storage is problematic on Windows i386
+	@(private="file")
+	local_test_index: libc.sig_atomic_t
+	@(private="file")
+	local_test_index_set: bool
+} else {
+	@(private="file", thread_local)
+	local_test_index: libc.sig_atomic_t
+	@(private="file", thread_local)
+	local_test_index_set: bool
+}
 
 // Windows does not appear to have a SIGTRAP, so this is defined here, instead
 // of in the libc package, just so there's no confusion about it being

+ 5 - 1
src/linker.cpp

@@ -281,7 +281,11 @@ try_cross_linking:;
 					link_settings = gb_string_append_fmt(link_settings, " /NOENTRY");
 				}
 			} else {
-				link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
+				// For i386 with CRT, libcmt provides the entry point
+				// For other cases or no_crt, we need to specify the entry point
+				if (!(build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt)) {
+					link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
+				}
 			}
 
 			if (build_context.build_paths[BuildPath_Symbols].name != "") {

+ 9 - 1
src/llvm_backend.cpp

@@ -2686,8 +2686,15 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
 		params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("fdwReason"),  t_u32,    false, true);
 		params->Tuple.variables[2] = alloc_entity_param(nullptr, make_token_ident("lpReserved"), t_rawptr, false, true);
 		call_cleanup = false;
-	} else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_i386 || build_context.no_crt)) {
+	} else if (build_context.metrics.os == TargetOs_windows && build_context.no_crt) {
 		name = str_lit("mainCRTStartup");
+	} else if (build_context.metrics.os == TargetOs_windows && build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt) {
+		// Windows i386 with CRT: libcmt expects _main (main with underscore prefix)
+		name = str_lit("main");
+		has_args = true;
+		slice_init(&params->Tuple.variables, permanent_allocator(), 2);
+		params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true);
+		params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), t_ptr_cstring, false, true);
 	} else if (is_arch_wasm()) {
 		name = str_lit("_start");
 		call_cleanup = false;
@@ -3162,6 +3169,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
 				String link_name = e->Procedure.link_name;
 				if (e->pkg->kind == Package_Runtime) {
 					if (link_name == "main"           ||
+					    link_name == "_main"          ||
 					    link_name == "DllMain"        ||
 					    link_name == "WinMain"        ||
 					    link_name == "wWinMain"       ||

+ 5 - 0
src/main.cpp

@@ -3617,6 +3617,11 @@ int main(int arg_count, char const **arg_ptr) {
 	// 	print_usage_line(0, "%.*s 32-bit is not yet supported for this platform", LIT(args[0]));
 	// 	return 1;
 	// }
+	
+	// Warn about Windows i386 thread-local storage limitations
+	if (build_context.metrics.arch == TargetArch_i386 && build_context.metrics.os == TargetOs_windows) {
+		gb_printf_err("Warning: Thread-local storage is disabled on Windows i386.\n");
+	}
 
 	// Check chosen microarchitecture. If not found or ?, print list.
 	bool print_microarch_list = true;