github.com/kitech/dl@v0.0.0-20201225001532-be4f4faa4070/dl2/dl.go (about)

     1  package dl
     2  
     3  // Still use some cgo type/const/variable
     4  // But aims avoid original cgo call to speed up call performance
     5  
     6  /*
     7  #cgo CFLAGS: -D_GNU_SOURCE
     8  #cgo LDFLAGS: -ldl
     9  
    10  #include <stdlib.h>
    11  #include <stdio.h>
    12  #include <stdint.h>
    13  #include <dlfcn.h>
    14  
    15  // 由于pad有问题,所有的函数都打包成一个void*结构体参数,返回值也打包在这个结构体中
    16  int goasmcc_dlopen(struct {char *a0; int a1; void* ret;} *ax) {
    17     ax->ret = dlopen(ax->a0, ax->a1);
    18     return 0; // just error code
    19  }
    20  int goasmcc_dlclose(struct {void* a0; int ret; } *ax) {
    21      ax->ret = dlclose(ax->a0);
    22    return 0;
    23  }
    24  int goasmcc_dlsym(struct {void* a0; char* a1; void* ret; } *ax) {
    25    ax->ret = dlsym(ax->a0, ax->a1);
    26    return 0;
    27  }
    28  int goasmcc_dlerror(struct {char* ret;} *ax) {
    29    ax->ret = dlerror();
    30    return 0;
    31  }
    32  int goasmcc_dladdr(struct {void* a0; Dl_info* a1; int ret;} *ax) {
    33    ax->ret = dladdr(ax->a0, ax->a1);
    34    return 0;
    35  }
    36  
    37  int goasmcc_empty() {
    38    char buf[100];
    39    buf[0] = 12;
    40    //sprintf(buf, "ttt %d", 999);
    41    return 0;
    42  }
    43  */
    44  import "C"
    45  
    46  import (
    47  	"fmt"
    48  	"unsafe"
    49  
    50  	"github.com/kitech/dl/asmcgocall"
    51  )
    52  
    53  //
    54  type Flags int
    55  
    56  const (
    57  	Lazy   Flags = C.RTLD_LAZY
    58  	Now    Flags = C.RTLD_NOW
    59  	Global Flags = C.RTLD_GLOBAL
    60  	Local  Flags = C.RTLD_LOCAL
    61  	//NoLoad   Flags = C.RTLD_NOLOAD
    62  	//NoDelete Flags = C.RTLD_NODELETE
    63  	// First Flags = C.RTLD_FIRST
    64  )
    65  
    66  func EmptyAsmcc(unsafe.Pointer) { asmcgocall.Asmcc(C.goasmcc_empty, nil) }
    67  func EmptyCgocc()               { C.goasmcc_empty() }
    68  
    69  type Handle struct {
    70  	fname string
    71  	c     unsafe.Pointer
    72  }
    73  
    74  func Open(fname string, flags Flags) (Handle, error) {
    75  	fname2 := []byte(fname + "\x00")
    76  	c_str := (*C.char)(unsafe.Pointer(&fname2[0]))
    77  
    78  	var argv = struct {
    79  		p0  *C.char
    80  		p1  C.int
    81  		ret unsafe.Pointer
    82  	}{c_str, C.int(flags), nil}
    83  
    84  	asmcgocall.Asmcc(C.goasmcc_dlopen, unsafe.Pointer(&argv))
    85  	h := argv.ret
    86  	if h == nil {
    87  		err := fmt.Errorf("dl: %s", DLError())
    88  		return Handle{}, err
    89  	}
    90  	h2 := unsafe.Pointer(uintptr(h))
    91  	return Handle{fname, h2}, nil
    92  }
    93  
    94  func (h Handle) Close() error {
    95  	if h.c == nil {
    96  		return nil
    97  	}
    98  	var argv = struct {
    99  		a0  unsafe.Pointer
   100  		ret C.int
   101  	}{h.c, 0}
   102  
   103  	asmcgocall.Asmcc(C.goasmcc_dlclose, unsafe.Pointer(&argv))
   104  	o := argv.ret
   105  	if o != C.int(0) {
   106  		err := fmt.Errorf("dl: %s", DLError())
   107  		return err
   108  	}
   109  	h.c = nil
   110  	return nil
   111  }
   112  
   113  func (h Handle) RawAddr() uintptr {
   114  	return uintptr(h.c)
   115  }
   116  
   117  func (h Handle) Symbol(symbol string) (uintptr, error) {
   118  	sym2 := []byte(symbol + "\x00") // ensure \0
   119  	c_sym := (*C.char)(unsafe.Pointer(&sym2[0]))
   120  
   121  	var argv = struct {
   122  		a0  unsafe.Pointer
   123  		a1  *C.char
   124  		ret unsafe.Pointer
   125  	}{h.c, c_sym, nil}
   126  
   127  	asmcgocall.Asmcc(C.goasmcc_dlsym, unsafe.Pointer(&argv))
   128  	c_addr := argv.ret
   129  	if c_addr == nil {
   130  		err := fmt.Errorf("dl: %s", DLError())
   131  		return 0, err
   132  	}
   133  	return uintptr(c_addr), nil
   134  }
   135  
   136  func (h Handle) DLError() string { return DLError() }
   137  func DLError() string {
   138  	var argv = struct{ ret *C.char }{nil}
   139  
   140  	asmcgocall.Asmcc(C.goasmcc_dlerror, unsafe.Pointer(&argv))
   141  	c_err := argv.ret
   142  	if c_err == nil {
   143  		return ""
   144  	}
   145  	return C.GoString(c_err)
   146  }
   147  
   148  type Dlinfo struct {
   149  	Fname string
   150  	Fbase unsafe.Pointer
   151  	Sname string
   152  	Saddr unsafe.Pointer
   153  }
   154  
   155  func DlAddr(addr unsafe.Pointer) (res Dlinfo) {
   156  	var dlainfo C.Dl_info
   157  
   158  	var argv = struct {
   159  		addr unsafe.Pointer
   160  		info unsafe.Pointer
   161  		ret  C.int
   162  	}{addr, unsafe.Pointer(&dlainfo), C.int(0)}
   163  
   164  	asmcgocall.Asmcc(C.goasmcc_dladdr, unsafe.Pointer(&argv))
   165  	rv := int(argv.ret)
   166  	if rv != 0 {
   167  		res.Fname = C.GoString(dlainfo.dli_fname)
   168  		res.Sname = C.GoString(dlainfo.dli_sname)
   169  		res.Fbase = dlainfo.dli_fbase
   170  		res.Saddr = dlainfo.dli_saddr
   171  	}
   172  	return
   173  }
   174  
   175  // TODO
   176  func (h Handle) Info() {
   177  	//C.dlinfo(h.c, 0, nil)
   178  	panic("not impled")
   179  }
   180  
   181  // /* Portable libltdl versions of the system dlopen() API. */
   182  // LT_SCOPE lt_dlhandle lt_dlopen          (const char *filename);
   183  // LT_SCOPE lt_dlhandle lt_dlopenext       (const char *filename);
   184  // LT_SCOPE lt_dlhandle lt_dlopenadvise    (const char *filename,
   185  //                                          lt_dladvise advise);
   186  // LT_SCOPE void *     lt_dlsym            (lt_dlhandle handle, const char *name);
   187  // LT_SCOPE const char *lt_dlerror         (void);
   188  // LT_SCOPE int        lt_dlclose          (lt_dlhandle handle);
   189  
   190  // EOF