1 // Copyright 2014 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 package runtime 6 7 import ( 8 "unsafe" 9 ) 10 11 type callbacks struct { 12 lock mutex 13 ctxt [cb_max]*wincallbackcontext 14 n int 15 } 16 17 func (c *wincallbackcontext) isCleanstack() bool { 18 return c.cleanstack 19 } 20 21 func (c *wincallbackcontext) setCleanstack(cleanstack bool) { 22 c.cleanstack = cleanstack 23 } 24 25 var ( 26 cbs callbacks 27 cbctxts **wincallbackcontext = &cbs.ctxt[0] // to simplify access to cbs.ctxt in sys_windows_*.s 28 29 callbackasm byte // type isn't really byte, it's code in runtime 30 ) 31 32 // callbackasmAddr returns address of runtime.callbackasm 33 // function adjusted by i. 34 // runtime.callbackasm is just a series of CALL instructions 35 // (each is 5 bytes long), and we want callback to arrive at 36 // correspondent call instruction instead of start of 37 // runtime.callbackasm. 38 func callbackasmAddr(i int) uintptr { 39 return uintptr(add(unsafe.Pointer(&callbackasm), uintptr(i*5))) 40 } 41 42 //go:linkname compileCallback syscall.compileCallback 43 func compileCallback(fn eface, cleanstack bool) (code uintptr) { 44 if fn._type == nil || (fn._type.kind&kindMask) != kindFunc { 45 panic("compileCallback: not a function") 46 } 47 ft := (*functype)(unsafe.Pointer(fn._type)) 48 if len(ft.out()) != 1 { 49 panic("compileCallback: function must have one output parameter") 50 } 51 uintptrSize := unsafe.Sizeof(uintptr(0)) 52 if ft.out()[0].size != uintptrSize { 53 panic("compileCallback: output parameter size is wrong") 54 } 55 argsize := uintptr(0) 56 for _, t := range ft.in() { 57 if t.size > uintptrSize { 58 panic("compileCallback: input parameter size is wrong") 59 } 60 argsize += uintptrSize 61 } 62 63 lock(&cbs.lock) 64 defer unlock(&cbs.lock) 65 66 n := cbs.n 67 for i := 0; i < n; i++ { 68 if cbs.ctxt[i].gobody == fn.data && cbs.ctxt[i].isCleanstack() == cleanstack { 69 return callbackasmAddr(i) 70 } 71 } 72 if n >= cb_max { 73 throw("too many callback functions") 74 } 75 76 c := new(wincallbackcontext) 77 c.gobody = fn.data 78 c.argsize = argsize 79 c.setCleanstack(cleanstack) 80 if cleanstack && argsize != 0 { 81 c.restorestack = argsize 82 } else { 83 c.restorestack = 0 84 } 85 cbs.ctxt[n] = c 86 cbs.n++ 87 88 return callbackasmAddr(n) 89 } 90 91 const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 92 93 //go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary 94 //go:nosplit 95 func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) { 96 c := &getg().m.syscall 97 98 if useLoadLibraryEx { 99 c.fn = getLoadLibraryEx() 100 c.n = 3 101 args := struct { 102 lpFileName *uint16 103 hFile uintptr // always 0 104 flags uint32 105 }{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32} 106 c.args = uintptr(noescape(unsafe.Pointer(&args))) 107 } else { 108 // User is on Windows XP or something ancient. 109 // The caller wanted to only load the filename DLL 110 // from the System32 directory but that facility 111 // doesn't exist, so just load it the normal way. This 112 // is a potential security risk, but so is Windows XP. 113 c.fn = getLoadLibrary() 114 c.n = 1 115 c.args = uintptr(noescape(unsafe.Pointer(&filename))) 116 } 117 118 cgocall(asmstdcallAddr, unsafe.Pointer(c)) 119 handle = c.r1 120 if handle == 0 { 121 err = c.err 122 } 123 return 124 } 125 126 //go:linkname syscall_loadlibrary syscall.loadlibrary 127 //go:nosplit 128 func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { 129 c := &getg().m.syscall 130 c.fn = getLoadLibrary() 131 c.n = 1 132 c.args = uintptr(noescape(unsafe.Pointer(&filename))) 133 cgocall(asmstdcallAddr, unsafe.Pointer(c)) 134 handle = c.r1 135 if handle == 0 { 136 err = c.err 137 } 138 return 139 } 140 141 //go:linkname syscall_getprocaddress syscall.getprocaddress 142 //go:nosplit 143 func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) { 144 c := &getg().m.syscall 145 c.fn = getGetProcAddress() 146 c.n = 2 147 c.args = uintptr(noescape(unsafe.Pointer(&handle))) 148 cgocall(asmstdcallAddr, unsafe.Pointer(c)) 149 outhandle = c.r1 150 if outhandle == 0 { 151 err = c.err 152 } 153 return 154 } 155 156 //go:linkname syscall_Syscall syscall.Syscall 157 //go:nosplit 158 func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) { 159 c := &getg().m.syscall 160 c.fn = fn 161 c.n = nargs 162 c.args = uintptr(noescape(unsafe.Pointer(&a1))) 163 cgocall(asmstdcallAddr, unsafe.Pointer(c)) 164 return c.r1, c.r2, c.err 165 } 166 167 //go:linkname syscall_Syscall6 syscall.Syscall6 168 //go:nosplit 169 func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { 170 c := &getg().m.syscall 171 c.fn = fn 172 c.n = nargs 173 c.args = uintptr(noescape(unsafe.Pointer(&a1))) 174 cgocall(asmstdcallAddr, unsafe.Pointer(c)) 175 return c.r1, c.r2, c.err 176 } 177 178 //go:linkname syscall_Syscall9 syscall.Syscall9 179 //go:nosplit 180 func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) { 181 c := &getg().m.syscall 182 c.fn = fn 183 c.n = nargs 184 c.args = uintptr(noescape(unsafe.Pointer(&a1))) 185 cgocall(asmstdcallAddr, unsafe.Pointer(c)) 186 return c.r1, c.r2, c.err 187 } 188 189 //go:linkname syscall_Syscall12 syscall.Syscall12 190 //go:nosplit 191 func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) { 192 c := &getg().m.syscall 193 c.fn = fn 194 c.n = nargs 195 c.args = uintptr(noescape(unsafe.Pointer(&a1))) 196 cgocall(asmstdcallAddr, unsafe.Pointer(c)) 197 return c.r1, c.r2, c.err 198 } 199 200 //go:linkname syscall_Syscall15 syscall.Syscall15 201 //go:nosplit 202 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) { 203 c := &getg().m.syscall 204 c.fn = fn 205 c.n = nargs 206 c.args = uintptr(noescape(unsafe.Pointer(&a1))) 207 cgocall(asmstdcallAddr, unsafe.Pointer(c)) 208 return c.r1, c.r2, c.err 209 } 210