From 9c02c75639b893cea6dbce1092d07e886ec5f44e Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 26 Oct 2016 13:29:39 -0400 Subject: [PATCH] runtime: pass windows float syscall args via XMM Based on the calling convention documented in: https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx and long-used in golang.org/x/mobile/gl via some fixup asm: https://go.googlesource.com/mobile/+/master/gl/work_windows_amd64.s Fixes #6510 Change-Id: I97e81baaa2872bcd732b1308915eb66f1ba2168f Reviewed-on: https://go-review.googlesource.com/32173 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Alex Brainman Reviewed-by: Minux Ma --- src/runtime/sys_windows_amd64.s | 8 +++++ src/runtime/syscall_windows_test.go | 56 +++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s index 9c197379fb8..9679099c4e7 100644 --- a/src/runtime/sys_windows_amd64.s +++ b/src/runtime/sys_windows_amd64.s @@ -45,6 +45,14 @@ loadregs: MOVQ 8(SI), DX MOVQ 16(SI), R8 MOVQ 24(SI), R9 + // Floating point arguments are passed in the XMM + // registers. Set them here in case any of the arguments + // are floating point values. For details see + // https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx + MOVQ CX, X0 + MOVQ DX, X1 + MOVQ R8, X2 + MOVQ R9, X3 // Call stdcall function. CALL AX diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go index c19cd71662f..11e67df100d 100644 --- a/src/runtime/syscall_windows_test.go +++ b/src/runtime/syscall_windows_test.go @@ -10,6 +10,7 @@ import ( "internal/syscall/windows/sysdll" "internal/testenv" "io/ioutil" + "math" "os" "os/exec" "path/filepath" @@ -622,6 +623,61 @@ uintptr_t cfunc(callback f, uintptr_t n) { } } +func TestFloatArgs(t *testing.T) { + if _, err := exec.LookPath("gcc"); err != nil { + t.Skip("skipping test: gcc is missing") + } + if runtime.GOARCH != "amd64" { + t.Skipf("skipping test: GOARCH=%s", runtime.GOARCH) + } + + const src = ` +#include +#include + +uintptr_t cfunc(uintptr_t a, double b, float c, double d) { + if (a == 1 && b == 2.2 && c == 3.3f && d == 4.4e44) { + return 1; + } + return 0; +} +` + tmpdir, err := ioutil.TempDir("", "TestFloatArgs") + if err != nil { + t.Fatal("TempDir failed: ", err) + } + defer os.RemoveAll(tmpdir) + + srcname := "mydll.c" + err = ioutil.WriteFile(filepath.Join(tmpdir, srcname), []byte(src), 0) + if err != nil { + t.Fatal(err) + } + outname := "mydll.dll" + cmd := exec.Command("gcc", "-shared", "-s", "-Werror", "-o", outname, srcname) + cmd.Dir = tmpdir + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("failed to build dll: %v - %v", err, string(out)) + } + dllpath := filepath.Join(tmpdir, outname) + + dll := syscall.MustLoadDLL(dllpath) + defer dll.Release() + + proc := dll.MustFindProc("cfunc") + + r, _, err := proc.Call( + 1, + uintptr(math.Float64bits(2.2)), + uintptr(math.Float32bits(3.3)), + uintptr(math.Float64bits(4.4e44)), + ) + if r != 1 { + t.Errorf("got %d want 1 (err=%v)", r, err) + } +} + func TestTimeBeginPeriod(t *testing.T) { const TIMERR_NOERROR = 0 if *runtime.TimeBeginPeriodRetValue != TIMERR_NOERROR {