mirror of
https://github.com/golang/go.git
synced 2025-10-19 19:13:18 +00:00
internal/runtime/syscall/windows: factor out code from runtime
Factor out the code related to doing calls using the Windows stdcall calling convention into a separate package. This will allow us to reuse it in other low-level packages that can't depend on syscall. Updates #51087. Cq-Include-Trybots: luci.golang.try:gotip-windows-arm64,gotip-windows-amd64-longtest,gotip-solaris-amd64 Change-Id: I68640b07091183b50da6bef17406c10a397896e9 Reviewed-on: https://go-review.googlesource.com/c/go/+/689156 Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
This commit is contained in:
parent
e81eac19d3
commit
c7ed3a1c5a
22 changed files with 407 additions and 346 deletions
|
@ -57,6 +57,7 @@ var runtimePkgs = []string{
|
||||||
"internal/runtime/strconv",
|
"internal/runtime/strconv",
|
||||||
"internal/runtime/sys",
|
"internal/runtime/sys",
|
||||||
"internal/runtime/syscall/linux",
|
"internal/runtime/syscall/linux",
|
||||||
|
"internal/runtime/syscall/windows",
|
||||||
|
|
||||||
"internal/abi",
|
"internal/abi",
|
||||||
"internal/bytealg",
|
"internal/bytealg",
|
||||||
|
@ -95,6 +96,7 @@ var allowAsmABIPkgs = []string{
|
||||||
"internal/bytealg",
|
"internal/bytealg",
|
||||||
"internal/chacha8rand",
|
"internal/chacha8rand",
|
||||||
"internal/runtime/syscall/linux",
|
"internal/runtime/syscall/linux",
|
||||||
|
"internal/runtime/syscall/windows",
|
||||||
"internal/runtime/startlinetest",
|
"internal/runtime/startlinetest",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,7 @@ var depsRules = `
|
||||||
< internal/asan
|
< internal/asan
|
||||||
< internal/runtime/sys
|
< internal/runtime/sys
|
||||||
< internal/runtime/syscall/linux
|
< internal/runtime/syscall/linux
|
||||||
|
< internal/runtime/syscall/windows
|
||||||
< internal/runtime/atomic
|
< internal/runtime/atomic
|
||||||
< internal/runtime/exithook
|
< internal/runtime/exithook
|
||||||
< internal/runtime/gc
|
< internal/runtime/gc
|
||||||
|
|
|
@ -67,6 +67,7 @@ var rtPkgs = [...]string{
|
||||||
"internal/runtime/sys",
|
"internal/runtime/sys",
|
||||||
"internal/runtime/maps",
|
"internal/runtime/maps",
|
||||||
"internal/runtime/syscall/linux",
|
"internal/runtime/syscall/linux",
|
||||||
|
"internal/runtime/syscall/windows",
|
||||||
"internal/runtime/cgroup",
|
"internal/runtime/cgroup",
|
||||||
"internal/stringslite",
|
"internal/stringslite",
|
||||||
"runtime",
|
"runtime",
|
||||||
|
|
48
src/internal/runtime/syscall/windows/asm_windows_386.s
Normal file
48
src/internal/runtime/syscall/windows/asm_windows_386.s
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright 2025 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "go_asm.h"
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
TEXT ·StdCall<ABIInternal>(SB),NOSPLIT,$0
|
||||||
|
JMP ·asmstdcall(SB)
|
||||||
|
|
||||||
|
TEXT ·asmstdcall(SB),NOSPLIT,$0
|
||||||
|
MOVL fn+0(FP), BX
|
||||||
|
MOVL SP, BP // save stack pointer
|
||||||
|
|
||||||
|
// SetLastError(0).
|
||||||
|
MOVL $0, 0x34(FS)
|
||||||
|
|
||||||
|
MOVL StdCallInfo_N(BX), CX
|
||||||
|
|
||||||
|
// Fast version, do not store args on the stack.
|
||||||
|
CMPL CX, $0
|
||||||
|
JE docall
|
||||||
|
|
||||||
|
// Copy args to the stack.
|
||||||
|
MOVL CX, AX
|
||||||
|
SALL $2, AX
|
||||||
|
SUBL AX, SP // room for args
|
||||||
|
MOVL SP, DI
|
||||||
|
MOVL StdCallInfo_Args(BX), SI
|
||||||
|
CLD
|
||||||
|
REP; MOVSL
|
||||||
|
|
||||||
|
docall:
|
||||||
|
// Call stdcall or cdecl function.
|
||||||
|
// DI SI BP BX are preserved, SP is not
|
||||||
|
CALL StdCallInfo_Fn(BX)
|
||||||
|
MOVL BP, SP
|
||||||
|
|
||||||
|
// Return result.
|
||||||
|
MOVL fn+0(FP), BX
|
||||||
|
MOVL AX, StdCallInfo_R1(BX)
|
||||||
|
MOVL DX, StdCallInfo_R2(BX)
|
||||||
|
|
||||||
|
// GetLastError().
|
||||||
|
MOVL 0x34(FS), AX
|
||||||
|
MOVL AX, StdCallInfo_Err(BX)
|
||||||
|
|
||||||
|
RET
|
84
src/internal/runtime/syscall/windows/asm_windows_amd64.s
Normal file
84
src/internal/runtime/syscall/windows/asm_windows_amd64.s
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
// Copyright 2025 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "go_asm.h"
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
TEXT ·StdCall<ABIInternal>(SB),NOSPLIT,$0
|
||||||
|
MOVQ AX, CX
|
||||||
|
JMP ·asmstdcall(SB)
|
||||||
|
|
||||||
|
TEXT ·asmstdcall(SB),NOSPLIT,$16
|
||||||
|
MOVQ SP, AX
|
||||||
|
ANDQ $~15, SP // alignment as per Windows requirement
|
||||||
|
MOVQ AX, 8(SP)
|
||||||
|
MOVQ CX, 0(SP) // asmcgocall will put first argument into CX.
|
||||||
|
|
||||||
|
MOVQ StdCallInfo_Fn(CX), AX
|
||||||
|
MOVQ StdCallInfo_Args(CX), SI
|
||||||
|
MOVQ StdCallInfo_N(CX), CX
|
||||||
|
|
||||||
|
// SetLastError(0).
|
||||||
|
MOVQ 0x30(GS), DI
|
||||||
|
MOVL $0, 0x68(DI)
|
||||||
|
|
||||||
|
SUBQ $(const_MaxArgs*8), SP // room for args
|
||||||
|
|
||||||
|
// Fast version, do not store args on the stack.
|
||||||
|
CMPL CX, $0; JE _0args
|
||||||
|
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.
|
||||||
|
CMPL CX, $const_MaxArgs
|
||||||
|
JLE 2(PC)
|
||||||
|
INT $3 // not enough room -> crash
|
||||||
|
|
||||||
|
// Copy args to the stack.
|
||||||
|
MOVQ SP, DI
|
||||||
|
CLD
|
||||||
|
REP; MOVSQ
|
||||||
|
MOVQ SP, SI
|
||||||
|
|
||||||
|
// Load first 4 args into correspondent registers.
|
||||||
|
// 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://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
|
||||||
|
_4args:
|
||||||
|
MOVQ 24(SI), R9
|
||||||
|
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:
|
||||||
|
|
||||||
|
// Call stdcall function.
|
||||||
|
CALL AX
|
||||||
|
|
||||||
|
ADDQ $(const_MaxArgs*8), SP
|
||||||
|
|
||||||
|
// Return result.
|
||||||
|
MOVQ 0(SP), CX
|
||||||
|
MOVQ 8(SP), SP
|
||||||
|
MOVQ AX, StdCallInfo_R1(CX)
|
||||||
|
// Floating point return values are returned in XMM0. Setting r2 to this
|
||||||
|
// value in case this call returned a floating point value. For details,
|
||||||
|
// see https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
|
||||||
|
MOVQ X0, StdCallInfo_R2(CX)
|
||||||
|
|
||||||
|
// GetLastError().
|
||||||
|
MOVQ 0x30(GS), DI
|
||||||
|
MOVL 0x68(DI), AX
|
||||||
|
MOVQ AX, StdCallInfo_Err(CX)
|
||||||
|
|
||||||
|
RET
|
77
src/internal/runtime/syscall/windows/asm_windows_arm.s
Normal file
77
src/internal/runtime/syscall/windows/asm_windows_arm.s
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright 2025 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "go_asm.h"
|
||||||
|
#include "go_tls.h"
|
||||||
|
#include "textflag.h"
|
||||||
|
#include "time_windows.h"
|
||||||
|
|
||||||
|
TEXT ·StdCall<ABIInternal>(SB),NOSPLIT,$0
|
||||||
|
B ·asmstdcall(SB)
|
||||||
|
|
||||||
|
TEXT ·asmstdcall(SB),NOSPLIT|NOFRAME,$0
|
||||||
|
MOVM.DB.W [R4, R5, R14], (R13) // push {r4, r5, lr}
|
||||||
|
MOVW R0, R4 // put fn * in r4
|
||||||
|
MOVW R13, R5 // save stack pointer in r5
|
||||||
|
|
||||||
|
// SetLastError(0)
|
||||||
|
MOVW $0, R0
|
||||||
|
MRC 15, 0, R1, C13, C0, 2
|
||||||
|
MOVW R0, 0x34(R1)
|
||||||
|
|
||||||
|
MOVW 8(R4), R12 // fn->Args
|
||||||
|
|
||||||
|
// Do we have more than 4 arguments?
|
||||||
|
MOVW 4(R4), R0 // fn->n
|
||||||
|
SUB.S $4, R0, R2
|
||||||
|
BLE loadregs
|
||||||
|
|
||||||
|
// Reserve stack space for remaining args
|
||||||
|
SUB R2<<2, R13
|
||||||
|
BIC $0x7, R13 // alignment for ABI
|
||||||
|
|
||||||
|
// R0: count of arguments
|
||||||
|
// R1:
|
||||||
|
// R2: loop counter, from 0 to (n-4)
|
||||||
|
// R3: scratch
|
||||||
|
// R4: pointer to StdCallInfo struct
|
||||||
|
// R12: fn->args
|
||||||
|
MOVW $0, R2
|
||||||
|
stackargs:
|
||||||
|
ADD $4, R2, R3 // r3 = args[4 + i]
|
||||||
|
MOVW R3<<2(R12), R3
|
||||||
|
MOVW R3, R2<<2(R13) // stack[i] = r3
|
||||||
|
|
||||||
|
ADD $1, R2 // i++
|
||||||
|
SUB $4, R0, R3 // while (i < (n - 4))
|
||||||
|
CMP R3, R2
|
||||||
|
BLT stackargs
|
||||||
|
|
||||||
|
loadregs:
|
||||||
|
CMP $3, R0
|
||||||
|
MOVW.GT 12(R12), R3
|
||||||
|
|
||||||
|
CMP $2, R0
|
||||||
|
MOVW.GT 8(R12), R2
|
||||||
|
|
||||||
|
CMP $1, R0
|
||||||
|
MOVW.GT 4(R12), R1
|
||||||
|
|
||||||
|
CMP $0, R0
|
||||||
|
MOVW.GT 0(R12), R0
|
||||||
|
|
||||||
|
BIC $0x7, R13 // alignment for ABI
|
||||||
|
MOVW 0(R4), R12 // branch to fn->fn
|
||||||
|
BL (R12)
|
||||||
|
|
||||||
|
MOVW R5, R13 // free stack space
|
||||||
|
MOVW R0, 12(R4) // save return value to fn->r1
|
||||||
|
MOVW R1, 16(R4)
|
||||||
|
|
||||||
|
// GetLastError
|
||||||
|
MRC 15, 0, R1, C13, C0, 2
|
||||||
|
MOVW 0x34(R1), R0
|
||||||
|
MOVW R0, 20(R4) // store in fn->err
|
||||||
|
|
||||||
|
MOVM.IA.W (R13), [R4, R5, R15]
|
90
src/internal/runtime/syscall/windows/asm_windows_arm64.s
Normal file
90
src/internal/runtime/syscall/windows/asm_windows_arm64.s
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
// Copyright 2025 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "go_asm.h"
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// Offsets into Thread Environment Block (pointer in R18)
|
||||||
|
#define TEB_error 0x68
|
||||||
|
|
||||||
|
TEXT ·StdCall<ABIInternal>(SB),NOSPLIT,$0
|
||||||
|
B ·asmstdcall(SB)
|
||||||
|
|
||||||
|
TEXT ·asmstdcall(SB),NOSPLIT,$16
|
||||||
|
STP (R19, R20), 16(RSP) // save old R19, R20
|
||||||
|
MOVD R0, R19 // save fn pointer
|
||||||
|
MOVD RSP, R20 // save stack pointer
|
||||||
|
|
||||||
|
// SetLastError(0)
|
||||||
|
MOVD $0, TEB_error(R18_PLATFORM)
|
||||||
|
MOVD StdCallInfo_Args(R19), R12
|
||||||
|
|
||||||
|
// Do we have more than 8 arguments?
|
||||||
|
MOVD StdCallInfo_N(R19), R0
|
||||||
|
CMP $0, R0; BEQ _0args
|
||||||
|
CMP $1, R0; BEQ _1args
|
||||||
|
CMP $2, R0; BEQ _2args
|
||||||
|
CMP $3, R0; BEQ _3args
|
||||||
|
CMP $4, R0; BEQ _4args
|
||||||
|
CMP $5, R0; BEQ _5args
|
||||||
|
CMP $6, R0; BEQ _6args
|
||||||
|
CMP $7, R0; BEQ _7args
|
||||||
|
CMP $8, R0; BEQ _8args
|
||||||
|
|
||||||
|
// Reserve stack space for remaining args
|
||||||
|
SUB $8, R0, R2
|
||||||
|
ADD $1, R2, R3 // make even number of words for stack alignment
|
||||||
|
AND $~1, R3
|
||||||
|
LSL $3, R3
|
||||||
|
SUB R3, RSP
|
||||||
|
|
||||||
|
// R4: size of stack arguments (n-8)*8
|
||||||
|
// R5: &args[8]
|
||||||
|
// R6: loop counter, from 0 to (n-8)*8
|
||||||
|
// R7: scratch
|
||||||
|
// R8: copy of RSP - (R2)(RSP) assembles as (R2)(ZR)
|
||||||
|
SUB $8, R0, R4
|
||||||
|
LSL $3, R4
|
||||||
|
ADD $(8*8), R12, R5
|
||||||
|
MOVD $0, R6
|
||||||
|
MOVD RSP, R8
|
||||||
|
stackargs:
|
||||||
|
MOVD (R6)(R5), R7
|
||||||
|
MOVD R7, (R6)(R8)
|
||||||
|
ADD $8, R6
|
||||||
|
CMP R6, R4
|
||||||
|
BNE stackargs
|
||||||
|
|
||||||
|
_8args:
|
||||||
|
MOVD (7*8)(R12), R7
|
||||||
|
_7args:
|
||||||
|
MOVD (6*8)(R12), R6
|
||||||
|
_6args:
|
||||||
|
MOVD (5*8)(R12), R5
|
||||||
|
_5args:
|
||||||
|
MOVD (4*8)(R12), R4
|
||||||
|
_4args:
|
||||||
|
MOVD (3*8)(R12), R3
|
||||||
|
_3args:
|
||||||
|
MOVD (2*8)(R12), R2
|
||||||
|
_2args:
|
||||||
|
MOVD (1*8)(R12), R1
|
||||||
|
_1args:
|
||||||
|
MOVD (0*8)(R12), R0
|
||||||
|
_0args:
|
||||||
|
|
||||||
|
MOVD StdCallInfo_Fn(R19), R12
|
||||||
|
BL (R12)
|
||||||
|
|
||||||
|
MOVD R20, RSP // free stack space
|
||||||
|
MOVD R0, StdCallInfo_R1(R19) // save return value
|
||||||
|
// TODO(rsc) floating point like amd64 in StdCallInfo_R2?
|
||||||
|
|
||||||
|
// GetLastError
|
||||||
|
MOVD TEB_error(R18_PLATFORM), R0
|
||||||
|
MOVD R0, StdCallInfo_Err(R19)
|
||||||
|
|
||||||
|
// Restore callee-saved registers.
|
||||||
|
LDP 16(RSP), (R19, R20)
|
||||||
|
RET
|
44
src/internal/runtime/syscall/windows/syscall_windows.go
Normal file
44
src/internal/runtime/syscall/windows/syscall_windows.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright 2025 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package windows provides the syscall primitives required for the runtime.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"internal/abi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MaxArgs should be divisible by 2, as Windows stack
|
||||||
|
// must be kept 16-byte aligned on syscall entry.
|
||||||
|
//
|
||||||
|
// Although it only permits maximum 42 parameters, it
|
||||||
|
// is arguably large enough.
|
||||||
|
const MaxArgs = 42
|
||||||
|
|
||||||
|
// StdCallInfo is a structure used to pass parameters to the system call.
|
||||||
|
type StdCallInfo struct {
|
||||||
|
Fn uintptr
|
||||||
|
N uintptr // number of parameters
|
||||||
|
Args uintptr // parameters
|
||||||
|
R1 uintptr // return values
|
||||||
|
R2 uintptr
|
||||||
|
Err uintptr // error number
|
||||||
|
}
|
||||||
|
|
||||||
|
// StdCall calls a function using Windows' stdcall convention.
|
||||||
|
//
|
||||||
|
//go:noescape
|
||||||
|
func StdCall(fn *StdCallInfo)
|
||||||
|
|
||||||
|
// asmstdcall is the function pointer for [AsmStdCallAddr].
|
||||||
|
func asmstdcall(fn *StdCallInfo)
|
||||||
|
|
||||||
|
// AsmStdCallAddr is the address of a function that accepts a pointer
|
||||||
|
// to [StdCallInfo] stored on the stack following the C calling convention,
|
||||||
|
// and calls the function using Windows' stdcall calling convention.
|
||||||
|
// Shouldn't be called directly from Go.
|
||||||
|
func AsmStdCallAddr() uintptr {
|
||||||
|
return abi.FuncPCABI0(asmstdcall)
|
||||||
|
}
|
|
@ -191,8 +191,8 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
|
||||||
|
|
||||||
osPreemptExtExit(mp)
|
osPreemptExtExit(mp)
|
||||||
|
|
||||||
// Save current syscall parameters, so m.winsyscall can be
|
// After exitsyscall we can be rescheduled on a different M,
|
||||||
// used again if callback decide to make syscall.
|
// so we need to restore the original M's winsyscall.
|
||||||
winsyscall := mp.winsyscall
|
winsyscall := mp.winsyscall
|
||||||
|
|
||||||
exitsyscall()
|
exitsyscall()
|
||||||
|
|
|
@ -11,8 +11,6 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const MaxArgs = maxArgs
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
OsYield = osyield
|
OsYield = osyield
|
||||||
TimeBeginPeriodRetValue = &timeBeginPeriodRetValue
|
TimeBeginPeriodRetValue = &timeBeginPeriodRetValue
|
||||||
|
|
|
@ -27,6 +27,7 @@ type funcDescriptor struct {
|
||||||
type mOS struct {
|
type mOS struct {
|
||||||
waitsema uintptr // semaphore for parking on locks
|
waitsema uintptr // semaphore for parking on locks
|
||||||
perrno uintptr // pointer to tls errno
|
perrno uintptr // pointer to tls errno
|
||||||
|
libcall libcall
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
|
|
|
@ -21,9 +21,8 @@ type mscratch struct {
|
||||||
type mOS struct {
|
type mOS struct {
|
||||||
waitsema uintptr // semaphore for parking on locks
|
waitsema uintptr // semaphore for parking on locks
|
||||||
perrno *int32 // pointer to tls errno
|
perrno *int32 // pointer to tls errno
|
||||||
// these are here because they are too large to be on the stack
|
// This is here to avoid using the G stack so the stack can move during the call.
|
||||||
// of low-level NOSPLIT functions.
|
libcall libcall
|
||||||
//LibCall libcall;
|
|
||||||
ts mts
|
ts mts
|
||||||
scratch mscratch
|
scratch mscratch
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"internal/abi"
|
"internal/abi"
|
||||||
"internal/runtime/atomic"
|
"internal/runtime/atomic"
|
||||||
"internal/runtime/sys"
|
"internal/runtime/sys"
|
||||||
|
"internal/runtime/syscall/windows"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -160,6 +161,9 @@ func tstart_stdcall(newm *m)
|
||||||
func wintls()
|
func wintls()
|
||||||
|
|
||||||
type mOS struct {
|
type mOS struct {
|
||||||
|
// This is here to avoid using the G stack so the stack can move during the call.
|
||||||
|
stdCallInfo windows.StdCallInfo
|
||||||
|
|
||||||
threadLock mutex // protects "thread" and prevents closing
|
threadLock mutex // protects "thread" and prevents closing
|
||||||
thread uintptr // thread handle
|
thread uintptr // thread handle
|
||||||
|
|
||||||
|
@ -210,13 +214,9 @@ func read(fd int32, p unsafe.Pointer, n int32) int32 {
|
||||||
|
|
||||||
type sigset struct{}
|
type sigset struct{}
|
||||||
|
|
||||||
// Call a Windows function with stdcall conventions,
|
|
||||||
// and switch to os stack during the call.
|
|
||||||
func asmstdcall(fn unsafe.Pointer)
|
|
||||||
|
|
||||||
var asmstdcallAddr unsafe.Pointer
|
var asmstdcallAddr unsafe.Pointer
|
||||||
|
|
||||||
type winlibcall libcall
|
type winlibcall windows.StdCallInfo
|
||||||
|
|
||||||
func windowsFindfunc(lib uintptr, name []byte) stdFunction {
|
func windowsFindfunc(lib uintptr, name []byte) stdFunction {
|
||||||
if name[len(name)-1] != 0 {
|
if name[len(name)-1] != 0 {
|
||||||
|
@ -472,7 +472,7 @@ func initLongPathSupport() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func osinit() {
|
func osinit() {
|
||||||
asmstdcallAddr = unsafe.Pointer(abi.FuncPCABI0(asmstdcall))
|
asmstdcallAddr = unsafe.Pointer(windows.AsmStdCallAddr())
|
||||||
|
|
||||||
loadOptionalSyscalls()
|
loadOptionalSyscalls()
|
||||||
|
|
||||||
|
@ -935,20 +935,17 @@ func mdestroy(mp *m) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// asmstdcall_trampoline calls asmstdcall converting from Go to C calling convention.
|
|
||||||
func asmstdcall_trampoline(args unsafe.Pointer)
|
|
||||||
|
|
||||||
// stdcall_no_g calls asmstdcall on os stack without using g.
|
// stdcall_no_g calls asmstdcall on os stack without using g.
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func stdcall_no_g(fn stdFunction, n int, args uintptr) uintptr {
|
func stdcall_no_g(fn stdFunction, n int, args uintptr) uintptr {
|
||||||
libcall := libcall{
|
call := windows.StdCallInfo{
|
||||||
fn: uintptr(unsafe.Pointer(fn)),
|
Fn: uintptr(unsafe.Pointer(fn)),
|
||||||
n: uintptr(n),
|
N: uintptr(n),
|
||||||
args: args,
|
Args: args,
|
||||||
}
|
}
|
||||||
asmstdcall_trampoline(noescape(unsafe.Pointer(&libcall)))
|
windows.StdCall(&call)
|
||||||
return libcall.r1
|
return call.R1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calling stdcall on os stack.
|
// Calling stdcall on os stack.
|
||||||
|
@ -959,7 +956,7 @@ func stdcall_no_g(fn stdFunction, n int, args uintptr) uintptr {
|
||||||
func stdcall(fn stdFunction) uintptr {
|
func stdcall(fn stdFunction) uintptr {
|
||||||
gp := getg()
|
gp := getg()
|
||||||
mp := gp.m
|
mp := gp.m
|
||||||
mp.libcall.fn = uintptr(unsafe.Pointer(fn))
|
mp.stdCallInfo.Fn = uintptr(unsafe.Pointer(fn))
|
||||||
resetLibcall := false
|
resetLibcall := false
|
||||||
if mp.profilehz != 0 && mp.libcallsp == 0 {
|
if mp.profilehz != 0 && mp.libcallsp == 0 {
|
||||||
// leave pc/sp for cpu profiler
|
// leave pc/sp for cpu profiler
|
||||||
|
@ -970,18 +967,18 @@ func stdcall(fn stdFunction) uintptr {
|
||||||
mp.libcallsp = sys.GetCallerSP()
|
mp.libcallsp = sys.GetCallerSP()
|
||||||
resetLibcall = true // See comment in sys_darwin.go:libcCall
|
resetLibcall = true // See comment in sys_darwin.go:libcCall
|
||||||
}
|
}
|
||||||
asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
|
asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.stdCallInfo))
|
||||||
if resetLibcall {
|
if resetLibcall {
|
||||||
mp.libcallsp = 0
|
mp.libcallsp = 0
|
||||||
}
|
}
|
||||||
return mp.libcall.r1
|
return mp.stdCallInfo.R1
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func stdcall0(fn stdFunction) uintptr {
|
func stdcall0(fn stdFunction) uintptr {
|
||||||
mp := getg().m
|
mp := getg().m
|
||||||
mp.libcall.n = 0
|
mp.stdCallInfo.N = 0
|
||||||
mp.libcall.args = 0
|
mp.stdCallInfo.Args = 0
|
||||||
return stdcall(fn)
|
return stdcall(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -989,8 +986,8 @@ func stdcall0(fn stdFunction) uintptr {
|
||||||
//go:cgo_unsafe_args
|
//go:cgo_unsafe_args
|
||||||
func stdcall1(fn stdFunction, a0 uintptr) uintptr {
|
func stdcall1(fn stdFunction, a0 uintptr) uintptr {
|
||||||
mp := getg().m
|
mp := getg().m
|
||||||
mp.libcall.n = 1
|
mp.stdCallInfo.N = 1
|
||||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||||
return stdcall(fn)
|
return stdcall(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -998,8 +995,8 @@ func stdcall1(fn stdFunction, a0 uintptr) uintptr {
|
||||||
//go:cgo_unsafe_args
|
//go:cgo_unsafe_args
|
||||||
func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
|
func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
|
||||||
mp := getg().m
|
mp := getg().m
|
||||||
mp.libcall.n = 2
|
mp.stdCallInfo.N = 2
|
||||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||||
return stdcall(fn)
|
return stdcall(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1007,8 +1004,8 @@ func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
|
||||||
//go:cgo_unsafe_args
|
//go:cgo_unsafe_args
|
||||||
func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
|
func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
|
||||||
mp := getg().m
|
mp := getg().m
|
||||||
mp.libcall.n = 3
|
mp.stdCallInfo.N = 3
|
||||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||||
return stdcall(fn)
|
return stdcall(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1016,8 +1013,8 @@ func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
|
||||||
//go:cgo_unsafe_args
|
//go:cgo_unsafe_args
|
||||||
func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
|
func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
|
||||||
mp := getg().m
|
mp := getg().m
|
||||||
mp.libcall.n = 4
|
mp.stdCallInfo.N = 4
|
||||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||||
return stdcall(fn)
|
return stdcall(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1025,8 +1022,8 @@ func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
|
||||||
//go:cgo_unsafe_args
|
//go:cgo_unsafe_args
|
||||||
func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
|
func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
|
||||||
mp := getg().m
|
mp := getg().m
|
||||||
mp.libcall.n = 5
|
mp.stdCallInfo.N = 5
|
||||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||||
return stdcall(fn)
|
return stdcall(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1034,8 +1031,8 @@ func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
|
||||||
//go:cgo_unsafe_args
|
//go:cgo_unsafe_args
|
||||||
func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
|
func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
|
||||||
mp := getg().m
|
mp := getg().m
|
||||||
mp.libcall.n = 6
|
mp.stdCallInfo.N = 6
|
||||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||||
return stdcall(fn)
|
return stdcall(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1043,8 +1040,8 @@ func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
|
||||||
//go:cgo_unsafe_args
|
//go:cgo_unsafe_args
|
||||||
func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
|
func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
|
||||||
mp := getg().m
|
mp := getg().m
|
||||||
mp.libcall.n = 7
|
mp.stdCallInfo.N = 7
|
||||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||||
return stdcall(fn)
|
return stdcall(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1052,8 +1049,8 @@ func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
|
||||||
//go:cgo_unsafe_args
|
//go:cgo_unsafe_args
|
||||||
func stdcall8(fn stdFunction, a0, a1, a2, a3, a4, a5, a6, a7 uintptr) uintptr {
|
func stdcall8(fn stdFunction, a0, a1, a2, a3, a4, a5, a6, a7 uintptr) uintptr {
|
||||||
mp := getg().m
|
mp := getg().m
|
||||||
mp.libcall.n = 8
|
mp.stdCallInfo.N = 8
|
||||||
mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
|
mp.stdCallInfo.Args = uintptr(noescape(unsafe.Pointer(&a0)))
|
||||||
return stdcall(fn)
|
return stdcall(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -593,9 +593,7 @@ type m struct {
|
||||||
freelink *m // on sched.freem
|
freelink *m // on sched.freem
|
||||||
trace mTraceState
|
trace mTraceState
|
||||||
|
|
||||||
// these are here because they are too large to be on the stack
|
// These are here to avoid using the G stack so the stack can move during the call.
|
||||||
// of low-level NOSPLIT functions.
|
|
||||||
libcall libcall
|
|
||||||
libcallpc uintptr // for cpu profiler
|
libcallpc uintptr // for cpu profiler
|
||||||
libcallsp uintptr
|
libcallsp uintptr
|
||||||
libcallg guintptr
|
libcallg guintptr
|
||||||
|
|
|
@ -130,15 +130,15 @@ TEXT sigtramp<>(SB),NOSPLIT|NOFRAME|TOPFRAME,$0
|
||||||
|
|
||||||
// Save m->libcall. We need to do this because we
|
// Save m->libcall. We need to do this because we
|
||||||
// might get interrupted by a signal in runtime·asmcgocall.
|
// might get interrupted by a signal in runtime·asmcgocall.
|
||||||
MOVD (m_libcall+libcall_fn)(R6), R7
|
MOVD (m_mOS+mOS_libcall+libcall_fn)(R6), R7
|
||||||
MOVD R7, 96(R1)
|
MOVD R7, 96(R1)
|
||||||
MOVD (m_libcall+libcall_args)(R6), R7
|
MOVD (m_mOS+mOS_libcall+libcall_args)(R6), R7
|
||||||
MOVD R7, 104(R1)
|
MOVD R7, 104(R1)
|
||||||
MOVD (m_libcall+libcall_n)(R6), R7
|
MOVD (m_mOS+mOS_libcall+libcall_n)(R6), R7
|
||||||
MOVD R7, 112(R1)
|
MOVD R7, 112(R1)
|
||||||
MOVD (m_libcall+libcall_r1)(R6), R7
|
MOVD (m_mOS+mOS_libcall+libcall_r1)(R6), R7
|
||||||
MOVD R7, 120(R1)
|
MOVD R7, 120(R1)
|
||||||
MOVD (m_libcall+libcall_r2)(R6), R7
|
MOVD (m_mOS+mOS_libcall+libcall_r2)(R6), R7
|
||||||
MOVD R7, 128(R1)
|
MOVD R7, 128(R1)
|
||||||
|
|
||||||
// save errno, it might be EINTR; stuff we do here might reset it.
|
// save errno, it might be EINTR; stuff we do here might reset it.
|
||||||
|
@ -162,15 +162,15 @@ sigtramp:
|
||||||
|
|
||||||
// restore libcall
|
// restore libcall
|
||||||
MOVD 96(R1), R7
|
MOVD 96(R1), R7
|
||||||
MOVD R7, (m_libcall+libcall_fn)(R6)
|
MOVD R7, (m_mOS+mOS_libcall+libcall_fn)(R6)
|
||||||
MOVD 104(R1), R7
|
MOVD 104(R1), R7
|
||||||
MOVD R7, (m_libcall+libcall_args)(R6)
|
MOVD R7, (m_mOS+mOS_libcall+libcall_args)(R6)
|
||||||
MOVD 112(R1), R7
|
MOVD 112(R1), R7
|
||||||
MOVD R7, (m_libcall+libcall_n)(R6)
|
MOVD R7, (m_mOS+mOS_libcall+libcall_n)(R6)
|
||||||
MOVD 120(R1), R7
|
MOVD 120(R1), R7
|
||||||
MOVD R7, (m_libcall+libcall_r1)(R6)
|
MOVD R7, (m_mOS+mOS_libcall+libcall_r1)(R6)
|
||||||
MOVD 128(R1), R7
|
MOVD 128(R1), R7
|
||||||
MOVD R7, (m_libcall+libcall_r2)(R6)
|
MOVD R7, (m_mOS+mOS_libcall+libcall_r2)(R6)
|
||||||
|
|
||||||
// restore errno
|
// restore errno
|
||||||
MOVD (m_mOS+mOS_perrno)(R6), R7
|
MOVD (m_mOS+mOS_perrno)(R6), R7
|
||||||
|
|
|
@ -155,7 +155,7 @@ allgood:
|
||||||
|
|
||||||
// save m->libcall
|
// save m->libcall
|
||||||
MOVQ g_m(R10), BP
|
MOVQ g_m(R10), BP
|
||||||
LEAQ m_libcall(BP), R11
|
LEAQ (m_mOS+mOS_libcall)(BP), R11
|
||||||
MOVQ libcall_fn(R11), R10
|
MOVQ libcall_fn(R11), R10
|
||||||
MOVQ R10, 72(SP)
|
MOVQ R10, 72(SP)
|
||||||
MOVQ libcall_args(R11), R10
|
MOVQ libcall_args(R11), R10
|
||||||
|
@ -197,7 +197,7 @@ allgood:
|
||||||
MOVQ g(BX), BP
|
MOVQ g(BX), BP
|
||||||
MOVQ g_m(BP), BP
|
MOVQ g_m(BP), BP
|
||||||
// restore libcall
|
// restore libcall
|
||||||
LEAQ m_libcall(BP), R11
|
LEAQ (m_mOS+mOS_libcall)(BP), R11
|
||||||
MOVQ 72(SP), R10
|
MOVQ 72(SP), R10
|
||||||
MOVQ R10, libcall_fn(R11)
|
MOVQ R10, libcall_fn(R11)
|
||||||
MOVQ 80(SP), R10
|
MOVQ 80(SP), R10
|
||||||
|
|
|
@ -11,49 +11,6 @@
|
||||||
#define TEB_TlsSlots 0xE10
|
#define TEB_TlsSlots 0xE10
|
||||||
#define TEB_ArbitraryPtr 0x14
|
#define TEB_ArbitraryPtr 0x14
|
||||||
|
|
||||||
TEXT runtime·asmstdcall_trampoline<ABIInternal>(SB),NOSPLIT,$0
|
|
||||||
JMP runtime·asmstdcall(SB)
|
|
||||||
|
|
||||||
// void runtime·asmstdcall(void *c);
|
|
||||||
TEXT runtime·asmstdcall(SB),NOSPLIT,$0
|
|
||||||
MOVL fn+0(FP), BX
|
|
||||||
MOVL SP, BP // save stack pointer
|
|
||||||
|
|
||||||
// SetLastError(0).
|
|
||||||
MOVL $0, 0x34(FS)
|
|
||||||
|
|
||||||
MOVL libcall_n(BX), CX
|
|
||||||
|
|
||||||
// Fast version, do not store args on the stack.
|
|
||||||
CMPL CX, $0
|
|
||||||
JE docall
|
|
||||||
|
|
||||||
// Copy args to the stack.
|
|
||||||
MOVL CX, AX
|
|
||||||
SALL $2, AX
|
|
||||||
SUBL AX, SP // room for args
|
|
||||||
MOVL SP, DI
|
|
||||||
MOVL libcall_args(BX), SI
|
|
||||||
CLD
|
|
||||||
REP; MOVSL
|
|
||||||
|
|
||||||
docall:
|
|
||||||
// Call stdcall or cdecl function.
|
|
||||||
// DI SI BP BX are preserved, SP is not
|
|
||||||
CALL libcall_fn(BX)
|
|
||||||
MOVL BP, SP
|
|
||||||
|
|
||||||
// Return result.
|
|
||||||
MOVL fn+0(FP), BX
|
|
||||||
MOVL AX, libcall_r1(BX)
|
|
||||||
MOVL DX, libcall_r2(BX)
|
|
||||||
|
|
||||||
// GetLastError().
|
|
||||||
MOVL 0x34(FS), AX
|
|
||||||
MOVL AX, libcall_err(BX)
|
|
||||||
|
|
||||||
RET
|
|
||||||
|
|
||||||
// faster get/set last error
|
// faster get/set last error
|
||||||
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
||||||
MOVL 0x34(FS), AX
|
MOVL 0x34(FS), AX
|
||||||
|
|
|
@ -12,85 +12,6 @@
|
||||||
#define TEB_TlsSlots 0x1480
|
#define TEB_TlsSlots 0x1480
|
||||||
#define TEB_ArbitraryPtr 0x28
|
#define TEB_ArbitraryPtr 0x28
|
||||||
|
|
||||||
TEXT runtime·asmstdcall_trampoline<ABIInternal>(SB),NOSPLIT,$0
|
|
||||||
MOVQ AX, CX
|
|
||||||
JMP runtime·asmstdcall(SB)
|
|
||||||
|
|
||||||
// void runtime·asmstdcall(void *c);
|
|
||||||
TEXT runtime·asmstdcall(SB),NOSPLIT,$16
|
|
||||||
MOVQ SP, AX
|
|
||||||
ANDQ $~15, SP // alignment as per Windows requirement
|
|
||||||
MOVQ AX, 8(SP)
|
|
||||||
MOVQ CX, 0(SP) // asmcgocall will put first argument into CX.
|
|
||||||
|
|
||||||
MOVQ libcall_fn(CX), AX
|
|
||||||
MOVQ libcall_args(CX), SI
|
|
||||||
MOVQ libcall_n(CX), CX
|
|
||||||
|
|
||||||
// SetLastError(0).
|
|
||||||
MOVQ 0x30(GS), DI
|
|
||||||
MOVL $0, 0x68(DI)
|
|
||||||
|
|
||||||
SUBQ $(const_maxArgs*8), SP // room for args
|
|
||||||
|
|
||||||
// Fast version, do not store args on the stack.
|
|
||||||
CMPL CX, $0; JE _0args
|
|
||||||
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.
|
|
||||||
CMPL CX, $const_maxArgs
|
|
||||||
JLE 2(PC)
|
|
||||||
INT $3 // not enough room -> crash
|
|
||||||
|
|
||||||
// Copy args to the stack.
|
|
||||||
MOVQ SP, DI
|
|
||||||
CLD
|
|
||||||
REP; MOVSQ
|
|
||||||
MOVQ SP, SI
|
|
||||||
|
|
||||||
// Load first 4 args into correspondent registers.
|
|
||||||
// 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://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
|
|
||||||
_4args:
|
|
||||||
MOVQ 24(SI), R9
|
|
||||||
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:
|
|
||||||
|
|
||||||
// Call stdcall function.
|
|
||||||
CALL AX
|
|
||||||
|
|
||||||
ADDQ $(const_maxArgs*8), SP
|
|
||||||
|
|
||||||
// Return result.
|
|
||||||
MOVQ 0(SP), CX
|
|
||||||
MOVQ 8(SP), SP
|
|
||||||
MOVQ AX, libcall_r1(CX)
|
|
||||||
// Floating point return values are returned in XMM0. Setting r2 to this
|
|
||||||
// value in case this call returned a floating point value. For details,
|
|
||||||
// see https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
|
|
||||||
MOVQ X0, libcall_r2(CX)
|
|
||||||
|
|
||||||
// GetLastError().
|
|
||||||
MOVQ 0x30(GS), DI
|
|
||||||
MOVL 0x68(DI), AX
|
|
||||||
MOVQ AX, libcall_err(CX)
|
|
||||||
|
|
||||||
RET
|
|
||||||
|
|
||||||
// faster get/set last error
|
// faster get/set last error
|
||||||
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
||||||
MOVQ 0x30(GS), AX
|
MOVQ 0x30(GS), AX
|
||||||
|
|
|
@ -9,76 +9,6 @@
|
||||||
|
|
||||||
// Note: For system ABI, R0-R3 are args, R4-R11 are callee-save.
|
// Note: For system ABI, R0-R3 are args, R4-R11 are callee-save.
|
||||||
|
|
||||||
TEXT runtime·asmstdcall_trampoline<ABIInternal>(SB),NOSPLIT,$0
|
|
||||||
B runtime·asmstdcall(SB)
|
|
||||||
|
|
||||||
// void runtime·asmstdcall(void *c);
|
|
||||||
TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0
|
|
||||||
MOVM.DB.W [R4, R5, R14], (R13) // push {r4, r5, lr}
|
|
||||||
MOVW R0, R4 // put libcall * in r4
|
|
||||||
MOVW R13, R5 // save stack pointer in r5
|
|
||||||
|
|
||||||
// SetLastError(0)
|
|
||||||
MOVW $0, R0
|
|
||||||
MRC 15, 0, R1, C13, C0, 2
|
|
||||||
MOVW R0, 0x34(R1)
|
|
||||||
|
|
||||||
MOVW 8(R4), R12 // libcall->args
|
|
||||||
|
|
||||||
// Do we have more than 4 arguments?
|
|
||||||
MOVW 4(R4), R0 // libcall->n
|
|
||||||
SUB.S $4, R0, R2
|
|
||||||
BLE loadregs
|
|
||||||
|
|
||||||
// Reserve stack space for remaining args
|
|
||||||
SUB R2<<2, R13
|
|
||||||
BIC $0x7, R13 // alignment for ABI
|
|
||||||
|
|
||||||
// R0: count of arguments
|
|
||||||
// R1:
|
|
||||||
// R2: loop counter, from 0 to (n-4)
|
|
||||||
// R3: scratch
|
|
||||||
// R4: pointer to libcall struct
|
|
||||||
// R12: libcall->args
|
|
||||||
MOVW $0, R2
|
|
||||||
stackargs:
|
|
||||||
ADD $4, R2, R3 // r3 = args[4 + i]
|
|
||||||
MOVW R3<<2(R12), R3
|
|
||||||
MOVW R3, R2<<2(R13) // stack[i] = r3
|
|
||||||
|
|
||||||
ADD $1, R2 // i++
|
|
||||||
SUB $4, R0, R3 // while (i < (n - 4))
|
|
||||||
CMP R3, R2
|
|
||||||
BLT stackargs
|
|
||||||
|
|
||||||
loadregs:
|
|
||||||
CMP $3, R0
|
|
||||||
MOVW.GT 12(R12), R3
|
|
||||||
|
|
||||||
CMP $2, R0
|
|
||||||
MOVW.GT 8(R12), R2
|
|
||||||
|
|
||||||
CMP $1, R0
|
|
||||||
MOVW.GT 4(R12), R1
|
|
||||||
|
|
||||||
CMP $0, R0
|
|
||||||
MOVW.GT 0(R12), R0
|
|
||||||
|
|
||||||
BIC $0x7, R13 // alignment for ABI
|
|
||||||
MOVW 0(R4), R12 // branch to libcall->fn
|
|
||||||
BL (R12)
|
|
||||||
|
|
||||||
MOVW R5, R13 // free stack space
|
|
||||||
MOVW R0, 12(R4) // save return value to libcall->r1
|
|
||||||
MOVW R1, 16(R4)
|
|
||||||
|
|
||||||
// GetLastError
|
|
||||||
MRC 15, 0, R1, C13, C0, 2
|
|
||||||
MOVW 0x34(R1), R0
|
|
||||||
MOVW R0, 20(R4) // store in libcall->err
|
|
||||||
|
|
||||||
MOVM.IA.W (R13), [R4, R5, R15]
|
|
||||||
|
|
||||||
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
||||||
MRC 15, 0, R0, C13, C0, 2
|
MRC 15, 0, R0, C13, C0, 2
|
||||||
MOVW 0x34(R0), R0
|
MOVW 0x34(R0), R0
|
||||||
|
|
|
@ -19,88 +19,6 @@
|
||||||
//
|
//
|
||||||
// load_g and save_g (in tls_arm64.s) clobber R27 (REGTMP) and R0.
|
// load_g and save_g (in tls_arm64.s) clobber R27 (REGTMP) and R0.
|
||||||
|
|
||||||
TEXT runtime·asmstdcall_trampoline<ABIInternal>(SB),NOSPLIT,$0
|
|
||||||
B runtime·asmstdcall(SB)
|
|
||||||
|
|
||||||
// void runtime·asmstdcall(void *c);
|
|
||||||
TEXT runtime·asmstdcall(SB),NOSPLIT,$16
|
|
||||||
STP (R19, R20), 16(RSP) // save old R19, R20
|
|
||||||
MOVD R0, R19 // save libcall pointer
|
|
||||||
MOVD RSP, R20 // save stack pointer
|
|
||||||
|
|
||||||
// SetLastError(0)
|
|
||||||
MOVD $0, TEB_error(R18_PLATFORM)
|
|
||||||
MOVD libcall_args(R19), R12 // libcall->args
|
|
||||||
|
|
||||||
// Do we have more than 8 arguments?
|
|
||||||
MOVD libcall_n(R19), R0
|
|
||||||
CMP $0, R0; BEQ _0args
|
|
||||||
CMP $1, R0; BEQ _1args
|
|
||||||
CMP $2, R0; BEQ _2args
|
|
||||||
CMP $3, R0; BEQ _3args
|
|
||||||
CMP $4, R0; BEQ _4args
|
|
||||||
CMP $5, R0; BEQ _5args
|
|
||||||
CMP $6, R0; BEQ _6args
|
|
||||||
CMP $7, R0; BEQ _7args
|
|
||||||
CMP $8, R0; BEQ _8args
|
|
||||||
|
|
||||||
// Reserve stack space for remaining args
|
|
||||||
SUB $8, R0, R2
|
|
||||||
ADD $1, R2, R3 // make even number of words for stack alignment
|
|
||||||
AND $~1, R3
|
|
||||||
LSL $3, R3
|
|
||||||
SUB R3, RSP
|
|
||||||
|
|
||||||
// R4: size of stack arguments (n-8)*8
|
|
||||||
// R5: &args[8]
|
|
||||||
// R6: loop counter, from 0 to (n-8)*8
|
|
||||||
// R7: scratch
|
|
||||||
// R8: copy of RSP - (R2)(RSP) assembles as (R2)(ZR)
|
|
||||||
SUB $8, R0, R4
|
|
||||||
LSL $3, R4
|
|
||||||
ADD $(8*8), R12, R5
|
|
||||||
MOVD $0, R6
|
|
||||||
MOVD RSP, R8
|
|
||||||
stackargs:
|
|
||||||
MOVD (R6)(R5), R7
|
|
||||||
MOVD R7, (R6)(R8)
|
|
||||||
ADD $8, R6
|
|
||||||
CMP R6, R4
|
|
||||||
BNE stackargs
|
|
||||||
|
|
||||||
_8args:
|
|
||||||
MOVD (7*8)(R12), R7
|
|
||||||
_7args:
|
|
||||||
MOVD (6*8)(R12), R6
|
|
||||||
_6args:
|
|
||||||
MOVD (5*8)(R12), R5
|
|
||||||
_5args:
|
|
||||||
MOVD (4*8)(R12), R4
|
|
||||||
_4args:
|
|
||||||
MOVD (3*8)(R12), R3
|
|
||||||
_3args:
|
|
||||||
MOVD (2*8)(R12), R2
|
|
||||||
_2args:
|
|
||||||
MOVD (1*8)(R12), R1
|
|
||||||
_1args:
|
|
||||||
MOVD (0*8)(R12), R0
|
|
||||||
_0args:
|
|
||||||
|
|
||||||
MOVD libcall_fn(R19), R12 // branch to libcall->fn
|
|
||||||
BL (R12)
|
|
||||||
|
|
||||||
MOVD R20, RSP // free stack space
|
|
||||||
MOVD R0, libcall_r1(R19) // save return value to libcall->r1
|
|
||||||
// TODO(rsc) floating point like amd64 in libcall->r2?
|
|
||||||
|
|
||||||
// GetLastError
|
|
||||||
MOVD TEB_error(R18_PLATFORM), R0
|
|
||||||
MOVD R0, libcall_err(R19)
|
|
||||||
|
|
||||||
// Restore callee-saved registers.
|
|
||||||
LDP 16(RSP), (R19, R20)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
TEXT runtime·getlasterror(SB),NOSPLIT,$0
|
||||||
MOVD TEB_error(R18_PLATFORM), R0
|
MOVD TEB_error(R18_PLATFORM), R0
|
||||||
MOVD R0, ret+0(FP)
|
MOVD R0, ret+0(FP)
|
||||||
|
|
|
@ -7,6 +7,7 @@ package runtime
|
||||||
import (
|
import (
|
||||||
"internal/abi"
|
"internal/abi"
|
||||||
"internal/goarch"
|
"internal/goarch"
|
||||||
|
"internal/runtime/syscall/windows"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -487,13 +488,6 @@ func syscall_Syscall18(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
|
||||||
return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18)
|
return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18)
|
||||||
}
|
}
|
||||||
|
|
||||||
// maxArgs should be divisible by 2, as Windows stack
|
|
||||||
// must be kept 16-byte aligned on syscall entry.
|
|
||||||
//
|
|
||||||
// Although it only permits maximum 42 parameters, it
|
|
||||||
// is arguably large enough.
|
|
||||||
const maxArgs = 42
|
|
||||||
|
|
||||||
//go:linkname syscall_SyscallN syscall.SyscallN
|
//go:linkname syscall_SyscallN syscall.SyscallN
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func syscall_SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
|
func syscall_SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
|
||||||
|
@ -505,7 +499,7 @@ func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) {
|
||||||
if n > uintptr(len(args)) {
|
if n > uintptr(len(args)) {
|
||||||
panic("syscall: n > len(args)") // should not be reachable from user code
|
panic("syscall: n > len(args)") // should not be reachable from user code
|
||||||
}
|
}
|
||||||
if n > maxArgs {
|
if n > windows.MaxArgs {
|
||||||
panic("runtime: SyscallN has too many arguments")
|
panic("runtime: SyscallN has too many arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,15 +507,15 @@ func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) {
|
||||||
// the stack because the stack can move during fn if it
|
// the stack because the stack can move during fn if it
|
||||||
// calls back into Go.
|
// calls back into Go.
|
||||||
c := &getg().m.winsyscall
|
c := &getg().m.winsyscall
|
||||||
c.fn = fn
|
c.Fn = fn
|
||||||
c.n = n
|
c.N = n
|
||||||
if c.n != 0 {
|
if c.N != 0 {
|
||||||
c.args = uintptr(noescape(unsafe.Pointer(&args[0])))
|
c.Args = uintptr(noescape(unsafe.Pointer(&args[0])))
|
||||||
}
|
}
|
||||||
cgocall(asmstdcallAddr, unsafe.Pointer(c))
|
cgocall(asmstdcallAddr, unsafe.Pointer(c))
|
||||||
// cgocall may reschedule us on to a different M,
|
// cgocall may reschedule us on to a different M,
|
||||||
// but it copies the return values into the new M's
|
// but it copies the return values into the new M's
|
||||||
// so we can read them from there.
|
// so we can read them from there.
|
||||||
c = &getg().m.winsyscall
|
c = &getg().m.winsyscall
|
||||||
return c.r1, c.r2, c.err
|
return c.R1, c.R2, c.Err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"internal/abi"
|
"internal/abi"
|
||||||
"internal/race"
|
"internal/race"
|
||||||
|
"internal/runtime/syscall/windows"
|
||||||
"internal/syscall/windows/sysdll"
|
"internal/syscall/windows/sysdll"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io"
|
"io"
|
||||||
|
@ -776,7 +777,7 @@ func TestSyscallN(t *testing.T) {
|
||||||
t.Skipf("skipping test: GOARCH=%s", runtime.GOARCH)
|
t.Skipf("skipping test: GOARCH=%s", runtime.GOARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
for arglen := 0; arglen <= runtime.MaxArgs; arglen++ {
|
for arglen := 0; arglen <= windows.MaxArgs; arglen++ {
|
||||||
arglen := arglen
|
arglen := arglen
|
||||||
t.Run(fmt.Sprintf("arg-%d", arglen), func(t *testing.T) {
|
t.Run(fmt.Sprintf("arg-%d", arglen), func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue