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 	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