From e51941976cdb2f698af8df5b673560bf5dbf250d Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 22 Nov 2024 15:17:37 +0100 Subject: [PATCH 1/2] windows: add windows/386 support --- builder/builder_test.go | 1 + builder/mingw-w64.go | 3 +++ compileopts/target.go | 18 ++++++++++++------ main_test.go | 7 +++++++ src/internal/task/task_stack_386.S | 14 ++++++++++++++ src/runtime/asm_386.S | 14 ++++++++++++++ 6 files changed, 51 insertions(+), 6 deletions(-) diff --git a/builder/builder_test.go b/builder/builder_test.go index 3d714808fa..2feb77e541 100644 --- a/builder/builder_test.go +++ b/builder/builder_test.go @@ -66,6 +66,7 @@ func TestClangAttributes(t *testing.T) { {GOOS: "linux", GOARCH: "mipsle", GOMIPS: "softfloat"}, {GOOS: "darwin", GOARCH: "amd64"}, {GOOS: "darwin", GOARCH: "arm64"}, + {GOOS: "windows", GOARCH: "386"}, {GOOS: "windows", GOARCH: "amd64"}, {GOOS: "windows", GOARCH: "arm64"}, {GOOS: "wasip1", GOARCH: "wasm"}, diff --git a/builder/mingw-w64.go b/builder/mingw-w64.go index 32cf58f531..6ea3560f73 100644 --- a/builder/mingw-w64.go +++ b/builder/mingw-w64.go @@ -93,6 +93,9 @@ func makeMinGWExtraLibs(tmpdir, goarch string) []*compileJob { defpath := inpath var archDef, emulation string switch goarch { + case "386": + archDef = "-DDEF_I386" + emulation = "i386pe" case "amd64": archDef = "-DDEF_X64" emulation = "i386pep" diff --git a/compileopts/target.go b/compileopts/target.go index f60ee30972..3a8761b28e 100644 --- a/compileopts/target.go +++ b/compileopts/target.go @@ -420,14 +420,20 @@ func defaultTarget(options *Options) (*TargetSpec, error) { case "windows": spec.Linker = "ld.lld" spec.Libc = "mingw-w64" - // Note: using a medium code model, low image base and no ASLR - // because Go doesn't really need those features. ASLR patches - // around issues for unsafe languages like C/C++ that are not - // normally present in Go (without explicitly opting in). - // For more discussion: - // https://groups.google.com/g/Golang-nuts/c/Jd9tlNc6jUE/m/Zo-7zIP_m3MJ?pli=1 switch options.GOARCH { + case "386": + spec.LDFlags = append(spec.LDFlags, + "-m", "i386pe", + ) + // __udivdi3 is not present in ucrt it seems. + spec.RTLib = "compiler-rt" case "amd64": + // Note: using a medium code model, low image base and no ASLR + // because Go doesn't really need those features. ASLR patches + // around issues for unsafe languages like C/C++ that are not + // normally present in Go (without explicitly opting in). + // For more discussion: + // https://groups.google.com/g/Golang-nuts/c/Jd9tlNc6jUE/m/Zo-7zIP_m3MJ?pli=1 spec.LDFlags = append(spec.LDFlags, "-m", "i386pep", "--image-base", "0x400000", diff --git a/main_test.go b/main_test.go index 22ac549de7..a6ffe51994 100644 --- a/main_test.go +++ b/main_test.go @@ -203,6 +203,13 @@ func TestBuild(t *testing.T) { t.Parallel() runPlatTests(optionsFromTarget("wasip2", sema), tests, t) }) + } else if runtime.GOOS == "windows" { + if runtime.GOARCH != "386" { + t.Run("Windows386", func(t *testing.T) { + t.Parallel() + runPlatTests(optionsFromOSARCH("windows/386", sema), tests, t) + }) + } } } diff --git a/src/internal/task/task_stack_386.S b/src/internal/task/task_stack_386.S index c82213e98f..1a52921540 100644 --- a/src/internal/task/task_stack_386.S +++ b/src/internal/task/task_stack_386.S @@ -1,7 +1,12 @@ +#ifdef _WIN32 +.global _tinygo_startTask +_tinygo_startTask: +#else // Linux etc .section .text.tinygo_startTask .global tinygo_startTask .type tinygo_startTask, %function tinygo_startTask: +#endif .cfi_startproc // Small assembly stub for starting a goroutine. This is already run on the // new stack, with the callee-saved registers already loaded. @@ -24,12 +29,21 @@ tinygo_startTask: addl $4, %esp // After return, exit this goroutine. This is a tail call. + #ifdef _WIN32 + jmp _tinygo_pause + #else jmp tinygo_pause + #endif .cfi_endproc +#ifdef _WIN32 +.global _tinygo_swapTask +_tinygo_swapTask: +#else .global tinygo_swapTask .type tinygo_swapTask, %function tinygo_swapTask: +#endif // This function gets the following parameters: movl 4(%esp), %eax // newStack uintptr movl 8(%esp), %ecx // oldStack *uintptr diff --git a/src/runtime/asm_386.S b/src/runtime/asm_386.S index faaa7c3a3b..f463ffa0a0 100644 --- a/src/runtime/asm_386.S +++ b/src/runtime/asm_386.S @@ -1,7 +1,12 @@ +#ifdef _WIN32 +.global _tinygo_scanCurrentStack +_tinygo_scanCurrentStack: +#else .section .text.tinygo_scanCurrentStack .global tinygo_scanCurrentStack .type tinygo_scanCurrentStack, %function tinygo_scanCurrentStack: +#endif // Sources: // * https://stackoverflow.com/questions/18024672/what-registers-are-preserved-through-a-linux-x86-64-function-call // * https://godbolt.org/z/q7e8dn @@ -15,7 +20,11 @@ tinygo_scanCurrentStack: // Scan the stack. subl $8, %esp // adjust the stack before the call to maintain 16-byte alignment pushl %esp + #ifdef _WIN32 + calll _tinygo_scanstack + #else calll tinygo_scanstack + #endif // Restore the stack pointer. Registers do not need to be restored as they // were only pushed to be discoverable by the GC. @@ -23,9 +32,14 @@ tinygo_scanCurrentStack: retl +#ifdef _WIN32 +.global _tinygo_longjmp +_tinygo_longjmp: +#else .section .text.tinygo_longjmp .global tinygo_longjmp tinygo_longjmp: +#endif // Note: the code we jump to assumes eax is set to a non-zero value if we // jump from here. movl 4(%esp), %eax From 0153a8f1bcaf90803bc4be71f1fdf91804c110f2 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 22 Nov 2024 15:54:16 +0100 Subject: [PATCH 2/2] WIP: actually run Windows 386 tests --- .github/workflows/build-macos.yml | 2 +- .github/workflows/windows.yml | 2 +- main_test.go | 53 +++++++++++++++++-------------- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 4f26e1fb8f..c0f59686c3 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -101,7 +101,7 @@ jobs: - name: make gen-device run: make -j3 gen-device - name: Test TinyGo - run: make test GOTESTFLAGS="-short" + run: make test GOTESTFLAGS="-only-current-os" - name: Build TinyGo release tarball run: make release -j3 - name: Test stdlib packages diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 0994d47a70..898b7a9e33 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -107,7 +107,7 @@ jobs: run: make -j3 gen-device - name: Test TinyGo shell: bash - run: make test GOTESTFLAGS="-short" + run: make test GOTESTFLAGS="-only-current-os" - name: Build TinyGo release tarball shell: bash run: make build/release -j4 diff --git a/main_test.go b/main_test.go index a6ffe51994..26635c130f 100644 --- a/main_test.go +++ b/main_test.go @@ -35,6 +35,8 @@ const TESTDATA = "testdata" var testTarget = flag.String("target", "", "override test target") +var testOnlyCurrentOS = flag.Bool("only-current-os", false, "") + var supportedLinuxArches = map[string]string{ "AMD64Linux": "linux/amd64", "X86Linux": "linux/386", @@ -158,20 +160,35 @@ func TestBuild(t *testing.T) { return } - t.Run("EmulatedCortexM3", func(t *testing.T) { - t.Parallel() - runPlatTests(optionsFromTarget("cortex-m-qemu", sema), tests, t) - }) + if !*testOnlyCurrentOS { + t.Run("EmulatedCortexM3", func(t *testing.T) { + t.Parallel() + runPlatTests(optionsFromTarget("cortex-m-qemu", sema), tests, t) + }) - t.Run("EmulatedRISCV", func(t *testing.T) { - t.Parallel() - runPlatTests(optionsFromTarget("riscv-qemu", sema), tests, t) - }) + t.Run("EmulatedRISCV", func(t *testing.T) { + t.Parallel() + runPlatTests(optionsFromTarget("riscv-qemu", sema), tests, t) + }) - t.Run("AVR", func(t *testing.T) { - t.Parallel() - runPlatTests(optionsFromTarget("simavr", sema), tests, t) - }) + t.Run("AVR", func(t *testing.T) { + t.Parallel() + runPlatTests(optionsFromTarget("simavr", sema), tests, t) + }) + + t.Run("WebAssembly", func(t *testing.T) { + t.Parallel() + runPlatTests(optionsFromTarget("wasm", sema), tests, t) + }) + t.Run("WASI", func(t *testing.T) { + t.Parallel() + runPlatTests(optionsFromTarget("wasip1", sema), tests, t) + }) + t.Run("WASIp2", func(t *testing.T) { + t.Parallel() + runPlatTests(optionsFromTarget("wasip2", sema), tests, t) + }) + } if runtime.GOOS == "linux" { for name, osArch := range supportedLinuxArches { @@ -191,18 +208,6 @@ func TestBuild(t *testing.T) { options := optionsFromOSARCH("linux/mipsle/softfloat", sema) runTest("cgo/", options, t, nil, nil) }) - t.Run("WebAssembly", func(t *testing.T) { - t.Parallel() - runPlatTests(optionsFromTarget("wasm", sema), tests, t) - }) - t.Run("WASI", func(t *testing.T) { - t.Parallel() - runPlatTests(optionsFromTarget("wasip1", sema), tests, t) - }) - t.Run("WASIp2", func(t *testing.T) { - t.Parallel() - runPlatTests(optionsFromTarget("wasip2", sema), tests, t) - }) } else if runtime.GOOS == "windows" { if runtime.GOARCH != "386" { t.Run("Windows386", func(t *testing.T) {