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