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