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