github.com/pkujhd/goloader@v0.0.0-20240411034752-1a28096bd7bd/register.go (about)

     1  package goloader
     2  
     3  import (
     4  	"cmd/objfile/objfile"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"strings"
     9  	"unsafe"
    10  
    11  	"github.com/pkujhd/goloader/constants"
    12  )
    13  
    14  // !IMPORTANT: only init firstmodule type, avoid load multiple objs but unload non-sequence errors
    15  func typelinksRegister(symPtr map[string]uintptr) {
    16  	md := firstmoduledata
    17  	for _, tl := range md.typelinks {
    18  		t := (*_type)(adduintptr(md.types, int(tl)))
    19  		if md.typemap != nil {
    20  			t = (*_type)(adduintptr(md.typemap[typeOff(tl)], 0))
    21  		}
    22  		registerType(t, symPtr)
    23  	}
    24  	//register function
    25  	for _, f := range md.ftab {
    26  		if int(f.funcoff) < len(md.pclntable) {
    27  			_func := (*_func)(unsafe.Pointer(&(md.pclntable[f.funcoff])))
    28  			name := getfuncname(_func, &md)
    29  			if name != EmptyString {
    30  				if _, ok := symPtr[name]; !ok {
    31  					symPtr[name] = getfuncentry(_func, md.text)
    32  				}
    33  			}
    34  		}
    35  	}
    36  }
    37  
    38  func registerType(t *_type, symPtr map[string]uintptr) {
    39  	if t.Kind() == reflect.Invalid {
    40  		panic("Unexpected invalid kind during registration!")
    41  	}
    42  
    43  	name := constants.TypePrefix + resolveTypeName(t)
    44  	if _, ok := symPtr[name]; ok {
    45  		return
    46  	}
    47  	symPtr[name] = uintptr(unsafe.Pointer(t))
    48  
    49  	switch t.Kind() {
    50  	case reflect.Ptr, reflect.Chan, reflect.Array, reflect.Slice:
    51  		registerType(rtypeOf(t.Elem()), symPtr)
    52  	case reflect.Func:
    53  		for i := 0; i < t.NumIn(); i++ {
    54  			registerType(rtypeOf(t.In(i)), symPtr)
    55  		}
    56  		for i := 0; i < t.NumOut(); i++ {
    57  			registerType(rtypeOf(t.Out(i)), symPtr)
    58  		}
    59  	case reflect.Struct:
    60  		for i := 0; i < t.NumField(); i++ {
    61  			registerType(rtypeOf(t.Field(i).Type), symPtr)
    62  		}
    63  	case reflect.Map:
    64  		registerType(rtypeOf(t.Key()), symPtr)
    65  		registerType(rtypeOf(t.Elem()), symPtr)
    66  	case reflect.Bool,
    67  		reflect.Int, reflect.Uint,
    68  		reflect.Int64, reflect.Uint64,
    69  		reflect.Int32, reflect.Uint32,
    70  		reflect.Int16, reflect.Uint16,
    71  		reflect.Int8, reflect.Uint8,
    72  		reflect.Float64, reflect.Float32,
    73  		reflect.Complex64, reflect.Complex128,
    74  		reflect.String, reflect.UnsafePointer,
    75  		reflect.Uintptr,
    76  		reflect.Interface:
    77  		// Nothing to do
    78  	default:
    79  		panic(fmt.Sprintf("typelinksregister found unexpected type (kind %s): ", t.Kind()))
    80  	}
    81  }
    82  
    83  func RegSymbolWithSo(symPtr map[string]uintptr, path string) error {
    84  	typelinksRegister(symPtr)
    85  	return regSymbol(symPtr, path)
    86  }
    87  
    88  func RegSymbolWithPath(symPtr map[string]uintptr, path string) error {
    89  	//register types and functions in exe file, the address of symbol not used for relocateaaa, just
    90  	//for builder check reachable
    91  	err := registerTypesInExe(symPtr, path)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	return regSymbol(symPtr, path)
    96  }
    97  
    98  func RegSymbol(symPtr map[string]uintptr) error {
    99  	path, err := os.Executable()
   100  	if err != nil {
   101  		return err
   102  	}
   103  	typelinksRegister(symPtr)
   104  	return regSymbol(symPtr, path)
   105  }
   106  
   107  func regSymbol(symPtr map[string]uintptr, path string) error {
   108  	f, err := objfile.Open(path)
   109  	if err != nil {
   110  		return err
   111  	}
   112  	defer f.Close()
   113  
   114  	syms, err := f.Symbols()
   115  	for _, sym := range syms {
   116  		if sym.Name == OsStdout {
   117  			symPtr[sym.Name] = uintptr(sym.Addr)
   118  		}
   119  	}
   120  	//Address space layout randomization(ASLR)
   121  	//golang 1.15 symbol address has offset, before 1.15 offset is 0
   122  	addroff := int64(uintptr(unsafe.Pointer(&os.Stdout))) - int64(symPtr[OsStdout])
   123  	for _, sym := range syms {
   124  		code := strings.ToUpper(string(sym.Code))
   125  		if code == "B" || code == "D" {
   126  			symPtr[sym.Name] = uintptr(int64(sym.Addr) + addroff)
   127  		}
   128  		if strings.HasPrefix(sym.Name, constants.ItabPrefix) {
   129  			symPtr[sym.Name] = uintptr(int64(sym.Addr) + addroff)
   130  		}
   131  	}
   132  	return nil
   133  }