github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/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 // 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 77 TEXT 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 100 TEXT runtime·getlasterror(SB),NOSPLIT,$0 101 MOVQ 0x30(GS), AX 102 MOVL 0x68(AX), AX 103 MOVL AX, ret+0(FP) 104 RET 105 106 TEXT 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. 117 TEXT 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 173 g0: 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 190 done: 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 205 TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0 206 MOVQ $runtime·exceptionhandler(SB), AX 207 JMP sigtramp<>(SB) 208 209 TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 210 MOVQ $runtime·firstcontinuehandler(SB), AX 211 JMP sigtramp<>(SB) 212 213 TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 214 MOVQ $runtime·lastcontinuehandler(SB), AX 215 JMP sigtramp<>(SB) 216 217 TEXT 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 224 TEXT 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 230 TEXT 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 281 GLOBL runtime·cbctxts(SB), NOPTR, $8 282 283 TEXT 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); 358 TEXT 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 387 TEXT runtime·settls(SB),NOSPLIT,$0 388 MOVQ DI, 0x28(GS) 389 RET 390 391 // func onosstack(fn unsafe.Pointer, arg uint32) 392 TEXT 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 425 switch: 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 433 ret: 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). 440 TEXT 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. 456 TEXT 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 490 gisnotset: 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. 497 TEXT 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 516 TEXT runtime·nanotime1(SB),NOSPLIT,$0-8 517 CMPB runtime·useQPCTime(SB), $0 518 JNE useQPC 519 MOVQ $_INTERRUPT_TIME, DI 520 loop: 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 531 useQPC: 532 JMP runtime·nanotimeQPC(SB) 533 RET 534 535 TEXT time·now(SB),NOSPLIT,$0-24 536 CMPB runtime·useQPCTime(SB), $0 537 JNE useQPC 538 MOVQ $_INTERRUPT_TIME, DI 539 loop: 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 551 wall: 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 577 useQPC: 578 JMP runtime·nowQPC(SB) 579 RET