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

     1  package goloader
     2  
     3  import (
     4  	"cmd/objfile/gcprog"
     5  	"fmt"
     6  	"sort"
     7  	"unsafe"
     8  
     9  	"github.com/pkujhd/goloader/obj"
    10  	"github.com/pkujhd/goloader/objabi/symkind"
    11  )
    12  
    13  const (
    14  	KindGCProg = 1 << 6
    15  )
    16  
    17  func generategcdata(linker *Linker, codeModule *CodeModule, symbolMap map[string]uintptr, w *gcprog.Writer, sym *obj.Sym) error {
    18  	segment := &codeModule.segment
    19  	//if symbol is in loader, ignore generate gc data
    20  	if symbolMap[sym.Name] < uintptr(segment.dataBase) || symbolMap[sym.Name] > uintptr(segment.dataBase+segment.dataSeg.length) {
    21  		return nil
    22  	}
    23  	objsym := linker.ObjSymbolMap[sym.Name]
    24  	typeName := objsym.Type
    25  	if len(typeName) == 0 && objsym.Size > 0 {
    26  		// This is likely a global var with no type information encoded, so can't be GC'd (ignore it)
    27  		return nil
    28  	}
    29  	sval := int64(symbolMap[sym.Name] - uintptr(segment.dataBase))
    30  	if int(sym.Kind) == symkind.SBSS {
    31  		sval = sval - int64(segment.dataLen+segment.noptrdataLen)
    32  	}
    33  	if ptr, ok := symbolMap[typeName]; ok {
    34  		typ := (*_type)(adduintptr(ptr, 0))
    35  		nptr := int64(typ.ptrdata) / int64(linker.Arch.PtrSize)
    36  		if typ.kind&KindGCProg == 0 {
    37  			var mask []byte
    38  			append2Slice(&mask, uintptr(unsafe.Pointer(typ.gcdata)), int(nptr+7)/8)
    39  			for i := int64(0); i < nptr; i++ {
    40  				if (mask[i/8]>>uint(i%8))&1 != 0 {
    41  					w.Ptr(sval/int64(linker.Arch.PtrSize) + i)
    42  				}
    43  			}
    44  
    45  		} else {
    46  			var prog []byte
    47  			append2Slice(&prog, uintptr(unsafe.Pointer(typ.gcdata)), Uint32Size+int((*(*uint32)(unsafe.Pointer(typ.gcdata)))))
    48  			w.ZeroUntil(sval / int64(linker.Arch.PtrSize))
    49  			w.Append(prog[4:], nptr)
    50  		}
    51  	} else {
    52  		return fmt.Errorf("type:%s not found\n", typeName)
    53  	}
    54  	return nil
    55  }
    56  
    57  func sortSym(symMap map[string]*obj.Sym, kind int) []*obj.Sym {
    58  	syms := make(map[int]*obj.Sym)
    59  	keys := []int{}
    60  	for _, sym := range symMap {
    61  		if sym.Kind == kind {
    62  			syms[sym.Offset] = sym
    63  			keys = append(keys, sym.Offset)
    64  		}
    65  	}
    66  	sort.Ints(keys)
    67  	symbols := []*obj.Sym{}
    68  	for _, key := range keys {
    69  		symbols = append(symbols, syms[key])
    70  	}
    71  	return symbols
    72  }
    73  
    74  func (linker *Linker) addgcdata(codeModule *CodeModule, symbolMap map[string]uintptr) error {
    75  	module := codeModule.module
    76  	w := gcprog.Writer{}
    77  	w.Init(func(x byte) {
    78  		codeModule.gcdata = append(codeModule.gcdata, x)
    79  	})
    80  	for _, sym := range sortSym(linker.SymMap, symkind.SDATA) {
    81  		err := generategcdata(linker, codeModule, symbolMap, &w, sym)
    82  		if err != nil {
    83  			return err
    84  		}
    85  	}
    86  	w.ZeroUntil(int64(module.edata-module.data) / int64(linker.Arch.PtrSize))
    87  	w.End()
    88  	module.gcdata = (*sliceHeader)(unsafe.Pointer(&codeModule.gcdata)).Data
    89  	module.gcdatamask = progToPointerMask((*byte)(adduintptr(module.gcdata, 0)), module.edata-module.data)
    90  
    91  	w = gcprog.Writer{}
    92  	w.Init(func(x byte) {
    93  		codeModule.gcbss = append(codeModule.gcbss, x)
    94  	})
    95  
    96  	for _, sym := range sortSym(linker.SymMap, symkind.SBSS) {
    97  		err := generategcdata(linker, codeModule, symbolMap, &w, sym)
    98  		if err != nil {
    99  			return err
   100  		}
   101  	}
   102  	w.ZeroUntil(int64(module.ebss-module.bss) / int64(linker.Arch.PtrSize))
   103  	w.End()
   104  	module.gcbss = (*sliceHeader)(unsafe.Pointer(&codeModule.gcbss)).Data
   105  	module.gcbssmask = progToPointerMask((*byte)(adduintptr(module.gcbss, 0)), module.ebss-module.bss)
   106  	return nil
   107  }