你正在使用的Go版本是什么( go version
)?
$ go version
go version go1.21.1 linux/amd64
这个问题在最新版本的发布中是否会重现?
是的。
你正在使用什么操作系统和处理器架构( go env
)?
go env
输出
$ go env
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/agiacomolli/.cache/go-build'
GOENV='/home/agiacomolli/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/agiacomolli/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/agiacomolli/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/tmp/go1.21.1'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/tmp/go1.21.1/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.21.1'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/tmp/windows-crash/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build63189677=/tmp/go-build -gno-record-gcc-switches'
你做了什么?
从Linux机器上交叉构建Windows。amd64
在运行在amd64
或arm64
机器上的构建工作正常。arm64
版本在运行时抛出异常导致崩溃。
package main
import (
"log"
"math"
"syscall"
"time"
"unsafe"
"golang.org/x/sys/windows"
)
var (
modoleaut32 = windows.NewLazySystemDLL("oleaut32.dll")
procVariantTimeToSystemTime = modoleaut32.NewProc("VariantTimeToSystemTime")
)
func main() {
t, err := GetVariantDate(45000.0)
if err != nil {
log.Fatal(err)
}
log.Printf("time = %v", t)
}
func GetVariantDate(value float64) (time.Time, error) {
var st syscall.Systemtime
r, _, err := procVariantTimeToSystemTime.Call(
uintptr(math.Float64bits(value)),
uintptr(unsafe.Pointer(&st)),
)
if r == 0 {
return time.Time{}, err
}
return time.Date(
int(st.Year),
time.Month(st.Month),
int(st.Day),
int(st.Hour),
int(st.Minute),
int(st.Second),
int(st.Milliseconds/1000),
time.UTC,
), nil
}
你期望看到什么?
在Linux上构建:
GOOS=windows GOARCH=arm64 go build -o crash.exe main.go
在Windows ARM64上运行:
PS C:\tmp> .\crash.exe
2023/09/11 19:30:33 time = 2023-03-15 00:00:00 +0000 UTC
你实际上看到了什么?
PS C:\tmp> .\crash.exe
Exception 0xc0000005 0x1 0x40e5f9000000000e 0x7ffb0b780d30
PC=0x7ffb0b780d30
runtime.cgocall(0x7ff784c919c0, 0x7ff784da1348)
/tmp/go1.21.1/src/runtime/cgocall.go:157 +0x38 fp=0x40000b7c80 sp=0x40000b7c40 pc=0x7ff784c33b98
syscall.SyscallN(0x7ffb0b780cf0?, {0x40000b7d30?, 0x3?, 0x7ff784ccb3a8?})
/tmp/go1.21.1/src/runtime/syscall_windows.go:544 +0xe8 fp=0x40000b7d00 sp=0x40000b7c80 pc=0x7ff784c8d9f8
syscall.Syscall(0x40000b7d88?, 0x7ff784ccb3d4?, 0x40000b7d88?, 0x7ff784ccb3f4?, 0x7ff784d92134?)
/tmp/go1.21.1/src/runtime/syscall_windows.go:482 +0x30 fp=0x40000b7d50 sp=0x40000b7d00 pc=0x7ff784c8d750
golang.org/x/sys/windows.(*Proc).Call(0x7ff784d92160?, {0x400009a0f0?, 0x4000047e01?, 0x7ff784c476e0?})
/home/agiacomolli/go/pkg/mod/golang.org/x/sys@v0.12.0/windows/dll_windows.go:172 +0xe0 fp=0x40000b7e00 sp=0x40000b7d50 pc=0x7ff784ccaa80
golang.org/x/sys/windows.(*LazyProc).Call(0x7ff784d92160, {0x400009a0f0, 0x2, 0x2})
/home/agiacomolli/go/pkg/mod/golang.org/x/sys@v0.12.0/windows/dll_windows.go:348 +0x4c fp=0x40000b7e30 sp=0x40000b7e00 pc=0x7ff784ccb53c
main.GetVariantDate(0x40e5f90000000000)
/tmp/windows-crash/main.go:31 +0x6c fp=0x40000b7e90 sp=0x40000b7e30 pc=0x7ff784cd187c
main.main()
/tmp/windows-crash/main.go:20 +0x28 fp=0x40000b7f30 sp=0x40000b7e90 pc=0x7ff784cd16d8
runtime.main()
/tmp/go1.21.1/src/runtime/proc.go:267 +0x2a4 fp=0x40000b7fd0 sp=0x40000b7f30 pc=0x7ff784c66d74
runtime.goexit()
/tmp/go1.21.1/src/runtime/asm_arm64.s:1197 +0x4 fp=0x40000b7fd0 sp=0x40000b7fd0 pc=0x7ff784c90d14
goroutine 2 [force gc (idle)]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/tmp/go1.21.1/src/runtime/proc.go:398 +0xc8 fp=0x4000043f90 sp=0x4000043f70 pc=0x7ff784c67188
runtime.goparkunlock(...)
/tmp/go1.21.1/src/runtime/proc.go:404
runtime.forcegchelper()
/tmp/go1.21.1/src/runtime/proc.go:322 +0xb8 fp=0x4000043fd0 sp=0x4000043f90 pc=0x7ff784c67018
runtime.goexit()
/tmp/go1.21.1/src/runtime/asm_arm64.s:1197 +0x4 fp=0x4000043fd0 sp=0x4000043fd0 pc=0x7ff784c90d14
created by runtime.init.6 in goroutine 1
/tmp/go1.21.1/src/runtime/proc.go:310 +0x24
goroutine 3 [GC sweep wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/tmp/go1.21.1/src/runtime/proc.go:398 +0xc8 fp=0x4000045f60 sp=0x4000045f40 pc=0x7ff784c67188
runtime.goparkunlock(...)
/tmp/go1.21.1/src/runtime/proc.go:404
runtime.bgsweep(0x0?)
/tmp/go1.21.1/src/runtime/mgcsweep.go:280 +0xa0 fp=0x4000045fb0 sp=0x4000045f60 pc=0x7ff784c527a0
runtime.gcenable.func1()
/tmp/go1.21.1/src/runtime/mgc.go:200 +0x28 fp=0x4000045fd0 sp=0x4000045fb0 pc=0x7ff784c474e8
runtime.goexit()
/tmp/go1.21.1/src/runtime/asm_arm64.s:1197 +0x4 fp=0x4000045fd0 sp=0x4000045fd0 pc=0x7ff784c90d14
created by runtime.gcenable in goroutine 1
/tmp/go1.21.1/src/runtime/mgc.go:200 +0x6c
goroutine 4 [GC scavenge wait]:
runtime.gopark(0x4000016070?, 0x7ff784d17d18?, 0x1?, 0x0?, 0x4000040b60?)
/tmp/go1.21.1/src/runtime/proc.go:398 +0xc8 fp=0x4000055f50 sp=0x4000055f30 pc=0x7ff784c67188
runtime.goparkunlock(...)
/tmp/go1.21.1/src/runtime/proc.go:404
runtime.(*scavengerState).park(0x7ff784da0b80)
/tmp/go1.21.1/src/runtime/mgcscavenge.go:425 +0x5c fp=0x4000055f80 sp=0x4000055f50 pc=0x7ff784c5003c
runtime.bgscavenge(0x0?)
/tmp/go1.21.1/src/runtime/mgcscavenge.go:653 +0x44 fp=0x4000055fb0 sp=0x4000055f80 pc=0x7ff784c50584
runtime.gcenable.func2()
/tmp/go1.21.1/src/runtime/mgc.go:201 +0x28 fp=0x4000055fd0 sp=0x4000055fb0 pc=0x7ff784c47488
runtime.goexit()
/tmp/go1.21.1/src/runtime/asm_arm64.s:1197 +0x4 fp=0x4000055fd0 sp=0x4000055fd0 pc=0x7ff784c90d14
created by runtime.gcenable in goroutine 1
/tmp/go1.21.1/src/runtime/mgc.go:201 +0xac
goroutine 18 [finalizer wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/tmp/go1.21.1/src/runtime/proc.go:398 +0xc8 fp=0x4000047d80 sp=0x4000047d60 pc=0x7ff784c67188
runtime.runfinq()
/tmp/go1.21.1/src/runtime/mfinal.go:193 +0x108 fp=0x4000047fd0 sp=0x4000047d80 pc=0x7ff784c46618
runtime.goexit()
/tmp/go1.21.1/src/runtime/asm_arm64.s:1197 +0x4 fp=0x4000047fd0 sp=0x4000047fd0 pc=0x7ff784c90d14
created by runtime.createfing in goroutine 1
/tmp/go1.21.1/src/runtime/mfinal.go:163 +0x80
r0 0x0
r1 0x2
r2 0x4
r3 0x0
r4 0x0
r5 0x1
r6 0xf1f09ff972
r7 0x1e
r8 0x0
r9 0xc
r10 0x1e
r11 0x7ffb0b874308
r12 0x16b
r13 0xf1f09ff9d0
r14 0x20
r15 0x16c
r16 0x40000b13a0
r17 0x40000b7dd0
r18 0x0
r19 0x40e5f90000000000
r20 0xf1f09ff9b0
r21 0xf1f09ff818
r22 0x0
r23 0x0
r24 0x0
r25 0x0
r26 0x40000b7de0
r27 0x1488
r28 0x7ff784da0c20
r29 0xf1f09ff960
lr 0x7ffb0b780d20
sp 0xf1f09ff960
pc 0x7ffb0b780d30
cpsr 0x80000000
8条答案
按热度按时间sshcrbum1#
看起来windows/arm64似乎没有将浮点参数设置到专用的浮点寄存器中,这会导致后续出现异常。
例如,这里是第一个cgo参数被设置的地方:
go/src/runtime/sys_windows_arm64.s
第83行 905b58b
| | MOVD (0*8)(R12), R0 |
但它应该是这样的:
不幸的是,修复方法并不那么简单。AArch64调用约定为整数和浮点数分别分配寄存器。也就是说,在
VariantTimeToSystemTime(arg0 float64, arg1 uintptr)
中,arg0将存储在V0中,arg1将存储在R0中,而不是R1中。这意味着需要知道每个参数的值类,才能从Go调用约定转换为AArch64。我想知道其他arm64操作系统是如何实现这一点的。@golang/compiler
rbl8hiat2#
另外,值得注意的是,在windows/arm64系统上跳过了
TestFloatArgs
:go/src/runtime/syscall_windows_test.go
第824行到第830行的代码:
| | funcTestFloatArgs(t*testing.T) { |
| | if_, err:=exec.LookPath("gcc"); err!=nil { |
| | t.Skip("skipping test: gcc is missing") |
| | } |
| | ifruntime.GOARCH!="amd64" { |
| | t.Skipf("skipping test: GOARCH=%s", runtime.GOARCH) |
| | } |
与#6510相关。
bnlyeluc3#
在其他平台上,我们通常假设系统调用不接受浮点数参数。
syscall.Syscall
显然也是这样认为的。但是如果我们需要浮点数参数,它有一个特殊的代码路径,例如 https://cs.opensource.google/go/go/+/master:src/runtime/sys_darwin.go;l=105 ,我们称之为带有浮点数参数的macOS系统函数。它的签名不同,并且有不同的汇编实现。avwztpqn4#
如果浮点参数是Windows系统调用的一般情况,我们可能需要一些其他机制,除了
syscall.Syscall
。也许对于具有1、2、... ... FP参数的系统调用,可以使用syscall.SyscallFP1
、syscall.SyscallFP2
等。ygya80vv5#
@cherrymui,既然我们已经有了
syscall.SyscallN
,那么我们是否可以换成syscall.SyscallFPN
,这样就更具未来性?rdrgkggo6#
我认为我们不能有两个可变参数,一个用于整数,另一个用于浮点数。如果有一种方法可以编写这样的可变函数并实现它,我会完全没问题。
jchrr9hc7#
嗯,这个API接受整数和浮点数参数:
ejk8hzay8#
相关问题,但对于Windows C API调用回Go:#45300
我更喜欢有类型化的API,或许是这样的:
这基本上是syscall.NewCallback的逆操作。我没有想过如何实现这个。这可能会很棘手,看起来像是NewCallback和reflect.makeMethodValue之间的交叉。
总的来说,我非常不喜欢Windows
syscall.Syscall*
函数,因为它们与Windows上的事物并不完全匹配,尤其是它们将“trap”参数作为函数PC进行重载的方式。如果我们能避免的话,我不想深入研究这些函数。