...

Text file src/runtime/sys_windows_amd64.s

Documentation: runtime

     1// Copyright 2011 The Go Authors. All rights reserved.
     2// Use of this source code is governed by a BSD-style
     3// license that can be found in the LICENSE file.
     4
     5#include "go_asm.h"
     6#include "go_tls.h"
     7#include "textflag.h"
     8#include "time_windows.h"
     9#include "cgo/abi_amd64.h"
    10
    11// Offsets into Thread Environment Block (pointer in GS)
    12#define TEB_TlsSlots 0x1480
    13#define TEB_ArbitraryPtr 0x28
    14
    15TEXT runtime·asmstdcall_trampoline<ABIInternal>(SB),NOSPLIT,$0
    16	MOVQ	AX, CX
    17	JMP	runtime·asmstdcall(SB)
    18
    19// void runtime·asmstdcall(void *c);
    20TEXT runtime·asmstdcall(SB),NOSPLIT,$16
    21	MOVQ	SP, AX
    22	ANDQ	$~15, SP	// alignment as per Windows requirement
    23	MOVQ	AX, 8(SP)
    24	MOVQ	CX, 0(SP)	// asmcgocall will put first argument into CX.
    25
    26	MOVQ	libcall_fn(CX), AX
    27	MOVQ	libcall_args(CX), SI
    28	MOVQ	libcall_n(CX), CX
    29
    30	// SetLastError(0).
    31	MOVQ	0x30(GS), DI
    32	MOVL	$0, 0x68(DI)
    33
    34	SUBQ	$(const_maxArgs*8), SP	// room for args
    35
    36	// Fast version, do not store args on the stack nor
    37	// load them into registers.
    38	CMPL	CX, $0
    39	JE	docall
    40
    41	// Fast version, do not store args on the stack.
    42	CMPL	CX, $4
    43	JLE	loadregs
    44
    45	// Check we have enough room for args.
    46	CMPL	CX, $const_maxArgs
    47	JLE	2(PC)
    48	INT	$3			// not enough room -> crash
    49
    50	// Copy args to the stack.
    51	MOVQ	SP, DI
    52	CLD
    53	REP; MOVSQ
    54	MOVQ	SP, SI
    55
    56loadregs:
    57	// Load first 4 args into correspondent registers.
    58	MOVQ	0(SI), CX
    59	MOVQ	8(SI), DX
    60	MOVQ	16(SI), R8
    61	MOVQ	24(SI), R9
    62	// Floating point arguments are passed in the XMM
    63	// registers. Set them here in case any of the arguments
    64	// are floating point values. For details see
    65	//	https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
    66	MOVQ	CX, X0
    67	MOVQ	DX, X1
    68	MOVQ	R8, X2
    69	MOVQ	R9, X3
    70
    71docall:
    72	// Call stdcall function.
    73	CALL	AX
    74
    75	ADDQ	$(const_maxArgs*8), SP
    76
    77	// Return result.
    78	MOVQ	0(SP), CX
    79	MOVQ	8(SP), SP
    80	MOVQ	AX, libcall_r1(CX)
    81	// Floating point return values are returned in XMM0. Setting r2 to this
    82	// value in case this call returned a floating point value. For details,
    83	// see https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
    84	MOVQ    X0, libcall_r2(CX)
    85
    86	// GetLastError().
    87	MOVQ	0x30(GS), DI
    88	MOVL	0x68(DI), AX
    89	MOVQ	AX, libcall_err(CX)
    90
    91	RET
    92
    93// faster get/set last error
    94TEXT runtime·getlasterror(SB),NOSPLIT,$0
    95	MOVQ	0x30(GS), AX
    96	MOVL	0x68(AX), AX
    97	MOVL	AX, ret+0(FP)
    98	RET
    99
   100// Called by Windows as a Vectored Exception Handler (VEH).
   101// CX is pointer to struct containing
   102// exception record and context pointers.
   103// DX is the kind of sigtramp function.
   104// Return value of sigtrampgo is stored in AX.
   105TEXT sigtramp<>(SB),NOSPLIT,$0-0
   106	// Switch from the host ABI to the Go ABI.
   107	PUSH_REGS_HOST_TO_ABI0()
   108
   109	// Set up ABIInternal environment: cleared X15 and R14.
   110	// R14 is cleared in case there's a non-zero value in there
   111	// if called from a non-go thread.
   112	XORPS	X15, X15
   113	XORQ	R14, R14
   114
   115	get_tls(AX)
   116	CMPQ	AX, $0
   117	JE	2(PC)
   118	// Exception from Go thread, set R14.
   119	MOVQ	g(AX), R14
   120
   121	// Reserve space for spill slots.
   122	ADJSP	$16
   123	MOVQ	CX, AX
   124	MOVQ	DX, BX
   125	// Calling ABIInternal because TLS might be nil.
   126	CALL	runtime·sigtrampgo<ABIInternal>(SB)
   127	// Return value is already stored in AX.
   128
   129	ADJSP	$-16
   130
   131	POP_REGS_HOST_TO_ABI0()
   132	RET
   133
   134// Trampoline to resume execution from exception handler.
   135// This is part of the control flow guard workaround.
   136// It switches stacks and jumps to the continuation address.
   137// R8 and R9 are set above at the end of sigtrampgo
   138// in the context that starts executing at sigresume.
   139TEXT runtime·sigresume(SB),NOSPLIT|NOFRAME,$0
   140	MOVQ	R8, SP
   141	JMP	R9
   142
   143TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0
   144	// PExceptionPointers already on CX
   145	MOVQ	$const_callbackVEH, DX
   146	JMP	sigtramp<>(SB)
   147
   148TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0
   149	// PExceptionPointers already on CX
   150	MOVQ	$const_callbackFirstVCH, DX
   151	JMP	sigtramp<>(SB)
   152
   153TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0
   154	// PExceptionPointers already on CX
   155	MOVQ	$const_callbackLastVCH, DX
   156	JMP	sigtramp<>(SB)
   157
   158TEXT runtime·sehtramp(SB),NOSPLIT,$40-0
   159	// CX: PEXCEPTION_RECORD ExceptionRecord
   160	// DX: ULONG64 EstablisherFrame
   161	// R8: PCONTEXT ContextRecord
   162	// R9: PDISPATCHER_CONTEXT DispatcherContext
   163	// Switch from the host ABI to the Go ABI.
   164	PUSH_REGS_HOST_TO_ABI0()
   165
   166	get_tls(AX)
   167	CMPQ	AX, $0
   168	JNE	2(PC)
   169	// This shouldn't happen, sehtramp is only attached to functions
   170	// called from Go, and exception handlers are only called from
   171	// the thread that threw the exception.
   172	INT	$3
   173
   174	// Exception from Go thread, set R14.
   175	MOVQ	g(AX), R14
   176
   177	ADJSP	$40
   178	MOVQ	CX, 0(SP)
   179	MOVQ	DX, 8(SP)
   180	MOVQ	R8, 16(SP)
   181	MOVQ	R9, 24(SP)
   182	CALL	runtime·sehhandler(SB)
   183	MOVL	32(SP), AX
   184
   185	ADJSP	$-40
   186
   187	POP_REGS_HOST_TO_ABI0()
   188	RET
   189
   190TEXT runtime·callbackasm1(SB),NOSPLIT|NOFRAME,$0
   191	// Construct args vector for cgocallback().
   192	// By windows/amd64 calling convention first 4 args are in CX, DX, R8, R9
   193	// args from the 5th on are on the stack.
   194	// In any case, even if function has 0,1,2,3,4 args, there is reserved
   195	// but uninitialized "shadow space" for the first 4 args.
   196	// The values are in registers.
   197	MOVQ	CX, (16+0)(SP)
   198	MOVQ	DX, (16+8)(SP)
   199	MOVQ	R8, (16+16)(SP)
   200	MOVQ	R9, (16+24)(SP)
   201	// R8 = address of args vector
   202	LEAQ	(16+0)(SP), R8
   203
   204	// remove return address from stack, we are not returning to callbackasm, but to its caller.
   205	MOVQ	0(SP), AX
   206	ADDQ	$8, SP
   207
   208	// determine index into runtime·cbs table
   209	MOVQ	$runtime·callbackasm(SB), DX
   210	SUBQ	DX, AX
   211	MOVQ	$0, DX
   212	MOVQ	$5, CX	// divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
   213	DIVL	CX
   214	SUBQ	$1, AX	// subtract 1 because return PC is to the next slot
   215
   216	// Switch from the host ABI to the Go ABI.
   217	PUSH_REGS_HOST_TO_ABI0()
   218
   219	// Create a struct callbackArgs on our stack to be passed as
   220	// the "frame" to cgocallback and on to callbackWrap.
   221	SUBQ	$(24+callbackArgs__size), SP
   222	MOVQ	AX, (24+callbackArgs_index)(SP) 	// callback index
   223	MOVQ	R8, (24+callbackArgs_args)(SP)  	// address of args vector
   224	MOVQ	$0, (24+callbackArgs_result)(SP)	// result
   225	LEAQ	24(SP), AX
   226	// Call cgocallback, which will call callbackWrap(frame).
   227	MOVQ	$0, 16(SP)	// context
   228	MOVQ	AX, 8(SP)	// frame (address of callbackArgs)
   229	LEAQ	·callbackWrap<ABIInternal>(SB), BX	// cgocallback takes an ABIInternal entry-point
   230	MOVQ	BX, 0(SP)	// PC of function value to call (callbackWrap)
   231	CALL	·cgocallback(SB)
   232	// Get callback result.
   233	MOVQ	(24+callbackArgs_result)(SP), AX
   234	ADDQ	$(24+callbackArgs__size), SP
   235
   236	POP_REGS_HOST_TO_ABI0()
   237
   238	// The return value was placed in AX above.
   239	RET
   240
   241// uint32 tstart_stdcall(M *newm);
   242TEXT runtime·tstart_stdcall(SB),NOSPLIT|NOFRAME,$0
   243	// Switch from the host ABI to the Go ABI.
   244	PUSH_REGS_HOST_TO_ABI0()
   245
   246	// CX contains first arg newm
   247	MOVQ	m_g0(CX), DX		// g
   248
   249	// Layout new m scheduler stack on os stack.
   250	MOVQ	SP, AX
   251	MOVQ	AX, (g_stack+stack_hi)(DX)
   252	SUBQ	$(64*1024), AX		// initial stack size (adjusted later)
   253	MOVQ	AX, (g_stack+stack_lo)(DX)
   254	ADDQ	$const_stackGuard, AX
   255	MOVQ	AX, g_stackguard0(DX)
   256	MOVQ	AX, g_stackguard1(DX)
   257
   258	// Set up tls.
   259	LEAQ	m_tls(CX), DI
   260	MOVQ	CX, g_m(DX)
   261	MOVQ	DX, g(DI)
   262	CALL	runtime·settls(SB) // clobbers CX
   263
   264	CALL	runtime·stackcheck(SB)	// clobbers AX,CX
   265	CALL	runtime·mstart(SB)
   266
   267	POP_REGS_HOST_TO_ABI0()
   268
   269	XORL	AX, AX			// return 0 == success
   270	RET
   271
   272// set tls base to DI
   273TEXT runtime·settls(SB),NOSPLIT,$0
   274	MOVQ	runtime·tls_g(SB), CX
   275	MOVQ	DI, 0(CX)(GS)
   276	RET
   277
   278TEXT runtime·nanotime1(SB),NOSPLIT,$0-8
   279	MOVQ	$_INTERRUPT_TIME, DI
   280	MOVQ	time_lo(DI), AX
   281	IMULQ	$100, AX
   282	MOVQ	AX, ret+0(FP)
   283	RET
   284
   285// func osSetupTLS(mp *m)
   286// Setup TLS. for use by needm on Windows.
   287TEXT runtime·osSetupTLS(SB),NOSPLIT,$0-8
   288	MOVQ	mp+0(FP), AX
   289	LEAQ	m_tls(AX), DI
   290	CALL	runtime·settls(SB)
   291	RET
   292
   293// This is called from rt0_go, which runs on the system stack
   294// using the initial stack allocated by the OS.
   295TEXT runtime·wintls(SB),NOSPLIT,$0
   296	// Allocate a TLS slot to hold g across calls to external code
   297	MOVQ	SP, AX
   298	ANDQ	$~15, SP	// alignment as per Windows requirement
   299	SUBQ	$48, SP	// room for SP and 4 args as per Windows requirement
   300			// plus one extra word to keep stack 16 bytes aligned
   301	MOVQ	AX, 32(SP)
   302	MOVQ	runtime·_TlsAlloc(SB), AX
   303	CALL	AX
   304	MOVQ	32(SP), SP
   305
   306	MOVQ	AX, CX	// TLS index
   307
   308	// Assert that slot is less than 64 so we can use _TEB->TlsSlots
   309	CMPQ	CX, $64
   310	JB	ok
   311
   312	// Fallback to the TEB arbitrary pointer.
   313	// TODO: don't use the arbitrary pointer (see go.dev/issue/59824)
   314	MOVQ	$TEB_ArbitraryPtr, CX
   315	JMP	settls
   316ok:
   317	// Convert the TLS index at CX into
   318	// an offset from TEB_TlsSlots.
   319	SHLQ	$3, CX
   320
   321	// Save offset from TLS into tls_g.
   322	ADDQ	$TEB_TlsSlots, CX
   323settls:
   324	MOVQ	CX, runtime·tls_g(SB)
   325	RET

View as plain text