github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/syscall/dll_windows.go (about) 1 // Copyright 2011 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 syscall 6 7 import ( 8 "internal/syscall/windows/sysdll" 9 "sync" 10 "sync/atomic" 11 "unsafe" 12 ) 13 14 // DLLError describes reasons for DLL load failures. 15 type DLLError struct { 16 Err error 17 ObjName string 18 Msg string 19 } 20 21 func (e *DLLError) Error() string { return e.Msg } 22 23 func (e *DLLError) Unwrap() error { return e.Err } 24 25 // Implemented in ../runtime/syscall_windows.go. 26 27 // Deprecated: Use [SyscallN] instead. 28 func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) 29 30 // Deprecated: Use [SyscallN] instead. 31 func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) 32 33 // Deprecated: Use [SyscallN] instead. 34 func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) 35 36 // Deprecated: Use [SyscallN] instead. 37 func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno) 38 39 // Deprecated: Use [SyscallN] instead. 40 func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno) 41 42 // Deprecated: Use [SyscallN] instead. 43 func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2 uintptr, err Errno) 44 45 func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno) 46 func loadlibrary(filename *uint16) (handle uintptr, err Errno) 47 func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno) 48 func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno) 49 50 // A DLL implements access to a single DLL. 51 type DLL struct { 52 Name string 53 Handle Handle 54 } 55 56 // LoadDLL loads the named DLL file into memory. 57 // 58 // If name is not an absolute path and is not a known system DLL used by 59 // Go, Windows will search for the named DLL in many locations, causing 60 // potential DLL preloading attacks. 61 // 62 // Use [LazyDLL] in golang.org/x/sys/windows for a secure way to 63 // load system DLLs. 64 func LoadDLL(name string) (*DLL, error) { 65 namep, err := UTF16PtrFromString(name) 66 if err != nil { 67 return nil, err 68 } 69 var h uintptr 70 var e Errno 71 if sysdll.IsSystemDLL[name] { 72 h, e = loadsystemlibrary(namep) 73 } else { 74 h, e = loadlibrary(namep) 75 } 76 if e != 0 { 77 return nil, &DLLError{ 78 Err: e, 79 ObjName: name, 80 Msg: "Failed to load " + name + ": " + e.Error(), 81 } 82 } 83 d := &DLL{ 84 Name: name, 85 Handle: Handle(h), 86 } 87 return d, nil 88 } 89 90 // MustLoadDLL is like [LoadDLL] but panics if load operation fails. 91 func MustLoadDLL(name string) *DLL { 92 d, e := LoadDLL(name) 93 if e != nil { 94 panic(e) 95 } 96 return d 97 } 98 99 // FindProc searches [DLL] d for procedure named name and returns [*Proc] 100 // if found. It returns an error if search fails. 101 func (d *DLL) FindProc(name string) (proc *Proc, err error) { 102 namep, err := BytePtrFromString(name) 103 if err != nil { 104 return nil, err 105 } 106 a, e := getprocaddress(uintptr(d.Handle), namep) 107 if e != 0 { 108 return nil, &DLLError{ 109 Err: e, 110 ObjName: name, 111 Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(), 112 } 113 } 114 p := &Proc{ 115 Dll: d, 116 Name: name, 117 addr: a, 118 } 119 return p, nil 120 } 121 122 // MustFindProc is like [DLL.FindProc] but panics if search fails. 123 func (d *DLL) MustFindProc(name string) *Proc { 124 p, e := d.FindProc(name) 125 if e != nil { 126 panic(e) 127 } 128 return p 129 } 130 131 // Release unloads [DLL] d from memory. 132 func (d *DLL) Release() (err error) { 133 return FreeLibrary(d.Handle) 134 } 135 136 // A Proc implements access to a procedure inside a [DLL]. 137 type Proc struct { 138 Dll *DLL 139 Name string 140 addr uintptr 141 } 142 143 // Addr returns the address of the procedure represented by p. 144 // The return value can be passed to Syscall to run the procedure. 145 func (p *Proc) Addr() uintptr { 146 return p.addr 147 } 148 149 // Call executes procedure p with arguments a. 150 // 151 // The returned error is always non-nil, constructed from the result of GetLastError. 152 // Callers must inspect the primary return value to decide whether an error occurred 153 // (according to the semantics of the specific function being called) before consulting 154 // the error. The error always has type [Errno]. 155 // 156 // On amd64, Call can pass and return floating-point values. To pass 157 // an argument x with C type "float", use 158 // uintptr(math.Float32bits(x)). To pass an argument with C type 159 // "double", use uintptr(math.Float64bits(x)). Floating-point return 160 // values are returned in r2. The return value for C type "float" is 161 // [math.Float32frombits](uint32(r2)). For C type "double", it is 162 // [math.Float64frombits](uint64(r2)). 163 // 164 //go:uintptrescapes 165 func (p *Proc) Call(a ...uintptr) (uintptr, uintptr, error) { 166 return SyscallN(p.Addr(), a...) 167 } 168 169 // A LazyDLL implements access to a single [DLL]. 170 // It will delay the load of the DLL until the first 171 // call to its [LazyDLL.Handle] method or to one of its 172 // [LazyProc]'s Addr method. 173 // 174 // LazyDLL is subject to the same DLL preloading attacks as documented 175 // on [LoadDLL]. 176 // 177 // Use LazyDLL in golang.org/x/sys/windows for a secure way to 178 // load system DLLs. 179 type LazyDLL struct { 180 mu sync.Mutex 181 dll *DLL // non nil once DLL is loaded 182 Name string 183 } 184 185 // Load loads DLL file d.Name into memory. It returns an error if fails. 186 // Load will not try to load DLL, if it is already loaded into memory. 187 func (d *LazyDLL) Load() error { 188 // Non-racy version of: 189 // if d.dll == nil { 190 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil { 191 d.mu.Lock() 192 defer d.mu.Unlock() 193 if d.dll == nil { 194 dll, e := LoadDLL(d.Name) 195 if e != nil { 196 return e 197 } 198 // Non-racy version of: 199 // d.dll = dll 200 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll)) 201 } 202 } 203 return nil 204 } 205 206 // mustLoad is like Load but panics if search fails. 207 func (d *LazyDLL) mustLoad() { 208 e := d.Load() 209 if e != nil { 210 panic(e) 211 } 212 } 213 214 // Handle returns d's module handle. 215 func (d *LazyDLL) Handle() uintptr { 216 d.mustLoad() 217 return uintptr(d.dll.Handle) 218 } 219 220 // NewProc returns a [LazyProc] for accessing the named procedure in the [DLL] d. 221 func (d *LazyDLL) NewProc(name string) *LazyProc { 222 return &LazyProc{l: d, Name: name} 223 } 224 225 // NewLazyDLL creates new [LazyDLL] associated with [DLL] file. 226 func NewLazyDLL(name string) *LazyDLL { 227 return &LazyDLL{Name: name} 228 } 229 230 // A LazyProc implements access to a procedure inside a [LazyDLL]. 231 // It delays the lookup until the [LazyProc.Addr], [LazyProc.Call], or [LazyProc.Find] method is called. 232 type LazyProc struct { 233 mu sync.Mutex 234 Name string 235 l *LazyDLL 236 proc *Proc 237 } 238 239 // Find searches [DLL] for procedure named p.Name. It returns 240 // an error if search fails. Find will not search procedure, 241 // if it is already found and loaded into memory. 242 func (p *LazyProc) Find() error { 243 // Non-racy version of: 244 // if p.proc == nil { 245 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil { 246 p.mu.Lock() 247 defer p.mu.Unlock() 248 if p.proc == nil { 249 e := p.l.Load() 250 if e != nil { 251 return e 252 } 253 proc, e := p.l.dll.FindProc(p.Name) 254 if e != nil { 255 return e 256 } 257 // Non-racy version of: 258 // p.proc = proc 259 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc)) 260 } 261 } 262 return nil 263 } 264 265 // mustFind is like Find but panics if search fails. 266 func (p *LazyProc) mustFind() { 267 e := p.Find() 268 if e != nil { 269 panic(e) 270 } 271 } 272 273 // Addr returns the address of the procedure represented by p. 274 // The return value can be passed to Syscall to run the procedure. 275 func (p *LazyProc) Addr() uintptr { 276 p.mustFind() 277 return p.proc.Addr() 278 } 279 280 // Call executes procedure p with arguments a. See the documentation of 281 // Proc.Call for more information. 282 // 283 //go:uintptrescapes 284 func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { 285 p.mustFind() 286 return p.proc.Call(a...) 287 }