Source file
src/runtime/syscall_windows.go
Documentation: runtime
1
2
3
4
5 package runtime
6
7 import (
8 "internal/abi"
9 "internal/goarch"
10 "unsafe"
11 )
12
13
14 var cbs struct {
15 lock mutex
16 ctxt [cb_max]winCallback
17 index map[winCallbackKey]int
18 n int
19 }
20
21 func cbsLock() {
22 lock(&cbs.lock)
23
24
25
26
27 if raceenabled && mainStarted {
28 raceacquire(unsafe.Pointer(&cbs.lock))
29 }
30 }
31
32 func cbsUnlock() {
33 if raceenabled && mainStarted {
34 racerelease(unsafe.Pointer(&cbs.lock))
35 }
36 unlock(&cbs.lock)
37 }
38
39
40 type winCallback struct {
41 fn *funcval
42 retPop uintptr
43 abiMap abiDesc
44 }
45
46
47 type abiPartKind int
48
49 const (
50 abiPartBad abiPartKind = iota
51 abiPartStack
52 abiPartReg
53 )
54
55
56 type abiPart struct {
57 kind abiPartKind
58 srcStackOffset uintptr
59 dstStackOffset uintptr
60 dstRegister int
61 len uintptr
62 }
63
64 func (a *abiPart) tryMerge(b abiPart) bool {
65 if a.kind != abiPartStack || b.kind != abiPartStack {
66 return false
67 }
68 if a.srcStackOffset+a.len == b.srcStackOffset && a.dstStackOffset+a.len == b.dstStackOffset {
69 a.len += b.len
70 return true
71 }
72 return false
73 }
74
75
76
77
78
79
80 type abiDesc struct {
81 parts []abiPart
82
83 srcStackSize uintptr
84 dstStackSize uintptr
85 dstSpill uintptr
86 dstRegisters int
87
88
89
90 retOffset uintptr
91 }
92
93 func (p *abiDesc) assignArg(t *_type) {
94 if t.Size_ > goarch.PtrSize {
95
96
97
98
99
100
101
102
103
104 panic("compileCallback: argument size is larger than uintptr")
105 }
106 if k := t.Kind_ & kindMask; GOARCH != "386" && (k == kindFloat32 || k == kindFloat64) {
107
108
109
110
111
112
113
114 panic("compileCallback: float arguments not supported")
115 }
116
117 if t.Size_ == 0 {
118
119 p.dstStackSize = alignUp(p.dstStackSize, uintptr(t.Align_))
120 return
121 }
122
123
124
125
126
127
128
129
130
131 oldParts := p.parts
132 if p.tryRegAssignArg(t, 0) {
133
134
135
136
137 p.dstSpill = alignUp(p.dstSpill, uintptr(t.Align_))
138 p.dstSpill += t.Size_
139 } else {
140
141
142 p.parts = oldParts
143
144
145 p.dstStackSize = alignUp(p.dstStackSize, uintptr(t.Align_))
146
147
148
149
150
151 part := abiPart{
152 kind: abiPartStack,
153 srcStackOffset: p.srcStackSize,
154 dstStackOffset: p.dstStackSize,
155 len: t.Size_,
156 }
157
158 if len(p.parts) == 0 || !p.parts[len(p.parts)-1].tryMerge(part) {
159 p.parts = append(p.parts, part)
160 }
161
162 p.dstStackSize += t.Size_
163 }
164
165
166
167 p.srcStackSize += goarch.PtrSize
168 }
169
170
171
172
173
174
175
176 func (p *abiDesc) tryRegAssignArg(t *_type, offset uintptr) bool {
177 switch k := t.Kind_ & kindMask; k {
178 case kindBool, kindInt, kindInt8, kindInt16, kindInt32, kindUint, kindUint8, kindUint16, kindUint32, kindUintptr, kindPtr, kindUnsafePointer:
179
180 return p.assignReg(t.Size_, offset)
181 case kindInt64, kindUint64:
182
183 if goarch.PtrSize == 8 {
184 return p.assignReg(t.Size_, offset)
185 }
186 case kindArray:
187 at := (*arraytype)(unsafe.Pointer(t))
188 if at.Len == 1 {
189 return p.tryRegAssignArg(at.Elem, offset)
190 }
191 case kindStruct:
192 st := (*structtype)(unsafe.Pointer(t))
193 for i := range st.Fields {
194 f := &st.Fields[i]
195 if !p.tryRegAssignArg(f.Typ, offset+f.Offset) {
196 return false
197 }
198 }
199 return true
200 }
201
202
203 panic("compileCallback: type " + toRType(t).string() + " is currently not supported for use in system callbacks")
204 }
205
206
207
208
209
210
211 func (p *abiDesc) assignReg(size, offset uintptr) bool {
212 if p.dstRegisters >= intArgRegs {
213 return false
214 }
215 p.parts = append(p.parts, abiPart{
216 kind: abiPartReg,
217 srcStackOffset: p.srcStackSize + offset,
218 dstRegister: p.dstRegisters,
219 len: size,
220 })
221 p.dstRegisters++
222 return true
223 }
224
225 type winCallbackKey struct {
226 fn *funcval
227 cdecl bool
228 }
229
230 func callbackasm()
231
232
233
234
235
236
237
238
239
240
241 func callbackasmAddr(i int) uintptr {
242 var entrySize int
243 switch GOARCH {
244 default:
245 panic("unsupported architecture")
246 case "386", "amd64":
247 entrySize = 5
248 case "arm", "arm64":
249
250
251 entrySize = 8
252 }
253 return abi.FuncPCABI0(callbackasm) + uintptr(i*entrySize)
254 }
255
256 const callbackMaxFrame = 64 * goarch.PtrSize
257
258
259
260
261
262
263
264
265
266 func compileCallback(fn eface, cdecl bool) (code uintptr) {
267 if GOARCH != "386" {
268
269 cdecl = false
270 }
271
272 if fn._type == nil || (fn._type.Kind_&kindMask) != kindFunc {
273 panic("compileCallback: expected function with one uintptr-sized result")
274 }
275 ft := (*functype)(unsafe.Pointer(fn._type))
276
277
278 var abiMap abiDesc
279 for _, t := range ft.InSlice() {
280 abiMap.assignArg(t)
281 }
282
283
284 abiMap.dstStackSize = alignUp(abiMap.dstStackSize, goarch.PtrSize)
285 abiMap.retOffset = abiMap.dstStackSize
286
287 if len(ft.OutSlice()) != 1 {
288 panic("compileCallback: expected function with one uintptr-sized result")
289 }
290 if ft.OutSlice()[0].Size_ != goarch.PtrSize {
291 panic("compileCallback: expected function with one uintptr-sized result")
292 }
293 if k := ft.OutSlice()[0].Kind_ & kindMask; k == kindFloat32 || k == kindFloat64 {
294
295
296
297 panic("compileCallback: float results not supported")
298 }
299 if intArgRegs == 0 {
300
301
302
303 abiMap.dstStackSize += goarch.PtrSize
304 }
305
306
307
308 frameSize := alignUp(abiMap.dstStackSize, goarch.PtrSize)
309 frameSize += abiMap.dstSpill
310 if frameSize > callbackMaxFrame {
311 panic("compileCallback: function argument frame too large")
312 }
313
314
315
316 var retPop uintptr
317 if cdecl {
318 retPop = abiMap.srcStackSize
319 }
320
321 key := winCallbackKey{(*funcval)(fn.data), cdecl}
322
323 cbsLock()
324
325
326 if n, ok := cbs.index[key]; ok {
327 cbsUnlock()
328 return callbackasmAddr(n)
329 }
330
331
332 if cbs.index == nil {
333 cbs.index = make(map[winCallbackKey]int)
334 }
335 n := cbs.n
336 if n >= len(cbs.ctxt) {
337 cbsUnlock()
338 throw("too many callback functions")
339 }
340 c := winCallback{key.fn, retPop, abiMap}
341 cbs.ctxt[n] = c
342 cbs.index[key] = n
343 cbs.n++
344
345 cbsUnlock()
346 return callbackasmAddr(n)
347 }
348
349 type callbackArgs struct {
350 index uintptr
351
352
353
354
355
356
357
358
359
360
361
362 args unsafe.Pointer
363
364 result uintptr
365 retPop uintptr
366 }
367
368
369 func callbackWrap(a *callbackArgs) {
370 c := cbs.ctxt[a.index]
371 a.retPop = c.retPop
372
373
374 var regs abi.RegArgs
375 var frame [callbackMaxFrame]byte
376 goArgs := unsafe.Pointer(&frame)
377 for _, part := range c.abiMap.parts {
378 switch part.kind {
379 case abiPartStack:
380 memmove(add(goArgs, part.dstStackOffset), add(a.args, part.srcStackOffset), part.len)
381 case abiPartReg:
382 goReg := unsafe.Pointer(®s.Ints[part.dstRegister])
383 memmove(goReg, add(a.args, part.srcStackOffset), part.len)
384 default:
385 panic("bad ABI description")
386 }
387 }
388
389
390
391 frameSize := alignUp(c.abiMap.dstStackSize, goarch.PtrSize)
392 frameSize += c.abiMap.dstSpill
393
394
395
396 reflectcall(nil, unsafe.Pointer(c.fn), noescape(goArgs), uint32(c.abiMap.dstStackSize), uint32(c.abiMap.retOffset), uint32(frameSize), ®s)
397
398
399
400
401
402
403 if c.abiMap.dstStackSize != c.abiMap.retOffset {
404 a.result = *(*uintptr)(unsafe.Pointer(&frame[c.abiMap.retOffset]))
405 } else {
406 var zero int
407
408
409
410 a.result = regs.Ints[zero]
411 }
412 }
413
414 const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
415
416
417
418
419 func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
420 lockOSThread()
421 c := &getg().m.syscall
422 c.fn = getLoadLibraryEx()
423 c.n = 3
424 args := struct {
425 lpFileName *uint16
426 hFile uintptr
427 flags uint32
428 }{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32}
429 c.args = uintptr(noescape(unsafe.Pointer(&args)))
430
431 cgocall(asmstdcallAddr, unsafe.Pointer(c))
432 KeepAlive(filename)
433 handle = c.r1
434 if handle == 0 {
435 err = c.err
436 }
437 unlockOSThread()
438 return
439 }
440
441
442
443
444 func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
445 lockOSThread()
446 defer unlockOSThread()
447 c := &getg().m.syscall
448 c.fn = getLoadLibrary()
449 c.n = 1
450 c.args = uintptr(noescape(unsafe.Pointer(&filename)))
451 cgocall(asmstdcallAddr, unsafe.Pointer(c))
452 KeepAlive(filename)
453 handle = c.r1
454 if handle == 0 {
455 err = c.err
456 }
457 return
458 }
459
460
461
462
463 func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
464 lockOSThread()
465 defer unlockOSThread()
466 c := &getg().m.syscall
467 c.fn = getGetProcAddress()
468 c.n = 2
469 c.args = uintptr(noescape(unsafe.Pointer(&handle)))
470 cgocall(asmstdcallAddr, unsafe.Pointer(c))
471 KeepAlive(procname)
472 outhandle = c.r1
473 if outhandle == 0 {
474 err = c.err
475 }
476 return
477 }
478
479
480
481 func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
482 return syscall_SyscallN(fn, a1, a2, a3)
483 }
484
485
486
487 func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
488 return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6)
489 }
490
491
492
493 func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
494 return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9)
495 }
496
497
498
499 func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) {
500 return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
501 }
502
503
504
505 func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
506 return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
507 }
508
509
510
511 func syscall_Syscall18(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2, err uintptr) {
512 return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18)
513 }
514
515
516
517
518
519
520 const maxArgs = 42
521
522
523
524 func syscall_SyscallN(trap uintptr, args ...uintptr) (r1, r2, err uintptr) {
525 nargs := len(args)
526
527
528
529 var tmp [4]uintptr
530 switch {
531 case nargs < 4:
532 copy(tmp[:], args)
533 args = tmp[:]
534 case nargs > maxArgs:
535 panic("runtime: SyscallN has too many arguments")
536 }
537
538 lockOSThread()
539 defer unlockOSThread()
540 c := &getg().m.syscall
541 c.fn = trap
542 c.n = uintptr(nargs)
543 c.args = uintptr(noescape(unsafe.Pointer(&args[0])))
544 cgocall(asmstdcallAddr, unsafe.Pointer(c))
545 return c.r1, c.r2, c.err
546 }
547
View as plain text