github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/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 #include "time_windows.h" 9 #include "cgo/abi_amd64.h" 10 11 // Offsets into Thread Environment Block (pointer in GS) 12 #define TEB_TlsSlots 0x1480 13 #define TEB_ArbitraryPtr 0x28 14 15 // void runtime·asmstdcall(void *c); 16 TEXT runtime·asmstdcall(SB),NOSPLIT,$16 17 MOVQ SP, AX 18 ANDQ $~15, SP // alignment as per Windows requirement 19 MOVQ AX, 8(SP) 20 MOVQ CX, 0(SP) // asmcgocall will put first argument into CX. 21 22 MOVQ libcall_fn(CX), AX 23 MOVQ libcall_args(CX), SI 24 MOVQ libcall_n(CX), CX 25 26 // SetLastError(0). 27 MOVQ 0x30(GS), DI 28 MOVL $0, 0x68(DI) 29 30 SUBQ $(const_maxArgs*8), SP // room for args 31 32 // Fast version, do not store args on the stack. 33 CMPL CX, $4 34 JLE loadregs 35 36 // Check we have enough room for args. 37 CMPL CX, $const_maxArgs 38 JLE 2(PC) 39 INT $3 // not enough room -> crash 40 41 // Copy args to the stack. 42 MOVQ SP, DI 43 CLD 44 REP; MOVSQ 45 MOVQ SP, SI 46 47 loadregs: 48 // Load first 4 args into correspondent registers. 49 MOVQ 0(SI), CX 50 MOVQ 8(SI), DX 51 MOVQ 16(SI), R8 52 MOVQ 24(SI), R9 53 // Floating point arguments are passed in the XMM 54 // registers. Set them here in case any of the arguments 55 // are floating point values. For details see 56 // https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx 57 MOVQ CX, X0 58 MOVQ DX, X1 59 MOVQ R8, X2 60 MOVQ R9, X3 61 62 // Call stdcall function. 63 CALL AX 64 65 ADDQ $(const_maxArgs*8), SP 66 67 // Return result. 68 MOVQ 0(SP), CX 69 MOVQ 8(SP), SP 70 MOVQ AX, libcall_r1(CX) 71 // Floating point return values are returned in XMM0. Setting r2 to this 72 // value in case this call returned a floating point value. For details, 73 // see https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention 74 MOVQ X0, libcall_r2(CX) 75 76 // GetLastError(). 77 MOVQ 0x30(GS), DI 78 MOVL 0x68(DI), AX 79 MOVQ AX, libcall_err(CX) 80 81 RET 82 83 // faster get/set last error 84 TEXT runtime·getlasterror(SB),NOSPLIT,$0 85 MOVQ 0x30(GS), AX 86 MOVL 0x68(AX), AX 87 MOVL AX, ret+0(FP) 88 RET 89 90 // Called by Windows as a Vectored Exception Handler (VEH). 91 // CX is pointer to struct containing 92 // exception record and context pointers. 93 // DX is the kind of sigtramp function. 94 // Return value of sigtrampgo is stored in AX. 95 TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0-0 96 // Switch from the host ABI to the Go ABI. 97 PUSH_REGS_HOST_TO_ABI0() 98 99 // Set up ABIInternal environment: cleared X15 and R14. 100 // R14 is cleared in case there's a non-zero value in there 101 // if called from a non-go thread. 102 XORPS X15, X15 103 XORQ R14, R14 104 105 get_tls(AX) 106 CMPQ AX, $0 107 JE 2(PC) 108 // Exception from Go thread, set R14. 109 MOVQ g(AX), R14 110 111 // Reserve space for spill slots. 112 ADJSP $16 113 MOVQ CX, AX 114 MOVQ DX, BX 115 // Calling ABIInternal because TLS might be nil. 116 CALL runtime·sigtrampgo<ABIInternal>(SB) 117 // Return value is already stored in AX. 118 119 ADJSP $-16 120 121 POP_REGS_HOST_TO_ABI0() 122 RET 123 124 // Trampoline to resume execution from exception handler. 125 // This is part of the control flow guard workaround. 126 // It switches stacks and jumps to the continuation address. 127 // R8 and R9 are set above at the end of sigtrampgo 128 // in the context that starts executing at sigresume. 129 TEXT runtime·sigresume(SB),NOSPLIT|NOFRAME,$0 130 MOVQ R8, SP 131 JMP R9 132 133 TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0 134 // PExceptionPointers already on CX 135 MOVQ $const_callbackVEH, DX 136 JMP sigtramp<>(SB) 137 138 TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 139 // PExceptionPointers already on CX 140 MOVQ $const_callbackFirstVCH, DX 141 JMP sigtramp<>(SB) 142 143 TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0 144 // PExceptionPointers already on CX 145 MOVQ $const_callbackLastVCH, DX 146 JMP sigtramp<>(SB) 147 148 TEXT runtime·callbackasm1(SB),NOSPLIT|NOFRAME,$0 149 // Construct args vector for cgocallback(). 150 // By windows/amd64 calling convention first 4 args are in CX, DX, R8, R9 151 // args from the 5th on are on the stack. 152 // In any case, even if function has 0,1,2,3,4 args, there is reserved 153 // but uninitialized "shadow space" for the first 4 args. 154 // The values are in registers. 155 MOVQ CX, (16+0)(SP) 156 MOVQ DX, (16+8)(SP) 157 MOVQ R8, (16+16)(SP) 158 MOVQ R9, (16+24)(SP) 159 // R8 = address of args vector 160 LEAQ (16+0)(SP), R8 161 162 // remove return address from stack, we are not returning to callbackasm, but to its caller. 163 MOVQ 0(SP), AX 164 ADDQ $8, SP 165 166 // determine index into runtime·cbs table 167 MOVQ $runtime·callbackasm(SB), DX 168 SUBQ DX, AX 169 MOVQ $0, DX 170 MOVQ $5, CX // divide by 5 because each call instruction in runtime·callbacks is 5 bytes long 171 DIVL CX 172 SUBQ $1, AX // subtract 1 because return PC is to the next slot 173 174 // Switch from the host ABI to the Go ABI. 175 PUSH_REGS_HOST_TO_ABI0() 176 177 // Create a struct callbackArgs on our stack to be passed as 178 // the "frame" to cgocallback and on to callbackWrap. 179 SUBQ $(24+callbackArgs__size), SP 180 MOVQ AX, (24+callbackArgs_index)(SP) // callback index 181 MOVQ R8, (24+callbackArgs_args)(SP) // address of args vector 182 MOVQ $0, (24+callbackArgs_result)(SP) // result 183 LEAQ 24(SP), AX 184 // Call cgocallback, which will call callbackWrap(frame). 185 MOVQ $0, 16(SP) // context 186 MOVQ AX, 8(SP) // frame (address of callbackArgs) 187 LEAQ ·callbackWrap<ABIInternal>(SB), BX // cgocallback takes an ABIInternal entry-point 188 MOVQ BX, 0(SP) // PC of function value to call (callbackWrap) 189 CALL ·cgocallback(SB) 190 // Get callback result. 191 MOVQ (24+callbackArgs_result)(SP), AX 192 ADDQ $(24+callbackArgs__size), SP 193 194 POP_REGS_HOST_TO_ABI0() 195 196 // The return value was placed in AX above. 197 RET 198 199 // uint32 tstart_stdcall(M *newm); 200 TEXT runtime·tstart_stdcall(SB),NOSPLIT|NOFRAME,$0 201 // Switch from the host ABI to the Go ABI. 202 PUSH_REGS_HOST_TO_ABI0() 203 204 // CX contains first arg newm 205 MOVQ m_g0(CX), DX // g 206 207 // Layout new m scheduler stack on os stack. 208 MOVQ SP, AX 209 MOVQ AX, (g_stack+stack_hi)(DX) 210 SUBQ $(64*1024), AX // initial stack size (adjusted later) 211 MOVQ AX, (g_stack+stack_lo)(DX) 212 ADDQ $const_stackGuard, AX 213 MOVQ AX, g_stackguard0(DX) 214 MOVQ AX, g_stackguard1(DX) 215 216 // Set up tls. 217 LEAQ m_tls(CX), DI 218 MOVQ CX, g_m(DX) 219 MOVQ DX, g(DI) 220 CALL runtime·settls(SB) // clobbers CX 221 222 CALL runtime·stackcheck(SB) // clobbers AX,CX 223 CALL runtime·mstart(SB) 224 225 POP_REGS_HOST_TO_ABI0() 226 227 XORL AX, AX // return 0 == success 228 RET 229 230 // set tls base to DI 231 TEXT runtime·settls(SB),NOSPLIT,$0 232 MOVQ runtime·tls_g(SB), CX 233 MOVQ DI, 0(CX)(GS) 234 RET 235 236 // Runs on OS stack. 237 // duration (in -100ns units) is in dt+0(FP). 238 // g may be nil. 239 // The function leaves room for 4 syscall parameters 240 // (as per windows amd64 calling convention). 241 TEXT runtime·usleep2(SB),NOSPLIT,$48-4 242 MOVLQSX dt+0(FP), BX 243 MOVQ SP, AX 244 ANDQ $~15, SP // alignment as per Windows requirement 245 MOVQ AX, 40(SP) 246 LEAQ 32(SP), R8 // ptime 247 MOVQ BX, (R8) 248 MOVQ $-1, CX // handle 249 MOVQ $0, DX // alertable 250 MOVQ runtime·_NtWaitForSingleObject(SB), AX 251 CALL AX 252 MOVQ 40(SP), SP 253 RET 254 255 // Runs on OS stack. 256 TEXT runtime·switchtothread(SB),NOSPLIT,$0 257 MOVQ SP, AX 258 ANDQ $~15, SP // alignment as per Windows requirement 259 SUBQ $(48), SP // room for SP and 4 args as per Windows requirement 260 // plus one extra word to keep stack 16 bytes aligned 261 MOVQ AX, 32(SP) 262 MOVQ runtime·_SwitchToThread(SB), AX 263 CALL AX 264 MOVQ 32(SP), SP 265 RET 266 267 TEXT runtime·nanotime1(SB),NOSPLIT,$0-8 268 CMPB runtime·useQPCTime(SB), $0 269 JNE useQPC 270 MOVQ $_INTERRUPT_TIME, DI 271 MOVQ time_lo(DI), AX 272 IMULQ $100, AX 273 MOVQ AX, ret+0(FP) 274 RET 275 useQPC: 276 JMP runtime·nanotimeQPC(SB) 277 RET 278 279 // func osSetupTLS(mp *m) 280 // Setup TLS. for use by needm on Windows. 281 TEXT runtime·osSetupTLS(SB),NOSPLIT,$0-8 282 MOVQ mp+0(FP), AX 283 LEAQ m_tls(AX), DI 284 CALL runtime·settls(SB) 285 RET 286 287 // This is called from rt0_go, which runs on the system stack 288 // using the initial stack allocated by the OS. 289 TEXT runtime·wintls(SB),NOSPLIT,$0 290 // Allocate a TLS slot to hold g across calls to external code 291 MOVQ SP, AX 292 ANDQ $~15, SP // alignment as per Windows requirement 293 SUBQ $48, SP // room for SP and 4 args as per Windows requirement 294 // plus one extra word to keep stack 16 bytes aligned 295 MOVQ AX, 32(SP) 296 MOVQ runtime·_TlsAlloc(SB), AX 297 CALL AX 298 MOVQ 32(SP), SP 299 300 MOVQ AX, CX // TLS index 301 302 // Assert that slot is less than 64 so we can use _TEB->TlsSlots 303 CMPQ CX, $64 304 JB ok 305 306 // Fallback to the TEB arbitrary pointer. 307 // TODO: don't use the arbitrary pointer (see go.dev/issue/59824) 308 MOVQ $TEB_ArbitraryPtr, CX 309 JMP settls 310 ok: 311 // Convert the TLS index at CX into 312 // an offset from TEB_TlsSlots. 313 SHLQ $3, CX 314 315 // Save offset from TLS into tls_g. 316 ADDQ $TEB_TlsSlots, CX 317 settls: 318 MOVQ CX, runtime·tls_g(SB) 319 RET