diff options
-rw-r--r-- | dl/dl_gnu.go | 58 | ||||
-rw-r--r-- | dl/dlfcn.go | 74 |
2 files changed, 132 insertions, 0 deletions
diff --git a/dl/dl_gnu.go b/dl/dl_gnu.go new file mode 100644 index 0000000..c7c409b --- /dev/null +++ b/dl/dl_gnu.go @@ -0,0 +1,58 @@ +package dl + +import "unsafe" + +//#define _GNU_SOURCE +//#include <stdlib.h> +//#include <stdint.h> +//#include <dlfcn.h> +//const uintptr_t rtld_next = (uintptr_t)RTLD_NEXT; +//const uintptr_t rtld_default = (uintptr_t)RTLD_DEFAULT; +import "C" + +const ( + RTLD_NOLOAD Flag = C.RTLD_NOLOAD + RTLD_NODELETE Flag = C.RTLD_NODELETE + RTLD_DEEPBIND Flag = C.RTLD_DEEPBIND +) + +// These are kinda weird in that they aren't required by the standard, +// but they are reserved by the standard (see the documentation for +// `dlsym(3)`). On glibc, it takes _GNU_SOURCE to get them. +// +// There are two special pseudo-handles that may be specified +// in handle: +var ( + RTLD_DEFAULT Handle = Handle{unsafe.Pointer(uintptr(C.rtld_default))} + // Find the first occurrence of the desired symbol using + // the default shared object search order. The search will + // include global symbols in the executable and its + // dependencies, as well as symbols in shared objects that + // were dynamically loaded with the RTLD_GLOBAL flag. + RTLD_NEXT Handle = Handle{unsafe.Pointer(uintptr(C.rtld_next))} + // Find the next occurrence of the desired symbol in the + // search order after the current object. This allows one + // to provide a wrapper around a function in another shared + // object, so that, for example, the definition of a + // function in a preloaded shared object (see LD_PRELOAD in + // ld.so(8)) can find and invoke the "real" function + // provided in another shared object (or for that matter, + // the "next" definition of the function in cases where + // there are multiple layers of preloading). +) + +// TODO: dlmopen +// TODO: dlvsym +// TODO: dladdr +// - dladdr1 +// TODO: dlinfo +// - RTLD_DI_LMID +// - RTLD_DI_LINKMAP +// - RTLD_DI_ORIGIN +// - RTLD_DI_SERINFO +// - RTLD_DI_SERINFOSIZE +// - RTLD_DI_MODID +// - RTLD_DI_DATA +// TODO: dl_iterate_phdr +// TODO: rtld-audit(7) + diff --git a/dl/dlfcn.go b/dl/dlfcn.go new file mode 100644 index 0000000..d5467f3 --- /dev/null +++ b/dl/dlfcn.go @@ -0,0 +1,74 @@ +package dl + +import ( + "errors" + "unsafe" +) + +//#cgo LDFLAGS: -ldl +//#include <stdlib.h> +//#include <dlfcn.h> +import "C" + +type Flag int + +const ( + RTLD_LAZY Flag = C.RTLD_LAZY // Relocations are performed at an + // implementation-defined time. + RTLD_NOW Flag = C.RTLD_NOW // Relocations are performed when the + // object is loaded. + RTLD_GLOBAL Flag = C.RTLD_GLOBAL // All symbols are available for + // relocation processing of other + // modules. + RTLD_LOCAL Flag = C.RTLD_LOCAL // All symbols are not made available + // for relocation processing by other + // modules. +) + +type Handle struct { + c unsafe.Pointer +} + +func Open(name string, flags Flag) (Handle, error) { + nameC := C.CString(name) + defer C.free(unsafe.Pointer(nameC)) + + dlerror() + ptr := C.dlopen(nameC, C.int(flags)) + if ptr == nil { + return Handle{}, dlerror() + } + return Handle{ptr}, nil +} + +// This returns uintptr instead of unsafe.Pointer so that code using +// reflect cannot obtain unsafe.Pointers without importing the unsafe +// package explicitly. +func (h Handle) Sym(symbol string) (uintptr, error) { + symbolC := C.CString(symbol) + defer C.free(unsafe.Pointer(symbolC)) + + dlerror() + ptr := C.dlsym(h.c, symbolC) + if ptr == nil { + return 0, dlerror() + } + return uintptr(ptr), nil +} + +func (h Handle) Close() error { + dlerror() + r := C.dlclose(h.c) + if r != 0 { + return dlerror() + } + return nil +} + +func dlerror() error { + strC := C.dlerror() + if strC == nil { + return nil + } + return errors.New(C.GoString(strC)) +} |