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 }