Black Lives Matter. Support the Equal Justice Initiative.

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
     9// maxargs should be divisible by 2, as Windows stack
    10// must be kept 16-byte aligned on syscall entry.
    11#define maxargs 16
    12
    13// void runtime·asmstdcall(void *c);
    14TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0
    15	// asmcgocall will put first argument into CX.
    16	PUSHQ	CX			// save for later
    17	MOVQ	libcall_fn(CX), AX
    18	MOVQ	libcall_args(CX), SI
    19	MOVQ	libcall_n(CX), CX
    20
    21	// SetLastError(0).
    22	MOVQ	0x30(GS), DI
    23	MOVL	$0, 0x68(DI)
    24
    25	SUBQ	$(maxargs*8), SP	// room for args
    26
    27	// Fast version, do not store args on the stack.
    28	CMPL	CX, $4
    29	JLE	loadregs
    30
    31	// Check we have enough room for args.
    32	CMPL	CX, $maxargs
    33	JLE	2(PC)
    34	INT	$3			// not enough room -> crash
    35
    36	// Copy args to the stack.
    37	MOVQ	SP, DI
    38	CLD
    39	REP; MOVSQ
    40	MOVQ	SP, SI
    41
    42loadregs:
    43	// Load first 4 args into correspondent registers.
    44	MOVQ	0(SI), CX
    45	MOVQ	8(SI), DX
    46	MOVQ	16(SI), R8
    47	MOVQ	24(SI), R9
    48	// Floating point arguments are passed in the XMM
    49	// registers. Set them here in case any of the arguments
    50	// are floating point values. For details see
    51	//	https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
    52	MOVQ	CX, X0
    53	MOVQ	DX, X1
    54	MOVQ	R8, X2
    55	MOVQ	R9, X3
    56
    57	// Call stdcall function.
    58	CALL	AX
    59
    60	ADDQ	$(maxargs*8), SP
    61
    62	// Return result.
    63	POPQ	CX
    64	MOVQ	AX, libcall_r1(CX)
    65	// Floating point return values are returned in XMM0. Setting r2 to this
    66	// value in case this call returned a floating point value. For details,
    67	// see https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
    68	MOVQ    X0, libcall_r2(CX)
    69
    70	// GetLastError().
    71	MOVQ	0x30(GS), DI
    72	MOVL	0x68(DI), AX
    73	MOVQ	AX, libcall_err(CX)
    74
    75	RET
    76
    77TEXT runtime·badsignal2(SB),NOSPLIT|NOFRAME,$48
    78	// stderr
    79	MOVQ	$-12, CX // stderr
    80	MOVQ	CX, 0(SP)
    81	MOVQ	runtime·_GetStdHandle(SB), AX
    82	CALL	AX
    83
    84	MOVQ	AX, CX	// handle
    85	MOVQ	CX, 0(SP)
    86	MOVQ	$runtime·badsignalmsg(SB), DX // pointer
    87	MOVQ	DX, 8(SP)
    88	MOVL	$runtime·badsignallen(SB), R8 // count
    89	MOVQ	R8, 16(SP)
    90	LEAQ	40(SP), R9  // written count
    91	MOVQ	$0, 0(R9)
    92	MOVQ	R9, 24(SP)
    93	MOVQ	$0, 32(SP)	// overlapped
    94	MOVQ	runtime·_WriteFile(SB), AX
    95	CALL	AX
    96
    97	RET
    98
    99// faster get/set last error
   100TEXT runtime·getlasterror(SB),NOSPLIT,$0
   101	MOVQ	0x30(GS), AX
   102	MOVL	0x68(AX), AX
   103	MOVL	AX, ret+0(FP)
   104	RET
   105
   106TEXT runtime·setlasterror(SB),NOSPLIT,$0
   107	MOVL	err+0(FP), AX
   108	MOVQ	0x30(GS),	CX
   109	MOVL	AX, 0x68(CX)
   110	RET
   111
   112// Called by Windows as a Vectored Exception Handler (VEH).
   113// First argument is pointer to struct containing
   114// exception record and context pointers.
   115// Handler function is stored in AX.
   116// Return 0 for 'not handled', -1 for handled.
   117TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0-0
   118	// CX: PEXCEPTION_POINTERS ExceptionInfo
   119
   120	// DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
   121	// as required by windows callback convention.
   122	PUSHFQ
   123	SUBQ	$112, SP
   124	MOVQ	DI, 80(SP)
   125	MOVQ	SI, 72(SP)
   126	MOVQ	BP, 64(SP)
   127	MOVQ	BX, 56(SP)
   128	MOVQ	R12, 48(SP)
   129	MOVQ	R13, 40(SP)
   130	MOVQ	R14, 32(SP)
   131	MOVQ	R15, 88(SP)
   132
   133	MOVQ	AX, R15	// save handler address
   134
   135	// find g
   136	get_tls(DX)
   137	CMPQ	DX, $0
   138	JNE	3(PC)
   139	MOVQ	$0, AX // continue
   140	JMP	done
   141	MOVQ	g(DX), DX
   142	CMPQ	DX, $0
   143	JNE	2(PC)
   144	CALL	runtime·badsignal2(SB)
   145
   146	// save g and SP in case of stack switch
   147	MOVQ	DX, 96(SP) // g
   148	MOVQ	SP, 104(SP)
   149
   150	// do we need to switch to the g0 stack?
   151	MOVQ	g_m(DX), BX
   152	MOVQ	m_g0(BX), BX
   153	CMPQ	DX, BX
   154	JEQ	g0
   155
   156	// switch to g0 stack
   157	get_tls(BP)
   158	MOVQ	BX, g(BP)
   159	MOVQ	(g_sched+gobuf_sp)(BX), DI
   160	// make it look like mstart called us on g0, to stop traceback
   161	SUBQ	$8, DI
   162	MOVQ	$runtime·mstart(SB), SI
   163	MOVQ	SI, 0(DI)
   164	// traceback will think that we've done PUSHFQ and SUBQ
   165	// on this stack, so subtract them here to match.
   166	// (we need room for sighandler arguments anyway).
   167	// and re-save old SP for restoring later.
   168	SUBQ	$(112+8), DI
   169	// save g, save old stack pointer.
   170	MOVQ	SP, 104(DI)
   171	MOVQ	DI, SP
   172
   173g0:
   174	MOVQ	0(CX), BX // ExceptionRecord*
   175	MOVQ	8(CX), CX // Context*
   176	MOVQ	BX, 0(SP)
   177	MOVQ	CX, 8(SP)
   178	MOVQ	DX, 16(SP)
   179	CALL	R15	// call handler
   180	// AX is set to report result back to Windows
   181	MOVL	24(SP), AX
   182
   183	// switch back to original stack and g
   184	// no-op if we never left.
   185	MOVQ	104(SP), SP
   186	MOVQ	96(SP), DX
   187	get_tls(BP)
   188	MOVQ	DX, g(BP)
   189
   190done:
   191	// restore registers as required for windows callback
   192	MOVQ	88(SP), R15
   193	MOVQ	32(SP), R14
   194	MOVQ	40(SP), R13
   195	MOVQ	48(SP), R12
   196	MOVQ	56(SP), BX
   197	MOVQ	64(SP), BP
   198	MOVQ	72(SP), SI
   199	MOVQ	80(SP), DI
   200	ADDQ	$112, SP
   201	POPFQ
   202
   203	RET
   204
   205TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0
   206	MOVQ	$runtime·exceptionhandler(SB), AX
   207	JMP	sigtramp<>(SB)
   208
   209TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0
   210	MOVQ	$runtime·firstcontinuehandler(SB), AX
   211	JMP	sigtramp<>(SB)
   212
   213TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0
   214	MOVQ	$runtime·lastcontinuehandler(SB), AX
   215	JMP	sigtramp<>(SB)
   216
   217TEXT runtime·ctrlhandler(SB),NOSPLIT|NOFRAME,$8
   218	MOVQ	CX, 16(SP)		// spill
   219	MOVQ	$runtime·ctrlhandler1(SB), CX
   220	MOVQ	CX, 0(SP)
   221	CALL	runtime·externalthreadhandler(SB)
   222	RET
   223
   224TEXT runtime·profileloop(SB),NOSPLIT|NOFRAME,$8
   225	MOVQ	$runtime·profileloop1(SB), CX
   226	MOVQ	CX, 0(SP)
   227	CALL	runtime·externalthreadhandler(SB)
   228	RET
   229
   230TEXT runtime·externalthreadhandler(SB),NOSPLIT|NOFRAME,$0
   231	PUSHQ	BP
   232	MOVQ	SP, BP
   233	PUSHQ	BX
   234	PUSHQ	SI
   235	PUSHQ	DI
   236	PUSHQ	0x28(GS)
   237	MOVQ	SP, DX
   238
   239	// setup dummy m, g
   240	SUBQ	$m__size, SP		// space for M
   241	MOVQ	SP, 0(SP)
   242	MOVQ	$m__size, 8(SP)
   243	CALL	runtime·memclrNoHeapPointers(SB)	// smashes AX,BX,CX, maybe BP
   244
   245	LEAQ	m_tls(SP), CX
   246	MOVQ	CX, 0x28(GS)
   247	MOVQ	SP, BX
   248	SUBQ	$g__size, SP		// space for G
   249	MOVQ	SP, g(CX)
   250	MOVQ	SP, m_g0(BX)
   251
   252	MOVQ	SP, 0(SP)
   253	MOVQ	$g__size, 8(SP)
   254	CALL	runtime·memclrNoHeapPointers(SB)	// smashes AX,BX,CX, maybe BP
   255	LEAQ	g__size(SP), BX
   256	MOVQ	BX, g_m(SP)
   257
   258	LEAQ	-32768(SP), CX		// must be less than SizeOfStackReserve set by linker
   259	MOVQ	CX, (g_stack+stack_lo)(SP)
   260	ADDQ	$const__StackGuard, CX
   261	MOVQ	CX, g_stackguard0(SP)
   262	MOVQ	CX, g_stackguard1(SP)
   263	MOVQ	DX, (g_stack+stack_hi)(SP)
   264
   265	PUSHQ	AX			// room for return value
   266	PUSHQ	32(BP)			// arg for handler
   267	CALL	16(BP)
   268	POPQ	CX
   269	POPQ	AX			// pass return value to Windows in AX
   270
   271	get_tls(CX)
   272	MOVQ	g(CX), CX
   273	MOVQ	(g_stack+stack_hi)(CX), SP
   274	POPQ	0x28(GS)
   275	POPQ	DI
   276	POPQ	SI
   277	POPQ	BX
   278	POPQ	BP
   279	RET
   280
   281GLOBL runtime·cbctxts(SB), NOPTR, $8
   282
   283TEXT runtime·callbackasm1(SB),NOSPLIT,$0
   284	// Construct args vector for cgocallback().
   285	// By windows/amd64 calling convention first 4 args are in CX, DX, R8, R9
   286	// args from the 5th on are on the stack.
   287	// In any case, even if function has 0,1,2,3,4 args, there is reserved
   288	// but uninitialized "shadow space" for the first 4 args.
   289	// The values are in registers.
   290  	MOVQ	CX, (16+0)(SP)
   291  	MOVQ	DX, (16+8)(SP)
   292  	MOVQ	R8, (16+16)(SP)
   293  	MOVQ	R9, (16+24)(SP)
   294	// R8 = address of args vector
   295	LEAQ	(16+0)(SP), R8
   296
   297	// remove return address from stack, we are not returning to callbackasm, but to its caller.
   298  	MOVQ	0(SP), AX
   299	ADDQ	$8, SP
   300
   301	// determine index into runtime·cbs table
   302	MOVQ	$runtime·callbackasm(SB), DX
   303	SUBQ	DX, AX
   304	MOVQ	$0, DX
   305	MOVQ	$5, CX	// divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
   306	DIVL	CX
   307	SUBQ	$1, AX	// subtract 1 because return PC is to the next slot
   308
   309	// DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
   310	// as required by windows callback convention.
   311	PUSHFQ
   312	SUBQ	$64, SP
   313	MOVQ	DI, 56(SP)
   314	MOVQ	SI, 48(SP)
   315	MOVQ	BP, 40(SP)
   316	MOVQ	BX, 32(SP)
   317	MOVQ	R12, 24(SP)
   318	MOVQ	R13, 16(SP)
   319	MOVQ	R14, 8(SP)
   320	MOVQ	R15, 0(SP)
   321
   322	// Go ABI requires DF flag to be cleared.
   323	CLD
   324
   325	// Create a struct callbackArgs on our stack to be passed as
   326	// the "frame" to cgocallback and on to callbackWrap.
   327	SUBQ	$(24+callbackArgs__size), SP
   328	MOVQ	AX, (24+callbackArgs_index)(SP) 	// callback index
   329	MOVQ	R8, (24+callbackArgs_args)(SP)  	// address of args vector
   330	MOVQ	$0, (24+callbackArgs_result)(SP)	// result
   331	LEAQ	24(SP), AX
   332	// Call cgocallback, which will call callbackWrap(frame).
   333	MOVQ	$0, 16(SP)	// context
   334	MOVQ	AX, 8(SP)	// frame (address of callbackArgs)
   335	LEAQ	·callbackWrap(SB), BX
   336	MOVQ	BX, 0(SP)	// PC of function value to call (callbackWrap)
   337	CALL	·cgocallback(SB)
   338	// Get callback result.
   339	MOVQ	(24+callbackArgs_result)(SP), AX
   340	ADDQ	$(24+callbackArgs__size), SP
   341
   342	// restore registers as required for windows callback
   343	MOVQ	0(SP), R15
   344	MOVQ	8(SP), R14
   345	MOVQ	16(SP), R13
   346	MOVQ	24(SP), R12
   347	MOVQ	32(SP), BX
   348	MOVQ	40(SP), BP
   349	MOVQ	48(SP), SI
   350	MOVQ	56(SP), DI
   351	ADDQ	$64, SP
   352	POPFQ
   353
   354	// The return value was placed in AX above.
   355	RET
   356
   357// uint32 tstart_stdcall(M *newm);
   358TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
   359	// CX contains first arg newm
   360	MOVQ	m_g0(CX), DX		// g
   361
   362	// Layout new m scheduler stack on os stack.
   363	MOVQ	SP, AX
   364	MOVQ	AX, (g_stack+stack_hi)(DX)
   365	SUBQ	$(64*1024), AX		// initial stack size (adjusted later)
   366	MOVQ	AX, (g_stack+stack_lo)(DX)
   367	ADDQ	$const__StackGuard, AX
   368	MOVQ	AX, g_stackguard0(DX)
   369	MOVQ	AX, g_stackguard1(DX)
   370
   371	// Set up tls.
   372	LEAQ	m_tls(CX), SI
   373	MOVQ	SI, 0x28(GS)
   374	MOVQ	CX, g_m(DX)
   375	MOVQ	DX, g(SI)
   376
   377	// Someday the convention will be D is always cleared.
   378	CLD
   379
   380	CALL	runtime·stackcheck(SB)	// clobbers AX,CX
   381	CALL	runtime·mstart(SB)
   382
   383	XORL	AX, AX			// return 0 == success
   384	RET
   385
   386// set tls base to DI
   387TEXT runtime·settls(SB),NOSPLIT,$0
   388	MOVQ	DI, 0x28(GS)
   389	RET
   390
   391// func onosstack(fn unsafe.Pointer, arg uint32)
   392TEXT runtime·onosstack(SB),NOSPLIT,$0
   393	MOVQ	fn+0(FP), AX		// to hide from 6l
   394	MOVL	arg+8(FP), BX
   395
   396	// Execute call on m->g0 stack, in case we are not actually
   397	// calling a system call wrapper, like when running under WINE.
   398	get_tls(R15)
   399	CMPQ	R15, $0
   400	JNE	3(PC)
   401	// Not a Go-managed thread. Do not switch stack.
   402	CALL	AX
   403	RET
   404
   405	MOVQ	g(R15), R13
   406	MOVQ	g_m(R13), R13
   407
   408	// leave pc/sp for cpu profiler
   409	MOVQ	(SP), R12
   410	MOVQ	R12, m_libcallpc(R13)
   411	MOVQ	g(R15), R12
   412	MOVQ	R12, m_libcallg(R13)
   413	// sp must be the last, because once async cpu profiler finds
   414	// all three values to be non-zero, it will use them
   415	LEAQ	fn+0(FP), R12
   416	MOVQ	R12, m_libcallsp(R13)
   417
   418	MOVQ	m_g0(R13), R14
   419	CMPQ	g(R15), R14
   420	JNE	switch
   421	// executing on m->g0 already
   422	CALL	AX
   423	JMP	ret
   424
   425switch:
   426	// Switch to m->g0 stack and back.
   427	MOVQ	(g_sched+gobuf_sp)(R14), R14
   428	MOVQ	SP, -8(R14)
   429	LEAQ	-8(R14), SP
   430	CALL	AX
   431	MOVQ	0(SP), SP
   432
   433ret:
   434	MOVQ	$0, m_libcallsp(R13)
   435	RET
   436
   437// Runs on OS stack. duration (in 100ns units) is in BX.
   438// The function leaves room for 4 syscall parameters
   439// (as per windows amd64 calling convention).
   440TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$48
   441	MOVQ	SP, AX
   442	ANDQ	$~15, SP	// alignment as per Windows requirement
   443	MOVQ	AX, 40(SP)
   444	// Want negative 100ns units.
   445	NEGQ	BX
   446	LEAQ	32(SP), R8  // ptime
   447	MOVQ	BX, (R8)
   448	MOVQ	$-1, CX // handle
   449	MOVQ	$0, DX // alertable
   450	MOVQ	runtime·_NtWaitForSingleObject(SB), AX
   451	CALL	AX
   452	MOVQ	40(SP), SP
   453	RET
   454
   455// Runs on OS stack. duration (in 100ns units) is in BX.
   456TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72
   457	get_tls(CX)
   458	CMPQ	CX, $0
   459	JE	gisnotset
   460
   461	MOVQ	SP, AX
   462	ANDQ	$~15, SP	// alignment as per Windows requirement
   463	MOVQ	AX, 64(SP)
   464
   465	MOVQ	g(CX), CX
   466	MOVQ	g_m(CX), CX
   467	MOVQ	(m_mOS+mOS_highResTimer)(CX), CX	// hTimer
   468	MOVQ	CX, 48(SP)				// save hTimer for later
   469	// Want negative 100ns units.
   470	NEGQ	BX
   471	LEAQ	56(SP), DX				// lpDueTime
   472	MOVQ	BX, (DX)
   473	MOVQ	$0, R8					// lPeriod
   474	MOVQ	$0, R9					// pfnCompletionRoutine
   475	MOVQ	$0, AX
   476	MOVQ	AX, 32(SP)				// lpArgToCompletionRoutine
   477	MOVQ	AX, 40(SP)				// fResume
   478	MOVQ	runtime·_SetWaitableTimer(SB), AX
   479	CALL	AX
   480
   481	MOVQ	48(SP), CX				// handle
   482	MOVQ	$0, DX					// alertable
   483	MOVQ	$0, R8					// ptime
   484	MOVQ	runtime·_NtWaitForSingleObject(SB), AX
   485	CALL	AX
   486
   487	MOVQ	64(SP), SP
   488	RET
   489
   490gisnotset:
   491	// TLS is not configured. Call usleep2 instead.
   492	MOVQ	$runtime·usleep2(SB), AX
   493	CALL	AX
   494	RET
   495
   496// Runs on OS stack.
   497TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
   498	MOVQ	SP, AX
   499	ANDQ	$~15, SP	// alignment as per Windows requirement
   500	SUBQ	$(48), SP	// room for SP and 4 args as per Windows requirement
   501				// plus one extra word to keep stack 16 bytes aligned
   502	MOVQ	AX, 32(SP)
   503	MOVQ	runtime·_SwitchToThread(SB), AX
   504	CALL	AX
   505	MOVQ	32(SP), SP
   506	RET
   507
   508// See https://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
   509// Must read hi1, then lo, then hi2. The snapshot is valid if hi1 == hi2.
   510#define _INTERRUPT_TIME 0x7ffe0008
   511#define _SYSTEM_TIME 0x7ffe0014
   512#define time_lo 0
   513#define time_hi1 4
   514#define time_hi2 8
   515
   516TEXT runtime·nanotime1(SB),NOSPLIT,$0-8
   517	CMPB	runtime·useQPCTime(SB), $0
   518	JNE	useQPC
   519	MOVQ	$_INTERRUPT_TIME, DI
   520loop:
   521	MOVL	time_hi1(DI), AX
   522	MOVL	time_lo(DI), BX
   523	MOVL	time_hi2(DI), CX
   524	CMPL	AX, CX
   525	JNE	loop
   526	SHLQ	$32, CX
   527	ORQ	BX, CX
   528	IMULQ	$100, CX
   529	MOVQ	CX, ret+0(FP)
   530	RET
   531useQPC:
   532	JMP	runtime·nanotimeQPC(SB)
   533	RET
   534
   535TEXT time·now(SB),NOSPLIT,$0-24
   536	CMPB	runtime·useQPCTime(SB), $0
   537	JNE	useQPC
   538	MOVQ	$_INTERRUPT_TIME, DI
   539loop:
   540	MOVL	time_hi1(DI), AX
   541	MOVL	time_lo(DI), BX
   542	MOVL	time_hi2(DI), CX
   543	CMPL	AX, CX
   544	JNE	loop
   545	SHLQ	$32, AX
   546	ORQ	BX, AX
   547	IMULQ	$100, AX
   548	MOVQ	AX, mono+16(FP)
   549
   550	MOVQ	$_SYSTEM_TIME, DI
   551wall:
   552	MOVL	time_hi1(DI), AX
   553	MOVL	time_lo(DI), BX
   554	MOVL	time_hi2(DI), CX
   555	CMPL	AX, CX
   556	JNE	wall
   557	SHLQ	$32, AX
   558	ORQ	BX, AX
   559	MOVQ	$116444736000000000, DI
   560	SUBQ	DI, AX
   561	IMULQ	$100, AX
   562
   563	// generated code for
   564	//	func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 }
   565	// adapted to reduce duplication
   566	MOVQ	AX, CX
   567	MOVQ	$1360296554856532783, AX
   568	MULQ	CX
   569	ADDQ	CX, DX
   570	RCRQ	$1, DX
   571	SHRQ	$29, DX
   572	MOVQ	DX, sec+0(FP)
   573	IMULQ	$1000000000, DX
   574	SUBQ	DX, CX
   575	MOVL	CX, nsec+8(FP)
   576	RET
   577useQPC:
   578	JMP	runtime·nowQPC(SB)
   579	RET

View as plain text