func (d *DL) Sym(symbol string, out interface{}) error {
	s := C.CString(symbol)
	defer C.free(unsafe.Pointer(s))
	mu.Lock()
	handle := C.dlsym(d.handle, s)
	if handle == nil {
		err := dlerror()
		mu.Unlock()
		return err
	}
	mu.Unlock()
	val := reflect.ValueOf(out)
	if !val.IsValid() || val.Kind() != reflect.Ptr {
		return fmt.Errorf("out must be a pointer, not %T", out)
	}
	if val.IsNil() {
		return errors.New("out can't be nil")
	}
	elem := val.Elem()
	switch elem.Kind() {
	case reflect.Int:
		elem.SetInt(int64(*(*int)(handle)))
	case reflect.Int8:
		elem.SetInt(int64(*(*int8)(handle)))
	case reflect.Int16:
		elem.SetInt(int64(*(*int16)(handle)))
	case reflect.Int32:
		elem.SetInt(int64(*(*int32)(handle)))
	case reflect.Int64:
		elem.SetInt(int64(*(*int64)(handle)))
	case reflect.Uint:
		elem.SetUint(uint64(*(*uint)(handle)))
	case reflect.Uint8:
		elem.SetUint(uint64(*(*uint8)(handle)))
	case reflect.Uint16:
		elem.SetUint(uint64(*(*uint16)(handle)))
	case reflect.Uint32:
		elem.SetUint(uint64(*(*uint32)(handle)))
	case reflect.Uint64:
		elem.SetUint(uint64(*(*uint64)(handle)))
	case reflect.Uintptr:
		elem.SetUint(uint64(*(*uintptr)(handle)))
	case reflect.Float32:
		elem.SetFloat(float64(*(*float32)(handle)))
	case reflect.Float64:
		elem.SetFloat(float64(*(*float64)(handle)))
	case reflect.Func:
		typ := elem.Type()
		tr, err := makeTrampoline(typ, handle)
		if err != nil {
			return err
		}
		v := reflect.MakeFunc(typ, tr)
		elem.Set(v)
	case reflect.Ptr:
		v := reflect.NewAt(elem.Type().Elem(), handle)
		elem.Set(v)
	case reflect.String:
		elem.SetString(C.GoString(*(**C.char)(handle)))
	case reflect.UnsafePointer:
		elem.SetPointer(handle)
	default:
		return fmt.Errorf("invalid out type %T", out)
	}
	return nil
}
Sym loads the symbol identified by the given name into
the out parameter. Note that out must always be a pointer.
See the package documentation to learn how types are mapped
between Go and C.
package dl
import "C"
import (
	"errors"
	"fmt"
	"path/filepath"
	"reflect"
	"runtime"
	"sync"
	"unsafe"
)
const (
	RTLD_LAZY     = int(C.RTLD_LAZY)
	RTLD_NOW      = int(C.RTLD_NOW)
	RTLD_GLOBAL   = int(C.RTLD_GLOBAL)
	RTLD_LOCAL    = int(C.RTLD_LOCAL)
	RTLD_NODELETE = int(C.RTLD_NODELETE)
	RTLD_NOLOAD   = int(C.RTLD_NOLOAD)
)
var (
	mu sync.Mutex
)
type DL struct {
	mu     sync.Mutex
	handle unsafe.Pointer
}
func Open(name string, flag int) (*DL, error) {
	if flag&RTLD_LAZY == 0 && flag&RTLD_NOW == 0 {
		flag |= RTLD_NOW
	}
	if name != "" && filepath.Ext(name) == "" {
		name = name + LibExt
	}
	s := C.CString(name)
	defer C.free(unsafe.Pointer(s))
	mu.Lock()
	handle := C.dlopen(s, C.int(flag))
	var err error
	if handle == nil {
		err = dlerror()
	}
	mu.Unlock()
	if err != nil {
		if runtime.GOOS == "linux" && name == "libc.so" {
			return Open(name+".6", flag)
		}
		return nil, err
	}
	return &DL{
		handle: handle,
	}, nil
}