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 runtimeasmstdcall(void *c); 14 TEXT runtimeasmstdcall(SB),NOSPLIT,$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 49 // Call stdcall function. 50 CALL AX 51 52 ADDQ $(maxargs*8), SP 53 54 // Return result. 55 POPQ CX 56 MOVQ AX, libcall_r1(CX) 57 58 // GetLastError(). 59 MOVQ 0x30(GS), DI 60 MOVL 0x68(DI), AX 61 MOVQ AX, libcall_err(CX) 62 63 RET 64 65 TEXT runtimebadsignal2(SB),NOSPLIT,$48 66 // stderr 67 MOVQ $-12, CX // stderr 68 MOVQ CX, 0(SP) 69 MOVQ runtime_GetStdHandle(SB), AX 70 CALL AX 71 72 MOVQ AX, CX // handle 73 MOVQ CX, 0(SP) 74 MOVQ $runtimebadsignalmsg(SB), DX // pointer 75 MOVQ DX, 8(SP) 76 MOVL $runtimebadsignallen(SB), R8 // count 77 MOVQ R8, 16(SP) 78 LEAQ 40(SP), R9 // written count 79 MOVQ $0, 0(R9) 80 MOVQ R9, 24(SP) 81 MOVQ $0, 32(SP) // overlapped 82 MOVQ runtime_WriteFile(SB), AX 83 CALL AX 84 85 RET 86 87 // faster get/set last error 88 TEXT runtimegetlasterror(SB),NOSPLIT,$0 89 MOVQ 0x30(GS), AX 90 MOVL 0x68(AX), AX 91 MOVL AX, ret+0(FP) 92 RET 93 94 TEXT runtimesetlasterror(SB),NOSPLIT,$0 95 MOVL err+0(FP), AX 96 MOVQ 0x30(GS), CX 97 MOVL AX, 0x68(CX) 98 RET 99 100 // Called by Windows as a Vectored Exception Handler (VEH). 101 // First argument is pointer to struct containing 102 // exception record and context pointers. 103 // Handler function is stored in AX. 104 // Return 0 for 'not handled', -1 for handled. 105 TEXT runtimesigtramp(SB),NOSPLIT,$0-0 106 // CX: PEXCEPTION_POINTERS ExceptionInfo 107 108 // DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved 109 // as required by windows callback convention. 110 PUSHFQ 111 SUBQ $112, SP 112 MOVQ DI, 80(SP) 113 MOVQ SI, 72(SP) 114 MOVQ BP, 64(SP) 115 MOVQ BX, 56(SP) 116 MOVQ R12, 48(SP) 117 MOVQ R13, 40(SP) 118 MOVQ R14, 32(SP) 119 MOVQ R15, 88(SP) 120 121 MOVQ AX, R15 // save handler address 122 123 // find g 124 get_tls(DX) 125 CMPQ DX, $0 126 JNE 3(PC) 127 MOVQ $0, AX // continue 128 JMP done 129 MOVQ g(DX), DX 130 CMPQ DX, $0 131 JNE 2(PC) 132 CALL runtimebadsignal2(SB) 133 134 // save g and SP in case of stack switch 135 MOVQ DX, 96(SP) // g 136 MOVQ SP, 104(SP) 137 138 // do we need to switch to the g0 stack? 139 MOVQ g_m(DX), BX 140 MOVQ m_g0(BX), BX 141 CMPQ DX, BX 142 JEQ g0 143 144 // switch to g0 stack 145 get_tls(BP) 146 MOVQ BX, g(BP) 147 MOVQ (g_sched+gobuf_sp)(BX), DI 148 // make it look like mstart called us on g0, to stop traceback 149 SUBQ $8, DI 150 MOVQ $runtimemstart(SB), SI 151 MOVQ SI, 0(DI) 152 // traceback will think that we've done PUSHFQ and SUBQ 153 // on this stack, so subtract them here to match. 154 // (we need room for sighandler arguments anyway). 155 // and re-save old SP for restoring later. 156 SUBQ $(112+8), DI 157 // save g, save old stack pointer. 158 MOVQ SP, 104(DI) 159 MOVQ DI, SP 160 161 g0: 162 MOVQ 0(CX), BX // ExceptionRecord* 163 MOVQ 8(CX), CX // Context* 164 MOVQ BX, 0(SP) 165 MOVQ CX, 8(SP) 166 MOVQ DX, 16(SP) 167 CALL R15 // call handler 168 // AX is set to report result back to Windows 169 MOVL 24(SP), AX 170 171 // switch back to original stack and g 172 // no-op if we never left. 173 MOVQ 104(SP), SP 174 MOVQ 96(SP), DX 175 get_tls(BP) 176 MOVQ DX, g(BP) 177 178 done: 179 // restore registers as required for windows callback 180 MOVQ 88(SP), R15 181 MOVQ 32(SP), R14 182 MOVQ 40(SP), R13 183 MOVQ 48(SP), R12 184 MOVQ 56(SP), BX 185 MOVQ 64(SP), BP 186 MOVQ 72(SP), SI 187 MOVQ 80(SP), DI 188 ADDQ $112, SP 189 POPFQ 190 191 RET 192 193 TEXT runtimeexceptiontramp(SB),NOSPLIT,$0 194 MOVQ $runtimeexceptionhandler(SB), AX 195 JMP runtimesigtramp(SB) 196 197 TEXT runtimefirstcontinuetramp(SB),NOSPLIT,$0-0 198 MOVQ $runtimefirstcontinuehandler(SB), AX 199 JMP runtimesigtramp(SB) 200 201 TEXT runtimelastcontinuetramp(SB),NOSPLIT,$0-0 202 MOVQ $runtimelastcontinuehandler(SB), AX 203 JMP runtimesigtramp(SB) 204 205 TEXT runtimectrlhandler(SB),NOSPLIT,$8 206 MOVQ CX, 16(SP) // spill 207 MOVQ $runtimectrlhandler1(SB), CX 208 MOVQ CX, 0(SP) 209 CALL runtimeexternalthreadhandler(SB) 210 RET 211 212 TEXT runtimeprofileloop(SB),NOSPLIT,$8 213 MOVQ $runtimeprofileloop1(SB), CX 214 MOVQ CX, 0(SP) 215 CALL runtimeexternalthreadhandler(SB) 216 RET 217 218 TEXT runtimeexternalthreadhandler(SB),NOSPLIT,$0 219 PUSHQ BP 220 MOVQ SP, BP 221 PUSHQ BX 222 PUSHQ SI 223 PUSHQ DI 224 PUSHQ 0x28(GS) 225 MOVQ SP, DX 226 227 // setup dummy m, g 228 SUBQ $m__size, SP // space for M 229 MOVQ SP, 0(SP) 230 MOVQ $m__size, 8(SP) 231 CALL runtimememclr(SB) // smashes AX,BX,CX 232 233 LEAQ m_tls(SP), CX 234 MOVQ CX, 0x28(GS) 235 MOVQ SP, BX 236 SUBQ $g__size, SP // space for G 237 MOVQ SP, g(CX) 238 MOVQ SP, m_g0(BX) 239 240 MOVQ SP, 0(SP) 241 MOVQ $g__size, 8(SP) 242 CALL runtimememclr(SB) // smashes AX,BX,CX 243 LEAQ g__size(SP), BX 244 MOVQ BX, g_m(SP) 245 246 LEAQ -8192(SP), CX 247 MOVQ CX, (g_stack+stack_lo)(SP) 248 ADDQ $const__StackGuard, CX 249 MOVQ CX, g_stackguard0(SP) 250 MOVQ CX, g_stackguard1(SP) 251 MOVQ DX, (g_stack+stack_hi)(SP) 252 253 PUSHQ AX // room for return value 254 PUSHQ 32(BP) // arg for handler 255 CALL 16(BP) 256 POPQ CX 257 POPQ AX // pass return value to Windows in AX 258 259 get_tls(CX) 260 MOVQ g(CX), CX 261 MOVQ (g_stack+stack_hi)(CX), SP 262 POPQ 0x28(GS) 263 POPQ DI 264 POPQ SI 265 POPQ BX 266 POPQ BP 267 RET 268 269 GLOBL runtimecbctxts(SB), NOPTR, $8 270 271 TEXT runtimecallbackasm1(SB),NOSPLIT,$0 272 // Construct args vector for cgocallback(). 273 // By windows/amd64 calling convention first 4 args are in CX, DX, R8, R9 274 // args from the 5th on are on the stack. 275 // In any case, even if function has 0,1,2,3,4 args, there is reserved 276 // but uninitialized "shadow space" for the first 4 args. 277 // The values are in registers. 278 MOVQ CX, (16+0)(SP) 279 MOVQ DX, (16+8)(SP) 280 MOVQ R8, (16+16)(SP) 281 MOVQ R9, (16+24)(SP) 282 283 // remove return address from stack, we are not returning there 284 MOVQ 0(SP), AX 285 ADDQ $8, SP 286 287 // determine index into runtimecbctxts table 288 MOVQ $runtimecallbackasm(SB), DX 289 SUBQ DX, AX 290 MOVQ $0, DX 291 MOVQ $5, CX // divide by 5 because each call instruction in runtimecallbacks is 5 bytes long 292 DIVL CX 293 294 // find correspondent runtimecbctxts table entry 295 MOVQ runtimecbctxts(SB), CX 296 MOVQ -8(CX)(AX*8), AX 297 298 // extract callback context 299 MOVQ wincallbackcontext_argsize(AX), DX 300 MOVQ wincallbackcontext_gobody(AX), AX 301 302 // preserve whatever's at the memory location that 303 // the callback will use to store the return value 304 LEAQ 8(SP), CX // args vector, skip return address 305 PUSHQ 0(CX)(DX*1) // store 8 bytes from just after the args array 306 ADDQ $8, DX // extend argsize by size of return value 307 308 // DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved 309 // as required by windows callback convention. 310 PUSHFQ 311 SUBQ $64, SP 312 MOVQ DI, 56(SP) 313 MOVQ SI, 48(SP) 314 MOVQ BP, 40(SP) 315 MOVQ BX, 32(SP) 316 MOVQ R12, 24(SP) 317 MOVQ R13, 16(SP) 318 MOVQ R14, 8(SP) 319 MOVQ R15, 0(SP) 320 321 // prepare call stack. use SUBQ to hide from stack frame checks 322 // cgocallback(Go func, void *frame, uintptr framesize) 323 SUBQ $24, SP 324 MOVQ DX, 16(SP) // argsize (including return value) 325 MOVQ CX, 8(SP) // callback parameters 326 MOVQ AX, 0(SP) // address of target Go function 327 CLD 328 CALL runtimecgocallback_gofunc(SB) 329 MOVQ 0(SP), AX 330 MOVQ 8(SP), CX 331 MOVQ 16(SP), DX 332 ADDQ $24, SP 333 334 // restore registers as required for windows callback 335 MOVQ 0(SP), R15 336 MOVQ 8(SP), R14 337 MOVQ 16(SP), R13 338 MOVQ 24(SP), R12 339 MOVQ 32(SP), BX 340 MOVQ 40(SP), BP 341 MOVQ 48(SP), SI 342 MOVQ 56(SP), DI 343 ADDQ $64, SP 344 POPFQ 345 346 MOVL -8(CX)(DX*1), AX // return value 347 POPQ -8(CX)(DX*1) // restore bytes just after the args 348 RET 349 350 // uint32 tstart_stdcall(M *newm); 351 TEXT runtimetstart_stdcall(SB),NOSPLIT,$0 352 // CX contains first arg newm 353 MOVQ m_g0(CX), DX // g 354 355 // Layout new m scheduler stack on os stack. 356 MOVQ SP, AX 357 MOVQ AX, (g_stack+stack_hi)(DX) 358 SUBQ $(64*1024), AX // stack size 359 MOVQ AX, (g_stack+stack_lo)(DX) 360 ADDQ $const__StackGuard, AX 361 MOVQ AX, g_stackguard0(DX) 362 MOVQ AX, g_stackguard1(DX) 363 364 // Set up tls. 365 LEAQ m_tls(CX), SI 366 MOVQ SI, 0x28(GS) 367 MOVQ CX, g_m(DX) 368 MOVQ DX, g(SI) 369 370 // Someday the convention will be D is always cleared. 371 CLD 372 373 CALL runtimestackcheck(SB) // clobbers AX,CX 374 CALL runtimemstart(SB) 375 376 XORL AX, AX // return 0 == success 377 RET 378 379 // set tls base to DI 380 TEXT runtimesettls(SB),NOSPLIT,$0 381 MOVQ DI, 0x28(GS) 382 RET 383 384 // Sleep duration is in 100ns units. 385 TEXT runtimeusleep1(SB),NOSPLIT,$0 386 MOVL usec+0(FP), BX 387 MOVQ $runtimeusleep2(SB), AX // to hide from 6l 388 389 // Execute call on m->g0 stack, in case we are not actually 390 // calling a system call wrapper, like when running under WINE. 391 get_tls(R15) 392 CMPQ R15, $0 393 JNE 3(PC) 394 // Not a Go-managed thread. Do not switch stack. 395 CALL AX 396 RET 397 398 MOVQ g(R15), R13 399 MOVQ g_m(R13), R13 400 401 // leave pc/sp for cpu profiler 402 MOVQ (SP), R12 403 MOVQ R12, m_libcallpc(R13) 404 MOVQ g(R15), R12 405 MOVQ R12, m_libcallg(R13) 406 // sp must be the last, because once async cpu profiler finds 407 // all three values to be non-zero, it will use them 408 LEAQ usec+0(FP), R12 409 MOVQ R12, m_libcallsp(R13) 410 411 MOVQ m_g0(R13), R14 412 CMPQ g(R15), R14 413 JNE switch 414 // executing on m->g0 already 415 CALL AX 416 JMP ret 417 418 switch: 419 // Switch to m->g0 stack and back. 420 MOVQ (g_sched+gobuf_sp)(R14), R14 421 MOVQ SP, -8(R14) 422 LEAQ -8(R14), SP 423 CALL AX 424 MOVQ 0(SP), SP 425 426 ret: 427 MOVQ $0, m_libcallsp(R13) 428 RET 429 430 // Runs on OS stack. duration (in 100ns units) is in BX. 431 TEXT runtimeusleep2(SB),NOSPLIT,$16 432 MOVQ SP, AX 433 ANDQ $~15, SP // alignment as per Windows requirement 434 MOVQ AX, 8(SP) 435 // Want negative 100ns units. 436 NEGQ BX 437 MOVQ SP, R8 // ptime 438 MOVQ BX, (R8) 439 MOVQ $-1, CX // handle 440 MOVQ $0, DX // alertable 441 MOVQ runtime_NtWaitForSingleObject(SB), AX 442 CALL AX 443 MOVQ 8(SP), SP 444 RET 445 446 // func now() (sec int64, nsec int32) 447 TEXT timenow(SB),NOSPLIT,$8-12 448 CALL runtimeunixnano(SB) 449 MOVQ 0(SP), AX 450 451 // generated code for 452 // func f(x uint64) (uint64, uint64) { return x/1000000000, x%100000000 } 453 // adapted to reduce duplication 454 MOVQ AX, CX 455 MOVQ $1360296554856532783, AX 456 MULQ CX 457 ADDQ CX, DX 458 RCRQ $1, DX 459 SHRQ $29, DX 460 MOVQ DX, sec+0(FP) 461 IMULQ $1000000000, DX 462 SUBQ DX, CX 463 MOVL CX, nsec+8(FP) 464 RET 465 466