// Copyright 2015 Luke Shumaker . // // This is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // The GNU General Public License's references to "object code" and // "executables" are to be interpreted to also include the output of // any document formatting or typesetting system, including // intermediate and printed output. // // This software is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public // License along with this manual; if not, see // . // Package dl provides an interface to the POSIX runtime linker. package dl import ( "errors" "sync" "unsafe" ) //#cgo LDFLAGS: -ldl //#include //#include import "C" var HandleClosedError = errors.New("Handle is already closed") type Flag int // POSIX specifies these four flags to Open(). const ( // Relocations are performed at an implementation-defined // time. RTLD_LAZY Flag = C.RTLD_LAZY // Relocations are performed when the object is loaded. RTLD_NOW Flag = C.RTLD_NOW // All symbols are available for relocation processing of // other modules. RTLD_GLOBAL Flag = C.RTLD_GLOBAL // All symbols are not made available for relocation // processing by other modules. RTLD_LOCAL Flag = C.RTLD_LOCAL ) type Handle struct { c unsafe.Pointer o int } var dllock sync.Mutex // Open a shared object file, returning a Handle to it, or an error. // If name is an empty string, then the returned handle is the global // symbol table for the current process; if the name contains a slash, // then it is interpretted as a pathname; otherwise, it is // interpretted in an implementation-defined manner. func Open(name string, flags Flag) (Handle, error) { nameC := C.CString(name) defer C.free(unsafe.Pointer(nameC)) if name == "" { nameC = nil } dllock.Lock() defer dllock.Unlock() dlerror() ptr := C.dlopen(nameC, C.int(flags)) if ptr == nil { return Handle{}, dlerror() } return Handle{c: ptr, o: 1}, nil } // Look up a symbol, and return a pointer to it. func (h Handle) Sym(symbol string) (unsafe.Pointer, error) { dllock.Lock() defer dllock.Unlock() if h.o == 0 { return nil, HandleClosedError } symbolC := C.CString(symbol) defer C.free(unsafe.Pointer(symbolC)) dlerror() ptr := C.dlsym(h.c, symbolC) if ptr == nil { return nil, dlerror() } return ptr, nil } // Close this handle on a shared object; decrementint the reference // count; if the reference count drops below 0, then the object is // unloaded. func (h Handle) Close() error { dllock.Lock() defer dllock.Unlock() if h.o == 0 { return HandleClosedError } dlerror() r := C.dlclose(h.c) if r != 0 { return dlerror() } if h.o == 1 { h.o = 0 } return nil } func dlerror() error { strC := C.dlerror() if strC == nil { return nil } return errors.New(C.GoString(strC)) }