Home | History | Annotate | Download | only in runtime
      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 	lockOSThread()
     97 	defer unlockOSThread()
     98 	c := &getg().m.syscall
     99 
    100 	if useLoadLibraryEx {
    101 		c.fn = getLoadLibraryEx()
    102 		c.n = 3
    103 		args := struct {
    104 			lpFileName *uint16
    105 			hFile      uintptr // always 0
    106 			flags      uint32
    107 		}{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32}
    108 		c.args = uintptr(noescape(unsafe.Pointer(&args)))
    109 	} else {
    110 		// User is on Windows XP or something ancient.
    111 		// The caller wanted to only load the filename DLL
    112 		// from the System32 directory but that facility
    113 		// doesn't exist, so just load it the normal way. This
    114 		// is a potential security risk, but so is Windows XP.
    115 		c.fn = getLoadLibrary()
    116 		c.n = 1
    117 		c.args = uintptr(noescape(unsafe.Pointer(&filename)))
    118 	}
    119 
    120 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    121 	handle = c.r1
    122 	if handle == 0 {
    123 		err = c.err
    124 	}
    125 	return
    126 }
    127 
    128 //go:linkname syscall_loadlibrary syscall.loadlibrary
    129 //go:nosplit
    130 func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
    131 	lockOSThread()
    132 	defer unlockOSThread()
    133 	c := &getg().m.syscall
    134 	c.fn = getLoadLibrary()
    135 	c.n = 1
    136 	c.args = uintptr(noescape(unsafe.Pointer(&filename)))
    137 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    138 	handle = c.r1
    139 	if handle == 0 {
    140 		err = c.err
    141 	}
    142 	return
    143 }
    144 
    145 //go:linkname syscall_getprocaddress syscall.getprocaddress
    146 //go:nosplit
    147 func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
    148 	lockOSThread()
    149 	defer unlockOSThread()
    150 	c := &getg().m.syscall
    151 	c.fn = getGetProcAddress()
    152 	c.n = 2
    153 	c.args = uintptr(noescape(unsafe.Pointer(&handle)))
    154 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    155 	outhandle = c.r1
    156 	if outhandle == 0 {
    157 		err = c.err
    158 	}
    159 	return
    160 }
    161 
    162 //go:linkname syscall_Syscall syscall.Syscall
    163 //go:nosplit
    164 func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
    165 	lockOSThread()
    166 	defer unlockOSThread()
    167 	c := &getg().m.syscall
    168 	c.fn = fn
    169 	c.n = nargs
    170 	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
    171 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    172 	return c.r1, c.r2, c.err
    173 }
    174 
    175 //go:linkname syscall_Syscall6 syscall.Syscall6
    176 //go:nosplit
    177 func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
    178 	lockOSThread()
    179 	defer unlockOSThread()
    180 	c := &getg().m.syscall
    181 	c.fn = fn
    182 	c.n = nargs
    183 	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
    184 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    185 	return c.r1, c.r2, c.err
    186 }
    187 
    188 //go:linkname syscall_Syscall9 syscall.Syscall9
    189 //go:nosplit
    190 func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
    191 	lockOSThread()
    192 	defer unlockOSThread()
    193 	c := &getg().m.syscall
    194 	c.fn = fn
    195 	c.n = nargs
    196 	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
    197 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    198 	return c.r1, c.r2, c.err
    199 }
    200 
    201 //go:linkname syscall_Syscall12 syscall.Syscall12
    202 //go:nosplit
    203 func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) {
    204 	lockOSThread()
    205 	defer unlockOSThread()
    206 	c := &getg().m.syscall
    207 	c.fn = fn
    208 	c.n = nargs
    209 	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
    210 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    211 	return c.r1, c.r2, c.err
    212 }
    213 
    214 //go:linkname syscall_Syscall15 syscall.Syscall15
    215 //go:nosplit
    216 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) {
    217 	lockOSThread()
    218 	defer unlockOSThread()
    219 	c := &getg().m.syscall
    220 	c.fn = fn
    221 	c.n = nargs
    222 	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
    223 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    224 	return c.r1, c.r2, c.err
    225 }
    226