mirror of
https://github.com/golang/go
synced 2024-11-17 02:54:45 -07:00
runtime: use the right number of parameters in syscall_SyscallX on Windows
The syscall_SyscallX functions currently discard the nargs parameter when calling syscall_SyscallN. This precludes some optimizations down the line. For example, on amd64, a syscall that takes 0 arguments don't need to set any of the params passing registers (CX, DX, R8, and R9). This CL updates all syscall_SyscallX functions so they call syscall_SyscallN with an argument slice of the right length. While here, remove the hack in syscall_SyscallN to support less than 4 arguments, and update instead asmstdcall on amd64 to properly handle this case. Change-Id: I0328e14f34c2b000fde06cc6a579b09e8c32f2b9 Reviewed-on: https://go-review.googlesource.com/c/go/+/563315 TryBot-Result: Gopher Robot <gobot@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
af5943f90c
commit
35fa852d6d
@ -33,14 +33,12 @@ TEXT runtime·asmstdcall(SB),NOSPLIT,$16
|
|||||||
|
|
||||||
SUBQ $(const_maxArgs*8), SP // room for args
|
SUBQ $(const_maxArgs*8), SP // room for args
|
||||||
|
|
||||||
// Fast version, do not store args on the stack nor
|
|
||||||
// load them into registers.
|
|
||||||
CMPL CX, $0
|
|
||||||
JE docall
|
|
||||||
|
|
||||||
// Fast version, do not store args on the stack.
|
// Fast version, do not store args on the stack.
|
||||||
CMPL CX, $4
|
CMPL CX, $0; JE _0args
|
||||||
JLE loadregs
|
CMPL CX, $1; JE _1args
|
||||||
|
CMPL CX, $2; JE _2args
|
||||||
|
CMPL CX, $3; JE _3args
|
||||||
|
CMPL CX, $4; JE _4args
|
||||||
|
|
||||||
// Check we have enough room for args.
|
// Check we have enough room for args.
|
||||||
CMPL CX, $const_maxArgs
|
CMPL CX, $const_maxArgs
|
||||||
@ -53,22 +51,25 @@ TEXT runtime·asmstdcall(SB),NOSPLIT,$16
|
|||||||
REP; MOVSQ
|
REP; MOVSQ
|
||||||
MOVQ SP, SI
|
MOVQ SP, SI
|
||||||
|
|
||||||
loadregs:
|
|
||||||
// Load first 4 args into correspondent registers.
|
// Load first 4 args into correspondent registers.
|
||||||
MOVQ 0(SI), CX
|
|
||||||
MOVQ 8(SI), DX
|
|
||||||
MOVQ 16(SI), R8
|
|
||||||
MOVQ 24(SI), R9
|
|
||||||
// Floating point arguments are passed in the XMM
|
// Floating point arguments are passed in the XMM
|
||||||
// registers. Set them here in case any of the arguments
|
// registers. Set them here in case any of the arguments
|
||||||
// are floating point values. For details see
|
// are floating point values. For details see
|
||||||
// https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
|
// https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
|
||||||
MOVQ CX, X0
|
_4args:
|
||||||
MOVQ DX, X1
|
MOVQ 24(SI), R9
|
||||||
MOVQ R8, X2
|
|
||||||
MOVQ R9, X3
|
MOVQ R9, X3
|
||||||
|
_3args:
|
||||||
|
MOVQ 16(SI), R8
|
||||||
|
MOVQ R8, X2
|
||||||
|
_2args:
|
||||||
|
MOVQ 8(SI), DX
|
||||||
|
MOVQ DX, X1
|
||||||
|
_1args:
|
||||||
|
MOVQ 0(SI), CX
|
||||||
|
MOVQ CX, X0
|
||||||
|
_0args:
|
||||||
|
|
||||||
docall:
|
|
||||||
// Call stdcall function.
|
// Call stdcall function.
|
||||||
CALL AX
|
CALL AX
|
||||||
|
|
||||||
|
@ -415,63 +415,36 @@ const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
|
|||||||
|
|
||||||
//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary
|
//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
//go:cgo_unsafe_args
|
|
||||||
func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
|
func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
|
||||||
lockOSThread()
|
fn := getLoadLibraryEx()
|
||||||
c := &getg().m.syscall
|
handle, _, err = syscall_SyscallN(fn, uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
|
||||||
c.fn = getLoadLibraryEx()
|
|
||||||
c.n = 3
|
|
||||||
args := struct {
|
|
||||||
lpFileName *uint16
|
|
||||||
hFile uintptr // always 0
|
|
||||||
flags uint32
|
|
||||||
}{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32}
|
|
||||||
c.args = uintptr(noescape(unsafe.Pointer(&args)))
|
|
||||||
|
|
||||||
cgocall(asmstdcallAddr, unsafe.Pointer(c))
|
|
||||||
KeepAlive(filename)
|
KeepAlive(filename)
|
||||||
handle = c.r1
|
if handle != 0 {
|
||||||
if handle == 0 {
|
err = 0
|
||||||
err = c.err
|
|
||||||
}
|
}
|
||||||
unlockOSThread() // not defer'd after the lockOSThread above to save stack frame size.
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname syscall_loadlibrary syscall.loadlibrary
|
//go:linkname syscall_loadlibrary syscall.loadlibrary
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
//go:cgo_unsafe_args
|
|
||||||
func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
|
func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
|
||||||
lockOSThread()
|
fn := getLoadLibrary()
|
||||||
defer unlockOSThread()
|
handle, _, err = syscall_SyscallN(fn, uintptr(unsafe.Pointer(filename)))
|
||||||
c := &getg().m.syscall
|
|
||||||
c.fn = getLoadLibrary()
|
|
||||||
c.n = 1
|
|
||||||
c.args = uintptr(noescape(unsafe.Pointer(&filename)))
|
|
||||||
cgocall(asmstdcallAddr, unsafe.Pointer(c))
|
|
||||||
KeepAlive(filename)
|
KeepAlive(filename)
|
||||||
handle = c.r1
|
if handle != 0 {
|
||||||
if handle == 0 {
|
err = 0
|
||||||
err = c.err
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname syscall_getprocaddress syscall.getprocaddress
|
//go:linkname syscall_getprocaddress syscall.getprocaddress
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
//go:cgo_unsafe_args
|
|
||||||
func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
|
func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
|
||||||
lockOSThread()
|
fn := getGetProcAddress()
|
||||||
defer unlockOSThread()
|
outhandle, _, err = syscall_SyscallN(fn, handle, uintptr(unsafe.Pointer(procname)))
|
||||||
c := &getg().m.syscall
|
|
||||||
c.fn = getGetProcAddress()
|
|
||||||
c.n = 2
|
|
||||||
c.args = uintptr(noescape(unsafe.Pointer(&handle)))
|
|
||||||
cgocall(asmstdcallAddr, unsafe.Pointer(c))
|
|
||||||
KeepAlive(procname)
|
KeepAlive(procname)
|
||||||
outhandle = c.r1
|
if outhandle != 0 {
|
||||||
if outhandle == 0 {
|
err = 0
|
||||||
err = c.err
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -479,37 +452,43 @@ func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uint
|
|||||||
//go:linkname syscall_Syscall syscall.Syscall
|
//go:linkname syscall_Syscall syscall.Syscall
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
|
func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
|
||||||
return syscall_SyscallN(fn, a1, a2, a3)
|
args := [...]uintptr{a1, a2, a3}
|
||||||
|
return syscall_SyscallN(fn, args[:nargs]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname syscall_Syscall6 syscall.Syscall6
|
//go:linkname syscall_Syscall6 syscall.Syscall6
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
|
func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
|
||||||
return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6)
|
args := [...]uintptr{a1, a2, a3, a4, a5, a6}
|
||||||
|
return syscall_SyscallN(fn, args[:nargs]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname syscall_Syscall9 syscall.Syscall9
|
//go:linkname syscall_Syscall9 syscall.Syscall9
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
|
func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
|
||||||
return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9)
|
args := [...]uintptr{a1, a2, a3, a4, a5, a6, a7, a8, a9}
|
||||||
|
return syscall_SyscallN(fn, args[:nargs]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname syscall_Syscall12 syscall.Syscall12
|
//go:linkname syscall_Syscall12 syscall.Syscall12
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) {
|
func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) {
|
||||||
return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
|
args := [...]uintptr{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12}
|
||||||
|
return syscall_SyscallN(fn, args[:nargs]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname syscall_Syscall15 syscall.Syscall15
|
//go:linkname syscall_Syscall15 syscall.Syscall15
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
|
func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
|
||||||
return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
|
args := [...]uintptr{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15}
|
||||||
|
return syscall_SyscallN(fn, args[:nargs]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname syscall_Syscall18 syscall.Syscall18
|
//go:linkname syscall_Syscall18 syscall.Syscall18
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func syscall_Syscall18(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2, err uintptr) {
|
func syscall_Syscall18(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2, err uintptr) {
|
||||||
return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18)
|
args := [...]uintptr{a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18}
|
||||||
|
return syscall_SyscallN(fn, args[:nargs]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// maxArgs should be divisible by 2, as Windows stack
|
// maxArgs should be divisible by 2, as Windows stack
|
||||||
@ -521,26 +500,22 @@ const maxArgs = 42
|
|||||||
|
|
||||||
//go:linkname syscall_SyscallN syscall.SyscallN
|
//go:linkname syscall_SyscallN syscall.SyscallN
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func syscall_SyscallN(trap uintptr, args ...uintptr) (r1, r2, err uintptr) {
|
func syscall_SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
|
||||||
nargs := len(args)
|
if len(args) > maxArgs {
|
||||||
|
|
||||||
// asmstdcall expects it can access the first 4 arguments
|
|
||||||
// to load them into registers.
|
|
||||||
var tmp [4]uintptr
|
|
||||||
switch {
|
|
||||||
case nargs < 4:
|
|
||||||
copy(tmp[:], args)
|
|
||||||
args = tmp[:]
|
|
||||||
case nargs > maxArgs:
|
|
||||||
panic("runtime: SyscallN has too many arguments")
|
panic("runtime: SyscallN has too many arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The cgocall parameters are stored in m instead of in
|
||||||
|
// the stack because the stack can move during if fn
|
||||||
|
// calls back into Go.
|
||||||
lockOSThread()
|
lockOSThread()
|
||||||
defer unlockOSThread()
|
defer unlockOSThread()
|
||||||
c := &getg().m.syscall
|
c := &getg().m.syscall
|
||||||
c.fn = trap
|
c.fn = fn
|
||||||
c.n = uintptr(nargs)
|
c.n = uintptr(len(args))
|
||||||
c.args = uintptr(noescape(unsafe.Pointer(&args[0])))
|
if c.n != 0 {
|
||||||
|
c.args = uintptr(noescape(unsafe.Pointer(&args[0])))
|
||||||
|
}
|
||||||
cgocall(asmstdcallAddr, unsafe.Pointer(c))
|
cgocall(asmstdcallAddr, unsafe.Pointer(c))
|
||||||
return c.r1, c.r2, c.err
|
return c.r1, c.r2, c.err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user