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