github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/runtime/sys_windows_amd64.s (about) 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 runtime·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 runtime·sigtramp(SB) 204 205 TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 206 MOVQ $runtime·firstcontinuehandler(SB), AX 207 JMP runtime·sigtramp(SB) 208 209 TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 210 MOVQ $runtime·lastcontinuehandler(SB), AX 211 JMP runtime·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 MOVL -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 // stack size 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 usec+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 http://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 MOVQ $_INTERRUPT_TIME, DI 478 loop: 479 MOVL time_hi1(DI), AX 480 MOVL time_lo(DI), BX 481 MOVL time_hi2(DI), CX 482 CMPL AX, CX 483 JNE loop 484 SHLQ $32, CX 485 ORQ BX, CX 486 IMULQ $100, CX 487 SUBQ runtime·startNano(SB), CX 488 MOVQ CX, ret+0(FP) 489 RET 490 491 TEXT time·now(SB),NOSPLIT,$0-24 492 MOVQ $_INTERRUPT_TIME, DI 493 loop: 494 MOVL time_hi1(DI), AX 495 MOVL time_lo(DI), BX 496 MOVL time_hi2(DI), CX 497 CMPL AX, CX 498 JNE loop 499 SHLQ $32, AX 500 ORQ BX, AX 501 IMULQ $100, AX 502 SUBQ runtime·startNano(SB), AX 503 MOVQ AX, mono+16(FP) 504 505 MOVQ $_SYSTEM_TIME, DI 506 wall: 507 MOVL time_hi1(DI), AX 508 MOVL time_lo(DI), BX 509 MOVL time_hi2(DI), CX 510 CMPL AX, CX 511 JNE wall 512 SHLQ $32, AX 513 ORQ BX, AX 514 MOVQ $116444736000000000, DI 515 SUBQ DI, AX 516 IMULQ $100, AX 517 518 // generated code for 519 // func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 } 520 // adapted to reduce duplication 521 MOVQ AX, CX 522 MOVQ $1360296554856532783, AX 523 MULQ CX 524 ADDQ CX, DX 525 RCRQ $1, DX 526 SHRQ $29, DX 527 MOVQ DX, sec+0(FP) 528 IMULQ $1000000000, DX 529 SUBQ DX, CX 530 MOVL CX, nsec+8(FP) 531 RET