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_ & abi.KindMask; GOARCH != "386" && (k == abi.Float32 || k == abi.Float64) {
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_ & abi.KindMask; k {
178 case abi.Bool, abi.Int, abi.Int8, abi.Int16, abi.Int32, abi.Uint, abi.Uint8, abi.Uint16, abi.Uint32, abi.Uintptr, abi.Pointer, abi.UnsafePointer:
179
180 return p.assignReg(t.Size_, offset)
181 case abi.Int64, abi.Uint64:
182
183 if goarch.PtrSize == 8 {
184 return p.assignReg(t.Size_, offset)
185 }
186 case abi.Array:
187 at := (*arraytype)(unsafe.Pointer(t))
188 if at.Len == 1 {
189 return p.tryRegAssignArg(at.Elem, offset)
190 }
191 case abi.Struct:
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_&abi.KindMask) != abi.Func {
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_ & abi.KindMask; k == abi.Float32 || k == abi.Float64 {
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 func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) {
418 handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryExW)), uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32)
419 KeepAlive(filename)
420 if handle != 0 {
421 err = 0
422 }
423 return
424 }
425
426
427
428
429
430
431 func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
432 handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryW)), uintptr(unsafe.Pointer(filename)))
433 KeepAlive(filename)
434 if handle != 0 {
435 err = 0
436 }
437 return
438 }
439
440
441
442
443
444
445 func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
446 outhandle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_GetProcAddress)), handle, uintptr(unsafe.Pointer(procname)))
447 KeepAlive(procname)
448 if outhandle != 0 {
449 err = 0
450 }
451 return
452 }
453
454
455
456 func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
457 return syscall_syscalln(fn, nargs, a1, a2, a3)
458 }
459
460
461
462 func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
463 return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6)
464 }
465
466
467
468 func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
469 return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9)
470 }
471
472
473
474 func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) {
475 return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12)
476 }
477
478
479
480 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) {
481 return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
482 }
483
484
485
486 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) {
487 return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18)
488 }
489
490
491
492
493
494
495 const maxArgs = 42
496
497
498
499 func syscall_SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
500 return syscall_syscalln(fn, uintptr(len(args)), args...)
501 }
502
503
504 func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) {
505 if n > uintptr(len(args)) {
506 panic("syscall: n > len(args)")
507 }
508 if n > maxArgs {
509 panic("runtime: SyscallN has too many arguments")
510 }
511
512
513
514
515 c := &getg().m.winsyscall
516 c.fn = fn
517 c.n = n
518 if c.n != 0 {
519 c.args = uintptr(noescape(unsafe.Pointer(&args[0])))
520 }
521 cgocall(asmstdcallAddr, unsafe.Pointer(c))
522
523
524
525 c = &getg().m.winsyscall
526 return c.r1, c.r2, c.err
527 }
528
View as plain text