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