github.com/eh-steve/goloader@v0.0.0-20240111193454-90ff3cfdae39/ld.go (about) 1 package goloader 2 3 import ( 4 "bytes" 5 "cmd/objfile/objabi" 6 "cmd/objfile/sys" 7 "encoding/binary" 8 "errors" 9 "fmt" 10 "os" 11 "reflect" 12 "runtime" 13 "sort" 14 "strings" 15 "sync" 16 "unsafe" 17 18 "github.com/eh-steve/goloader/obj" 19 "github.com/eh-steve/goloader/objabi/reloctype" 20 "github.com/eh-steve/goloader/objabi/symkind" 21 "github.com/eh-steve/goloader/stackobject" 22 ) 23 24 // ourself defined struct 25 // code segment 26 type segment struct { 27 codeByte []byte 28 dataByte []byte 29 codeBase int 30 dataBase int 31 sumDataLen int 32 dataLen int 33 noptrdataLen int 34 bssLen int 35 noptrbssLen int 36 codeLen int 37 maxCodeLength int 38 maxDataLength int 39 codeOff int 40 dataOff int 41 } 42 43 type Linker struct { 44 code []byte 45 data []byte 46 noptrdata []byte 47 bss []byte 48 noptrbss []byte 49 cuFiles []obj.CompilationUnitFiles 50 symMap map[string]*obj.Sym 51 objsymbolMap map[string]*obj.ObjSymbol 52 namemap map[string]int 53 fileNameMap map[string]int 54 cutab []uint32 55 filetab []byte 56 funcnametab []byte 57 functab []byte 58 pctab []byte 59 _func []*_func 60 initFuncs []string 61 symNameOrder []string 62 Arch *sys.Arch 63 options LinkerOptions 64 heapStringMap map[string]*string 65 appliedADRPRelocs map[*byte][]byte 66 appliedPCRelRelocs map[*byte][]byte 67 pkgNamesWithUnresolved map[string]struct{} 68 pkgNamesToForceRebuild map[string]struct{} 69 reachableTypes map[string]struct{} 70 reachableSymbols map[string]struct{} 71 pkgs []*obj.Pkg 72 pkgsByName map[string]*obj.Pkg 73 } 74 75 type CodeModule struct { 76 segment 77 SymbolsByPkg map[string]map[string]interface{} 78 Syms map[string]uintptr 79 module *moduledata 80 gcdata []byte 81 gcbss []byte 82 patchedTypeMethodsIfn map[*_type]map[int]struct{} 83 patchedTypeMethodsTfn map[*_type]map[int]struct{} 84 patchedTypeMethodsMtyp map[*_type]map[int]typeOff 85 deduplicatedTypes map[string]uintptr 86 heapStrings map[string]*string 87 } 88 89 var ( 90 modules = make(map[*CodeModule]bool) 91 modulesLock sync.Mutex 92 ) 93 94 // initialize Linker 95 func initLinker(opts []LinkerOptFunc) (*Linker, error) { 96 97 linker := &Linker{ 98 // Pad these tabs out so offsets don't start at 0, which is often used in runtime as a special value for "missing" 99 // e.g. runtime/traceback.go and runtime/symtab.go both contain checks like: 100 // if f.pcsp == 0 ... 101 // and 102 // if f.nameoff == 0 103 funcnametab: make([]byte, PtrSize), 104 pctab: make([]byte, PtrSize), 105 symMap: make(map[string]*obj.Sym), 106 objsymbolMap: make(map[string]*obj.ObjSymbol), 107 namemap: make(map[string]int), 108 fileNameMap: make(map[string]int), 109 heapStringMap: make(map[string]*string), 110 appliedADRPRelocs: make(map[*byte][]byte), 111 appliedPCRelRelocs: make(map[*byte][]byte), 112 pkgNamesWithUnresolved: make(map[string]struct{}), 113 pkgNamesToForceRebuild: make(map[string]struct{}), 114 reachableTypes: make(map[string]struct{}), 115 reachableSymbols: make(map[string]struct{}), 116 } 117 if os.Getenv("GOLOADER_FORCE_TEST_RELOCATION_EPILOGUES") == "1" { 118 opts = append(opts, WithForceTestRelocationEpilogues()) 119 } 120 linker.Opts(opts...) 121 122 head := make([]byte, unsafe.Sizeof(pcHeader{})) 123 copy(head, obj.ModuleHeadx86) 124 linker.functab = append(linker.functab, head...) 125 linker.functab[len(obj.ModuleHeadx86)-1] = PtrSize 126 return linker, nil 127 } 128 129 func (linker *Linker) Autolib() []string { 130 // Sort dependent packages into autolib order via depth first recursion 131 if len(linker.pkgs) == 0 { 132 return nil 133 } 134 seen := map[string]struct{}{} 135 var autolibsByPkg = map[string][]string{} 136 for _, pkg := range linker.pkgs { 137 autolibsByPkg[pkg.PkgPath] = pkg.AutoLib 138 } 139 // The last package is the main package, so start there 140 mainPkg := linker.pkgs[len(linker.pkgs)-1] 141 var autolibs []string 142 recurseAutolibs(autolibsByPkg, mainPkg.PkgPath, &autolibs, seen) 143 144 return autolibs 145 } 146 147 func recurseAutolibs(autolibsByPkg map[string][]string, targetPkg string, autolibs *[]string, seen map[string]struct{}) { 148 if _, ok := seen[targetPkg]; ok { 149 return 150 } 151 seen[targetPkg] = struct{}{} 152 for _, imported := range autolibsByPkg[targetPkg] { 153 recurseAutolibs(autolibsByPkg, imported, autolibs, seen) 154 newLibs := autolibsByPkg[imported] 155 for _, newLib := range newLibs { 156 if _, ok := seen[newLib]; !ok { 157 *autolibs = append(*autolibs, newLib) 158 } 159 } 160 } 161 *autolibs = append(*autolibs, targetPkg) 162 } 163 164 func (linker *Linker) Opts(linkerOpts ...LinkerOptFunc) { 165 for _, opt := range linkerOpts { 166 opt(&linker.options) 167 } 168 } 169 170 func (linker *Linker) addSymbols(symbolNames []string, globalSymPtr map[string]uintptr) error { 171 // static_tmp is 0, golang compile not allocate memory. 172 linker.noptrdata = append(linker.noptrdata, make([]byte, IntSize)...) 173 174 for _, cuFileSet := range linker.cuFiles { 175 for _, fileName := range cuFileSet.Files { 176 if offset, ok := linker.fileNameMap[fileName]; !ok { 177 linker.cutab = append(linker.cutab, (uint32)(len(linker.filetab))) 178 linker.fileNameMap[fileName] = len(linker.filetab) 179 fileName = expandGoroot(strings.TrimPrefix(fileName, FileSymPrefix)) 180 linker.filetab = append(linker.filetab, []byte(fileName)...) 181 linker.filetab = append(linker.filetab, ZeroByte) 182 } else { 183 linker.cutab = append(linker.cutab, uint32(offset)) 184 } 185 } 186 } 187 188 for _, objSymName := range symbolNames { 189 if _, ok := linker.symMap[objSymName]; ok { 190 continue 191 } 192 if !linker.isSymbolReachable(objSymName) { 193 continue 194 } 195 196 objSym := linker.objsymbolMap[objSymName] 197 if objSym == nil { 198 // Might have been added as an ABI wrapper without the actual implementation 199 objSym = linker.objsymbolMap[objSymName+obj.ABI0Suffix] 200 if objSym != nil { 201 panic("missing a symbol " + objSymName + " but found its ABI0 wrapper") 202 } else { 203 objSym = linker.objsymbolMap[objSymName+obj.ABIInternalSuffix] 204 if objSym != nil { 205 panic("missing a symbol " + objSymName + " but found its ABIInternal wrapper") 206 } 207 } 208 } 209 if objSym.Kind == symkind.STEXT && objSym.DupOK == false { 210 _, err := linker.addSymbol(objSym.Name, globalSymPtr) 211 if err != nil { 212 return err 213 } 214 } else if objSym.Kind == symkind.STEXT && objSym.DupOK { 215 // This might be an asm func ABIWRAPPER. Check if one of its relocs points to itself 216 // (the abi0 version of itself, without the .abiinternal suffix) 217 isAsmWrapper := false 218 219 if objSym.Func != nil && objSym.Func.FuncID == uint8(obj.FuncIDWrapper) { 220 for _, reloc := range objSym.Reloc { 221 if reloc.Sym.Name+obj.ABIInternalSuffix == objSym.Name { 222 // Relocation pointing at itself (the ABI0 ASM version) 223 isAsmWrapper = true 224 } 225 } 226 } 227 if isAsmWrapper { 228 // This wrapper's symbol has a suffix of .abiinternal to distinguish it from the abi0 ASM func 229 _, err := linker.addSymbol(objSym.Name, globalSymPtr) 230 if err != nil { 231 return err 232 } 233 } 234 } 235 switch objSym.Kind { 236 case symkind.SNOPTRDATA, symkind.SRODATA, symkind.SDATA, symkind.SBSS, symkind.SNOPTRBSS: 237 _, err := linker.addSymbol(objSym.Name, globalSymPtr) 238 if err != nil { 239 return err 240 } 241 } 242 } 243 for _, sym := range linker.symMap { 244 offset := 0 245 switch sym.Kind { 246 case symkind.SNOPTRDATA, symkind.SRODATA: 247 if strings.HasPrefix(sym.Name, TypeStringPrefix) { 248 // nothing todo 249 } else { 250 offset += len(linker.data) 251 } 252 case symkind.SBSS: 253 offset += len(linker.data) + len(linker.noptrdata) 254 case symkind.SNOPTRBSS: 255 offset += len(linker.data) + len(linker.noptrdata) + len(linker.bss) 256 } 257 sym.Offset += offset 258 if offset != 0 { 259 for index := range sym.Reloc { 260 sym.Reloc[index].Offset += offset 261 if sym.Reloc[index].EpilogueOffset > 0 { 262 sym.Reloc[index].EpilogueOffset += offset 263 } 264 } 265 } 266 } 267 linker.symNameOrder = symbolNames 268 return nil 269 } 270 271 func (linker *Linker) SymbolOrder() []string { 272 return linker.symNameOrder 273 } 274 275 func (linker *Linker) addSymbol(name string, globalSymPtr map[string]uintptr) (symbol *obj.Sym, err error) { 276 if symbol, ok := linker.symMap[name]; ok { 277 return symbol, nil 278 } 279 objsym := linker.objsymbolMap[name] 280 symbol = &obj.Sym{Name: objsym.Name, Kind: objsym.Kind, Pkg: objsym.Pkg} 281 linker.symMap[symbol.Name] = symbol 282 283 switch symbol.Kind { 284 case symkind.STEXT: 285 symbol.Offset = len(linker.code) 286 linker.code = append(linker.code, objsym.Data...) 287 bytearrayAlignNops(linker.Arch, &linker.code, PtrSize) 288 for i, reloc := range objsym.Reloc { 289 // Pessimistically pad the function text with extra bytes for any relocations which might add extra 290 // instructions at the end in the case of a 32 bit overflow. These epilogue PCs need to be added to 291 // the PCData, PCLine, PCFile, PCSP etc in case of pre-emption or stack unwinding while the PC is running these hacked instructions. 292 // We find the relevant PCValues for the offset of the reloc, and reuse the values for the reloc's epilogue 293 294 if linker.options.NoRelocationEpilogues && !strings.HasPrefix(reloc.Sym.Name, TypeStringPrefix) { 295 continue 296 } 297 switch reloc.Type { 298 case reloctype.R_ADDRARM64: 299 objsym.Reloc[i].EpilogueOffset = len(linker.code) - symbol.Offset 300 objsym.Reloc[i].EpilogueSize = maxExtraInstructionBytesADRP 301 linker.code = append(linker.code, createArchNops(linker.Arch, maxExtraInstructionBytesADRP)...) 302 case reloctype.R_ARM64_PCREL_LDST8, reloctype.R_ARM64_PCREL_LDST16, reloctype.R_ARM64_PCREL_LDST32, reloctype.R_ARM64_PCREL_LDST64: 303 objsym.Reloc[i].EpilogueOffset = len(linker.code) - symbol.Offset 304 objsym.Reloc[i].EpilogueSize = maxExtraInstructionBytesADRPLDST 305 linker.code = append(linker.code, createArchNops(linker.Arch, maxExtraInstructionBytesADRPLDST)...) 306 case reloctype.R_CALLARM64, reloctype.R_CALLARM64 | reloctype.R_WEAK: 307 objsym.Reloc[i].EpilogueOffset = alignof(len(linker.code)-symbol.Offset, PtrSize) 308 objsym.Reloc[i].EpilogueSize = maxExtraInstructionBytesCALLARM64 309 alignment := alignof(len(linker.code)-symbol.Offset, PtrSize) - (len(linker.code) - symbol.Offset) 310 linker.code = append(linker.code, createArchNops(linker.Arch, maxExtraInstructionBytesCALLARM64+alignment)...) 311 case reloctype.R_PCREL: 312 objsym.Reloc[i].EpilogueOffset = len(linker.code) - symbol.Offset 313 var epilogueSize int 314 offset := reloc.Offset 315 if reloc.Offset == 1 { 316 // This might happen if a CGo E9 JMP is right at the beginning of a function, so we want to avoid slicing before the start of the text 317 offset += 1 318 } 319 instructionBytes := objsym.Data[offset-2 : reloc.Offset+reloc.Size] 320 opcode := instructionBytes[0] 321 switch opcode { 322 case x86amd64LEAcode: 323 epilogueSize = maxExtraInstructionBytesPCRELxLEAQ 324 case x86amd64MOVcode: 325 epilogueSize = maxExtraInstructionBytesPCRELxMOVNear 326 case x86amd64CMPLcode: 327 epilogueSize = maxExtraInstructionBytesPCRELxCMPLNear 328 case x86amd64JMPcode: 329 epilogueSize = maxExtraInstructionBytesPCRELxJMP 330 case x86amd64CALL2code: // CGo FF 15 PCREL call 331 if instructionBytes[1] == 0x15 { 332 epilogueSize = maxExtraInstructionBytesPCRELxCALL2 333 break 334 } 335 fallthrough // Might be FF XX E8/E9 ... 336 default: 337 switch instructionBytes[1] { 338 case x86amd64CALLcode: 339 opcode = x86amd64CALLcode 340 epilogueSize = maxExtraInstructionBytesCALLNear 341 case x86amd64JMPcode: 342 epilogueSize = maxExtraInstructionBytesPCRELxJMP 343 } 344 } 345 returnOffset := (reloc.Offset + reloc.Size) - (objsym.Reloc[i].EpilogueOffset + epilogueSize) - len(x86amd64JMPShortCode) // assumes short jump, adjusts if not 346 shortJmp := returnOffset < 0 && returnOffset > -0x80 347 switch opcode { 348 case x86amd64MOVcode: 349 if shortJmp { 350 epilogueSize = maxExtraInstructionBytesPCRELxMOVShort 351 } 352 case x86amd64CMPLcode: 353 if shortJmp { 354 epilogueSize = maxExtraInstructionBytesPCRELxCMPLShort 355 } 356 case x86amd64CALLcode: 357 if shortJmp { 358 epilogueSize = maxExtraInstructionBytesCALLShort 359 } 360 } 361 objsym.Reloc[i].EpilogueSize = epilogueSize 362 linker.code = append(linker.code, createArchNops(linker.Arch, epilogueSize)...) 363 case reloctype.R_GOTPCREL, reloctype.R_TLS_IE: 364 objsym.Reloc[i].EpilogueOffset = len(linker.code) - symbol.Offset 365 objsym.Reloc[i].EpilogueSize = maxExtraInstructionBytesGOTPCREL 366 linker.code = append(linker.code, createArchNops(linker.Arch, objsym.Reloc[i].EpilogueSize)...) 367 case reloctype.R_ARM64_GOTPCREL, reloctype.R_ARM64_TLS_IE: 368 objsym.Reloc[i].EpilogueOffset = alignof(len(linker.code)-symbol.Offset, PtrSize) 369 objsym.Reloc[i].EpilogueSize = maxExtraInstructionBytesARM64GOTPCREL 370 // need to be able to pad to align to multiple of 8 371 alignment := alignof(len(linker.code)-symbol.Offset, PtrSize) - (len(linker.code) - symbol.Offset) 372 linker.code = append(linker.code, createArchNops(linker.Arch, objsym.Reloc[i].EpilogueSize+alignment)...) 373 case reloctype.R_CALL, reloctype.R_CALL | reloctype.R_WEAK: 374 epilogueSize := maxExtraInstructionBytesCALLNear 375 returnOffset := (reloc.Offset + reloc.Size) - (objsym.Reloc[i].EpilogueOffset + epilogueSize) - len(x86amd64JMPShortCode) // assumes short jump, adjusts if not 376 shortJmp := returnOffset < 0 && returnOffset > -0x80 377 objsym.Reloc[i].EpilogueOffset = len(linker.code) - symbol.Offset 378 if shortJmp { 379 epilogueSize = maxExtraInstructionBytesCALLShort 380 } 381 objsym.Reloc[i].EpilogueSize = epilogueSize 382 linker.code = append(linker.code, createArchNops(linker.Arch, epilogueSize)...) 383 } 384 bytearrayAlignNops(linker.Arch, &linker.code, PtrSize) 385 } 386 387 symbol.Func = &obj.Func{} 388 if err := linker.readFuncData(linker.objsymbolMap[name], symbol.Offset); err != nil { 389 return nil, err 390 } 391 case symkind.SDATA: 392 symbol.Offset = len(linker.data) 393 linker.data = append(linker.data, objsym.Data...) 394 bytearrayAlign(&linker.data, PtrSize) 395 case symkind.SNOPTRDATA, symkind.SRODATA: 396 // because golang string assignment is pointer assignment, so store go.string constants 397 // in a separate segment and not unload when module unload. 398 if strings.HasPrefix(symbol.Name, TypeStringPrefix) { 399 data := make([]byte, len(objsym.Data)) 400 copy(data, objsym.Data) 401 stringVal := string(data) 402 linker.heapStringMap[symbol.Name] = &stringVal 403 } else { 404 symbol.Offset = len(linker.noptrdata) 405 linker.noptrdata = append(linker.noptrdata, objsym.Data...) 406 bytearrayAlign(&linker.noptrdata, PtrSize) 407 } 408 case symkind.SBSS: 409 symbol.Offset = len(linker.bss) 410 linker.bss = append(linker.bss, objsym.Data...) 411 bytearrayAlign(&linker.bss, PtrSize) 412 case symkind.SNOPTRBSS: 413 symbol.Offset = len(linker.noptrbss) 414 linker.noptrbss = append(linker.noptrbss, objsym.Data...) 415 bytearrayAlign(&linker.noptrbss, PtrSize) 416 case symkind.STLSBSS: 417 // Nothing to do, since runtime.tls_g should be resolved from the host binary 418 default: 419 return nil, fmt.Errorf("invalid symbol:%s kind:%d", symbol.Name, symbol.Kind) 420 } 421 422 if symbol.Kind == symkind.STEXT { 423 symbol.Size = len(linker.code) - symbol.Offset // includes epilogue 424 } else { 425 symbol.Size = int(objsym.Size) 426 } 427 for _, loc := range objsym.Reloc { 428 reloc := loc 429 reloc.Offset = reloc.Offset + symbol.Offset 430 reloc.EpilogueOffset = reloc.EpilogueOffset + symbol.Offset 431 if _, ok := linker.objsymbolMap[reloc.Sym.Name]; ok { 432 reloc.Sym, err = linker.addSymbol(reloc.Sym.Name, globalSymPtr) 433 if err != nil { 434 return nil, err 435 } 436 if len(linker.objsymbolMap[reloc.Sym.Name].Data) == 0 && reloc.Size > 0 { 437 // static_tmp is 0, golang compile not allocate memory. 438 // goloader add IntSize bytes on linker.noptrdata[0] 439 if reloc.Size <= IntSize { 440 reloc.Sym.Offset = 0 441 } else { 442 return nil, fmt.Errorf("Symbol: %s size: %d > IntSize: %d\n", reloc.Sym.Name, reloc.Size, IntSize) 443 } 444 } 445 } else { 446 if reloc.Type == reloctype.R_TLS_LE || reloc.Type == reloctype.R_TLS_IE { 447 reloc.Sym.Name = TLSNAME 448 reloc.Sym.Offset = loc.Offset 449 } 450 if reloc.Type == reloctype.R_CALLIND { 451 reloc.Sym.Offset = 0 452 } 453 _, exist := linker.symMap[reloc.Sym.Name] 454 if strings.HasPrefix(reloc.Sym.Name, TypeImportPathPrefix) { 455 if exist { 456 reloc.Sym = linker.symMap[reloc.Sym.Name] 457 } else { 458 path := strings.Trim(strings.TrimPrefix(reloc.Sym.Name, TypeImportPathPrefix), ".") 459 reloc.Sym.Kind = symkind.SNOPTRDATA 460 reloc.Sym.Offset = len(linker.noptrdata) 461 // name memory layout 462 // name { tagLen(byte), len(uint16), str*} 463 nameLen := []byte{0, 0, 0} 464 binary.PutUvarint(nameLen[1:], uint64(len(path))) 465 linker.noptrdata = append(linker.noptrdata, nameLen...) 466 linker.noptrdata = append(linker.noptrdata, path...) 467 linker.noptrdata = append(linker.noptrdata, ZeroByte) 468 bytearrayAlign(&linker.noptrdata, PtrSize) 469 } 470 } 471 if ispreprocesssymbol(reloc.Sym.Name) { 472 bytes := make([]byte, UInt64Size) 473 if err := preprocesssymbol(linker.Arch.ByteOrder, reloc.Sym.Name, bytes); err != nil { 474 return nil, err 475 } else { 476 if exist { 477 reloc.Sym = linker.symMap[reloc.Sym.Name] 478 } else { 479 reloc.Sym.Kind = symkind.SNOPTRDATA 480 reloc.Sym.Offset = len(linker.noptrdata) 481 linker.noptrdata = append(linker.noptrdata, bytes...) 482 bytearrayAlign(&linker.noptrdata, PtrSize) 483 } 484 } 485 } 486 if !exist { 487 // golang1.8, some function generates more than one (MOVQ (TLS), CX) 488 // so when same name symbol in linker.symMap, do not update it 489 if reloc.Sym.Name != "" { 490 linker.symMap[reloc.Sym.Name] = reloc.Sym 491 } 492 } 493 } 494 symbol.Reloc = append(symbol.Reloc, reloc) 495 } 496 497 if objsym.Type != EmptyString { 498 if _, ok := linker.symMap[objsym.Type]; !ok { 499 if _, ok := linker.objsymbolMap[objsym.Type]; !ok { 500 linker.symMap[objsym.Type] = &obj.Sym{Name: objsym.Type, Offset: InvalidOffset, Pkg: objsym.Pkg} 501 } 502 } 503 } 504 return symbol, nil 505 } 506 507 func (linker *Linker) readFuncData(symbol *obj.ObjSymbol, codeLen int) (err error) { 508 nameOff := len(linker.funcnametab) 509 if offset, ok := linker.namemap[symbol.Name]; !ok { 510 linker.namemap[symbol.Name] = len(linker.funcnametab) 511 linker.funcnametab = append(linker.funcnametab, []byte(symbol.Name)...) 512 linker.funcnametab = append(linker.funcnametab, ZeroByte) 513 } else { 514 nameOff = offset 515 } 516 517 for _, reloc := range symbol.Reloc { 518 if reloc.EpilogueOffset > 0 { 519 if len(symbol.Func.PCSP) > 0 { 520 linker.patchPCValuesForReloc(&symbol.Func.PCSP, reloc.Offset, reloc.EpilogueOffset, reloc.EpilogueSize) 521 } 522 if len(symbol.Func.PCFile) > 0 { 523 linker.patchPCValuesForReloc(&symbol.Func.PCFile, reloc.Offset, reloc.EpilogueOffset, reloc.EpilogueSize) 524 } 525 if len(symbol.Func.PCLine) > 0 { 526 linker.patchPCValuesForReloc(&symbol.Func.PCLine, reloc.Offset, reloc.EpilogueOffset, reloc.EpilogueSize) 527 } 528 for i, pcdata := range symbol.Func.PCData { 529 if len(pcdata) > 0 { 530 linker.patchPCValuesForReloc(&symbol.Func.PCData[i], reloc.Offset, reloc.EpilogueOffset, reloc.EpilogueSize) 531 } 532 } 533 } 534 } 535 pcspOff := len(linker.pctab) 536 linker.pctab = append(linker.pctab, symbol.Func.PCSP...) 537 538 pcfileOff := len(linker.pctab) 539 linker.pctab = append(linker.pctab, symbol.Func.PCFile...) 540 541 pclnOff := len(linker.pctab) 542 linker.pctab = append(linker.pctab, symbol.Func.PCLine...) 543 544 _func := initfunc(symbol, nameOff, pcspOff, pcfileOff, pclnOff, symbol.Func.CUOffset) 545 linker._func = append(linker._func, &_func) 546 Func := linker.symMap[symbol.Name].Func 547 for _, pcdata := range symbol.Func.PCData { 548 if len(pcdata) == 0 { 549 Func.PCData = append(Func.PCData, 0) 550 } else { 551 Func.PCData = append(Func.PCData, uint32(len(linker.pctab))) 552 linker.pctab = append(linker.pctab, pcdata...) 553 } 554 } 555 556 for _, name := range symbol.Func.FuncData { 557 if name == EmptyString { 558 Func.FuncData = append(Func.FuncData, (uintptr)(0)) 559 } else { 560 if _, ok := linker.symMap[name]; !ok { 561 if _, ok := linker.objsymbolMap[name]; ok { 562 if _, err = linker.addSymbol(name, nil); err != nil { 563 return err 564 } 565 } else { 566 return errors.New("unknown gcobj:" + name) 567 } 568 } 569 if sym, ok := linker.symMap[name]; ok { 570 Func.FuncData = append(Func.FuncData, (uintptr)(sym.Offset)) 571 } else { 572 Func.FuncData = append(Func.FuncData, (uintptr)(0)) 573 } 574 } 575 } 576 577 if err = linker.addInlineTree(&_func, symbol); err != nil { 578 return err 579 } 580 581 grow(&linker.pctab, alignof(len(linker.pctab), PtrSize)) 582 return 583 } 584 585 func (linker *Linker) addSymbolMap(symPtr map[string]uintptr, codeModule *CodeModule) (symbolMap map[string]uintptr, err error) { 586 symbolMap = make(map[string]uintptr) 587 segment := &codeModule.segment 588 for name, sym := range linker.symMap { 589 if !linker.isSymbolReachable(name) { 590 continue 591 } 592 if sym.Offset == InvalidOffset { 593 if ptr, ok := symPtr[sym.Name]; ok { 594 symbolMap[name] = ptr 595 // Mark the symbol as a duplicate 596 symbolMap[FirstModulePrefix+name] = ptr 597 } else { 598 symbolMap[name] = InvalidHandleValue 599 return nil, fmt.Errorf("unresolved external symbol: %s", sym.Name) 600 } 601 } else if sym.Name == TLSNAME { 602 // nothing todo 603 } else if sym.Kind == symkind.STEXT { 604 symbolMap[name] = uintptr(linker.symMap[name].Offset + segment.codeBase) 605 codeModule.Syms[sym.Name] = symbolMap[name] 606 if _, ok := symPtr[name]; ok { 607 // Mark the symbol as a duplicate, and store the original entrypoint 608 symbolMap[FirstModulePrefix+name] = symPtr[name] 609 } 610 } else if strings.HasPrefix(sym.Name, ItabPrefix) { 611 if ptr, ok := symPtr[sym.Name]; ok { 612 symbolMap[name] = ptr 613 symbolMap[FirstModulePrefix+name] = ptr 614 } 615 } else { 616 if _, ok := symPtr[name]; !ok { 617 if strings.HasPrefix(name, TypeStringPrefix) { 618 strPtr := linker.heapStringMap[name] 619 if strPtr == nil { 620 return nil, fmt.Errorf("impossible! got a nil string for symbol %s", name) 621 } 622 if len(*strPtr) == 0 { 623 // Any address will do, the length is 0, so it should never be read 624 symbolMap[name] = uintptr(unsafe.Pointer(linker)) 625 } else { 626 x := (*reflect.StringHeader)(unsafe.Pointer(strPtr)) 627 symbolMap[name] = x.Data 628 } 629 } else { 630 symbolMap[name] = uintptr(linker.symMap[name].Offset + segment.dataBase) 631 if strings.HasSuffix(sym.Name, "·f") { 632 codeModule.Syms[sym.Name] = symbolMap[name] 633 } 634 if strings.HasPrefix(name, TypePrefix) { 635 if variant, ok := symbolIsVariant(name); ok && symPtr[variant] != 0 { 636 symbolMap[FirstModulePrefix+name] = symPtr[variant] 637 } 638 } 639 } 640 } else { 641 if strings.HasPrefix(name, MainPkgPrefix) || strings.HasPrefix(name, TypePrefix) { 642 symbolMap[name] = uintptr(linker.symMap[name].Offset + segment.dataBase) 643 // Record the presence of a duplicate symbol by adding a prefix 644 symbolMap[FirstModulePrefix+name] = symPtr[name] 645 } else { 646 shouldSkipDedup := false 647 for _, pkgPath := range linker.options.SkipTypeDeduplicationForPackages { 648 if strings.HasPrefix(name, pkgPath) { 649 shouldSkipDedup = true 650 } 651 } 652 if shouldSkipDedup { 653 // Use the new version of the symbol 654 symbolMap[name] = uintptr(linker.symMap[name].Offset + segment.dataBase) 655 } else { 656 symbolMap[name] = symPtr[name] 657 // Mark the symbol as a duplicate 658 symbolMap[FirstModulePrefix+name] = symPtr[name] 659 } 660 } 661 } 662 } 663 } 664 if tlsG, ok := symPtr[TLSNAME]; ok { 665 symbolMap[TLSNAME] = tlsG 666 } 667 codeModule.heapStrings = linker.heapStringMap 668 return symbolMap, err 669 } 670 671 func (linker *Linker) addFuncTab(module *moduledata, _func *_func, symbolMap map[string]uintptr) (err error) { 672 funcname := gostringnocopy(&linker.funcnametab[_func.nameoff]) 673 setfuncentry(_func, symbolMap[funcname], module.text) 674 Func := linker.symMap[funcname].Func 675 676 if err = stackobject.AddStackObject(funcname, linker.symMap, symbolMap, module.noptrdata); err != nil { 677 return err 678 } 679 if err = linker.addDeferReturn(_func); err != nil { 680 return err 681 } 682 683 append2Slice(&module.pclntable, uintptr(unsafe.Pointer(_func)), _FuncSize) 684 685 if _func.npcdata > 0 { 686 append2Slice(&module.pclntable, uintptr(unsafe.Pointer(&(Func.PCData[0]))), Uint32Size*int(_func.npcdata)) 687 } 688 689 if _func.nfuncdata > 0 { 690 addfuncdata(module, Func, _func) 691 } 692 693 return err 694 } 695 696 func readPCData(p []byte, startPC uintptr) (pcs []uintptr, vals []int32) { 697 pc := startPC 698 val := int32(-1) 699 if len(p) == 0 { 700 return nil, nil 701 } 702 for { 703 var ok bool 704 p, ok = step(p, &pc, &val, pc == startPC) 705 if !ok { 706 break 707 } 708 pcs = append(pcs, pc) 709 vals = append(vals, val) 710 if len(p) == 0 { 711 break 712 } 713 } 714 return 715 } 716 717 func formatPCData(p []byte, startPC uintptr) string { 718 pcs, vals := readPCData(p, startPC) 719 var result string 720 if len(pcs) == 0 { 721 return "()" 722 } 723 prevPC := startPC 724 for i := range pcs { 725 result += fmt.Sprintf("(%d-%d => %d), ", prevPC, pcs[i], vals[i]) 726 prevPC = startPC + pcs[i] 727 } 728 return result 729 } 730 731 func pcValue(p []byte, targetOffset uintptr) (int32, uintptr) { 732 startPC := uintptr(0) 733 pc := uintptr(0) 734 val := int32(-1) 735 if len(p) == 0 { 736 return -1, 1<<64 - 1 737 } 738 prevpc := pc 739 for { 740 var ok bool 741 p, ok = step(p, &pc, &val, pc == startPC) 742 if !ok { 743 break 744 } 745 if len(p) == 0 { 746 break 747 } 748 if targetOffset < pc { 749 return val, prevpc 750 } 751 prevpc = pc 752 } 753 return -1, 1<<64 - 1 754 } 755 756 func (linker *Linker) patchPCValuesForReloc(pcvalues *[]byte, relocOffet int, epilogueOffset int, epilogueSize int) { 757 // Use the pcvalue at the offset of the reloc for the entire of that reloc's epilogue. 758 // This ensures that if the code is pre-empted or the stack unwound while we're inside the epilogue, the runtime behaves correctly 759 760 var pcQuantum uintptr = 1 761 if linker.Arch.Family == sys.ARM64 { 762 pcQuantum = 4 763 } 764 p := *pcvalues 765 if len(p) == 0 { 766 panic("trying to patch a zero sized pcvalue table. This shouldn't be possible...") 767 } 768 valAtRelocSite, startPC := pcValue(p, uintptr(relocOffet)) 769 if startPC == 1<<64-1 && valAtRelocSite == -1 { 770 panic(fmt.Sprintf("couldn't interpret pcvalue data when trying to patch it... relocOffset: %d, pcdata: %v\n %s", relocOffet, p, formatPCData(p, 0))) 771 } 772 if p[len(p)-1] != 0 { 773 panic(fmt.Sprintf("got a pcvalue table with an unexpected ending (%d)...\n%s ", p[len(p)-1], formatPCData(p, 0))) 774 } 775 p = p[:len(p)-1] // Remove the terminating 0 776 777 // Table is (value, PC), (value, PC), (value, PC)... etc 778 // Each value is delta encoded (signed) relative to the last, and each PC is delta encoded (unsigned) 779 780 pcs, vals := readPCData(p, 0) 781 lastValue := vals[len(vals)-1] 782 lastPC := pcs[len(pcs)-1] 783 if lastValue == valAtRelocSite { 784 // Extend the lastPC delta to absorb our epilogue, keep the value the same 785 var pcDelta uintptr 786 if len(pcs) > 1 { 787 pcDelta = (lastPC - pcs[len(pcs)-2]) / pcQuantum 788 } else { 789 pcDelta = lastPC / pcQuantum 790 } 791 792 buf := make([]byte, 10) 793 n := binary.PutUvarint(buf, uint64(pcDelta)) 794 buf = buf[:n] 795 index := bytes.LastIndex(p, buf) 796 if index == -1 { 797 panic(fmt.Sprintf("could not find varint PC delta of %d (%v)", pcDelta, buf)) 798 } 799 p = p[:index] 800 if len(pcs) > 1 { 801 pcDelta = (uintptr(epilogueOffset+epilogueSize) - pcs[len(pcs)-2]) / pcQuantum 802 } else { 803 pcDelta = (uintptr(epilogueOffset + epilogueSize)) / pcQuantum 804 } 805 806 buf = make([]byte, 10) 807 n = binary.PutUvarint(buf, uint64(pcDelta)) 808 p = append(p, buf[:n]...) 809 } else { 810 // Append a new (value, PC) pair 811 pcDelta := (epilogueOffset + epilogueSize - int(lastPC)) / int(pcQuantum) 812 if pcDelta < 0 { 813 panic(fmt.Sprintf("somehow the epilogue is not at the end?? lastPC %d, epilogue offset %d", lastPC, epilogueOffset)) 814 } 815 valDelta := valAtRelocSite - lastValue 816 817 buf := make([]byte, 10) 818 n := binary.PutVarint(buf, int64(valDelta)) 819 p = append(p, buf[:n]...) 820 821 n = binary.PutUvarint(buf, uint64(pcDelta)) 822 p = append(p, buf[:n]...) 823 } 824 825 // Re-add the terminating 0 we stripped off 826 p = append(p, 0) 827 828 *pcvalues = p 829 } 830 831 func (linker *Linker) buildModule(codeModule *CodeModule, symbolMap map[string]uintptr) (err error) { 832 segment := &codeModule.segment 833 module := codeModule.module 834 module.pclntable = append(module.pclntable, linker.functab...) 835 module.minpc = uintptr(segment.codeBase) 836 module.maxpc = uintptr(segment.codeBase + segment.codeOff) 837 module.text = uintptr(segment.codeBase) 838 module.etext = module.maxpc 839 module.data = uintptr(segment.dataBase) 840 module.edata = uintptr(segment.dataBase) + uintptr(segment.dataLen) 841 module.noptrdata = module.edata 842 module.enoptrdata = module.noptrdata + uintptr(segment.noptrdataLen) 843 module.bss = module.enoptrdata 844 module.ebss = module.bss + uintptr(segment.bssLen) 845 module.noptrbss = module.ebss 846 module.enoptrbss = module.noptrbss + uintptr(segment.noptrbssLen) 847 module.end = module.enoptrbss 848 module.types = module.data 849 module.etypes = module.enoptrbss 850 851 module.ftab = append(module.ftab, initfunctab(module.minpc, uintptr(len(module.pclntable)), module.text)) 852 for index, _func := range linker._func { 853 funcname := gostringnocopy(&linker.funcnametab[_func.nameoff]) 854 module.ftab = append(module.ftab, initfunctab(symbolMap[funcname], uintptr(len(module.pclntable)), module.text)) 855 if err = linker.addFuncTab(module, linker._func[index], symbolMap); err != nil { 856 return err 857 } 858 } 859 module.ftab = append(module.ftab, initfunctab(module.maxpc, uintptr(len(module.pclntable)), module.text)) 860 861 // see:^src/cmd/link/internal/ld/pcln.go findfunctab 862 funcbucket := []findfuncbucket{} 863 for k := 0; k < len(linker._func); k++ { 864 lEntry := int(getfuncentry(linker._func[k], module.text) - module.text) 865 lb := lEntry / pcbucketsize 866 li := lEntry % pcbucketsize / (pcbucketsize / nsub) 867 868 entry := int(module.maxpc - module.text) 869 if k < len(linker._func)-1 { 870 entry = int(getfuncentry(linker._func[k+1], module.text) - module.text) 871 } 872 b := entry / pcbucketsize 873 i := entry % pcbucketsize / (pcbucketsize / nsub) 874 875 for m := b - len(funcbucket); m >= 0; m-- { 876 funcbucket = append(funcbucket, findfuncbucket{idx: uint32(k)}) 877 } 878 if lb < b { 879 i = nsub - 1 880 } 881 for n := li + 1; n <= i; n++ { 882 if funcbucket[lb].subbuckets[n] == 0 { 883 funcbucket[lb].subbuckets[n] = byte(k - int(funcbucket[lb].idx)) 884 } 885 } 886 } 887 length := len(funcbucket) * FindFuncBucketSize 888 append2Slice(&module.pclntable, uintptr(unsafe.Pointer(&funcbucket[0])), length) 889 module.findfunctab = (uintptr)(unsafe.Pointer(&module.pclntable[len(module.pclntable)-length])) 890 891 if err = linker.addgcdata(codeModule, symbolMap); err != nil { 892 return err 893 } 894 for name, addr := range symbolMap { 895 if strings.HasPrefix(name, TypePrefix) && 896 !strings.HasPrefix(name, TypeDoubleDotPrefix) && 897 addr >= module.types && addr < module.etypes { 898 module.typelinks = append(module.typelinks, int32(addr-module.types)) 899 module.typemap[typeOff(addr-module.types)] = (*_type)(unsafe.Pointer(addr)) 900 } 901 } 902 initmodule(codeModule.module, linker) 903 904 modulesLock.Lock() 905 addModule(codeModule) 906 modulesLock.Unlock() 907 additabs(codeModule.module) 908 moduledataverify1(codeModule.module) 909 modulesinit() 910 typelinksinit() // Deduplicate typelinks across all modules 911 return err 912 } 913 914 func (linker *Linker) deduplicateTypeDescriptors(codeModule *CodeModule, symbolMap map[string]uintptr) (err error) { 915 // Having called addModule and runtime.modulesinit(), we can now safely use typesEqual() 916 // (which depended on the module being in the linked list for safe name resolution of types). 917 // This means we can now deduplicate type descriptors in the actual code 918 // by relocating their addresses to the equivalent *_type in the main module 919 920 // We need to deduplicate type symbols with the main module according to type hash, since type assertion 921 // uses *_type pointer equality and many overlapping or builtin types may be included twice 922 // We have to do this after adding the module to the linked list since deduplication 923 // depends on symbol resolution across all modules 924 typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks)) 925 buildModuleTypeHash(activeModules()[0], typehash) 926 927 patchedTypeMethodsIfn := make(map[*_type]map[int]struct{}) 928 patchedTypeMethodsTfn := make(map[*_type]map[int]struct{}) 929 patchedTypeMethodsMtyp := make(map[*_type]map[int]typeOff) 930 segment := &codeModule.segment 931 byteorder := linker.Arch.ByteOrder 932 dedupedTypes := map[string]uintptr{} 933 for _, symbol := range linker.symMap { 934 if linker.options.DumpTextBeforeAndAfterRelocs && linker.options.RelocationDebugWriter != nil && symbol.Kind == symkind.STEXT && symbol.Offset >= 0 { 935 _, _ = fmt.Fprintf(linker.options.RelocationDebugWriter, "BEFORE DEDUPE (%x - %x) %142s: %x\n", codeModule.codeBase+symbol.Offset, codeModule.codeBase+symbol.Offset+symbol.Size, symbol.Name, codeModule.codeByte[symbol.Offset:symbol.Offset+symbol.Size]) 936 } 937 relocLoop: 938 for _, loc := range symbol.Reloc { 939 addr := symbolMap[loc.Sym.Name] 940 sym := loc.Sym 941 relocByte := segment.dataByte 942 addrBase := segment.dataBase 943 if symbol.Kind == symkind.STEXT { 944 addrBase = segment.codeBase 945 relocByte = segment.codeByte 946 } 947 if addr != InvalidHandleValue && sym.Kind == symkind.SRODATA && 948 strings.HasPrefix(sym.Name, TypePrefix) && 949 !strings.HasPrefix(sym.Name, TypeDoubleDotPrefix) && sym.Offset != -1 { 950 951 // if this is pointing to a type descriptor at an offset inside this binary, we should deduplicate it against 952 // already known types from other modules to allow fast type assertion using *_type pointer equality 953 t := (*_type)(unsafe.Pointer(addr)) 954 prevT := (*_type)(unsafe.Pointer(addr)) 955 for _, candidate := range typehash[t.hash] { 956 seen := map[_typePair]struct{}{} 957 if typesEqual(t, candidate, seen) { 958 t = candidate 959 break 960 } 961 } 962 963 // Only relocate code if the type is a duplicate 964 if t != prevT { 965 _, isVariant := symbolIsVariant(loc.Sym.Name) 966 if uintptr(unsafe.Pointer(t)) != symbolMap[FirstModulePrefix+loc.Sym.Name] && !isVariant { 967 // This shouldn't be possible and indicates a registration bug 968 panic(fmt.Sprintf("found another firstmodule type that wasn't registered by goloader. Symbol name: %s, type name: %s. This shouldn't be possible and indicates a bug in firstmodule type registration\n", loc.Sym.Name, t.nameOff(t.str).name())) 969 } 970 // Store this for later so we know which types were deduplicated 971 dedupedTypes[loc.Sym.Name] = uintptr(unsafe.Pointer(t)) 972 973 for _, pkgPathToSkip := range linker.options.SkipTypeDeduplicationForPackages { 974 if t.PkgPath() == pkgPathToSkip { 975 continue relocLoop 976 } 977 } 978 u := t.uncommon() 979 prevU := prevT.uncommon() 980 err2 := codeModule.patchTypeMethodOffsets(t, u, prevU, patchedTypeMethodsIfn, patchedTypeMethodsTfn, patchedTypeMethodsMtyp) 981 if err2 != nil { 982 return err2 983 } 984 985 addr = uintptr(unsafe.Pointer(t)) 986 if linker.options.RelocationDebugWriter != nil && loc.Offset != InvalidOffset { 987 var weakness string 988 if loc.Type&reloctype.R_WEAK > 0 { 989 weakness = "WEAK|" 990 } 991 relocType := weakness + objabi.RelocType(loc.Type&^reloctype.R_WEAK).String() 992 _, _ = fmt.Fprintf(linker.options.RelocationDebugWriter, "DEDUPLICATING %10s %10s %18s Base: 0x%x Pos: 0x%08x, Addr: 0x%016x AddrFromBase: %12d %s to %s\n", 993 objabi.SymKind(symbol.Kind), objabi.SymKind(sym.Kind), relocType, addrBase, uintptr(unsafe.Pointer(&relocByte[loc.Offset])), 994 addr, int(addr)-addrBase, symbol.Name, sym.Name) 995 } 996 switch loc.Type { 997 case reloctype.R_GOTPCREL: 998 linker.relocateGOTPCREL(addr, loc, relocByte) 999 case reloctype.R_PCREL: 1000 err2 := linker.relocatePCREL(addr, loc, &codeModule.segment, relocByte, addrBase) 1001 if err2 != nil { 1002 err = err2 1003 } 1004 case reloctype.R_CALLARM, reloctype.R_CALLARM64, reloctype.R_CALL: 1005 panic("This should not be possible") 1006 case reloctype.R_ADDRARM64, reloctype.R_ARM64_PCREL_LDST8, reloctype.R_ARM64_PCREL_LDST16, reloctype.R_ARM64_PCREL_LDST32, reloctype.R_ARM64_PCREL_LDST64, reloctype.R_ARM64_GOTPCREL: 1007 err2 := linker.relocateADRP(relocByte[loc.Offset:], loc, segment, addr) 1008 if err2 != nil { 1009 err = err2 1010 } 1011 case reloctype.R_ADDR, reloctype.R_WEAKADDR: 1012 // TODO - sanity check this 1013 address := uintptr(int(addr) + loc.Add) 1014 putAddress(byteorder, relocByte[loc.Offset:], uint64(address)) 1015 case reloctype.R_ADDROFF, reloctype.R_WEAKADDROFF: 1016 offset := int(addr) - addrBase + loc.Add 1017 if offset > 0x7FFFFFFF || offset < -0x80000000 { 1018 err = fmt.Errorf("symName: %s %s offset: %d overflows!\n", objabi.RelocType(loc.Type), sym.Name, offset) 1019 } 1020 byteorder.PutUint32(relocByte[loc.Offset:], uint32(offset)) 1021 case reloctype.R_METHODOFF: 1022 if loc.Sym.Kind == symkind.STEXT { 1023 addrBase = segment.codeBase 1024 } 1025 offset := int(addr) - addrBase + loc.Add 1026 if offset > 0x7FFFFFFF || offset < -0x80000000 { 1027 err = fmt.Errorf("symName: %s %s offset: %d overflows!\n", objabi.RelocType(loc.Type), sym.Name, offset) 1028 } 1029 byteorder.PutUint32(relocByte[loc.Offset:], uint32(offset)) 1030 case reloctype.R_USETYPE, reloctype.R_USEIFACE, reloctype.R_USEIFACEMETHOD, reloctype.R_ADDRCUOFF, reloctype.R_KEEP: 1031 // nothing to do 1032 default: 1033 panic(fmt.Sprintf("unhandled reloc %s", objabi.RelocType(loc.Type))) 1034 // TODO - should we attempt to rewrite other relocations which point at *_types too? 1035 } 1036 } 1037 } 1038 } 1039 if linker.options.DumpTextBeforeAndAfterRelocs && linker.options.RelocationDebugWriter != nil && symbol.Kind == symkind.STEXT && symbol.Offset >= 0 { 1040 _, _ = fmt.Fprintf(linker.options.RelocationDebugWriter, " AFTER DEDUPE (%x - %x) %142s: %x\n", codeModule.codeBase+symbol.Offset, codeModule.codeBase+symbol.Offset+symbol.Size, symbol.Name, codeModule.codeByte[symbol.Offset:symbol.Offset+symbol.Size]) 1041 } 1042 } 1043 codeModule.patchedTypeMethodsIfn = patchedTypeMethodsIfn 1044 codeModule.patchedTypeMethodsTfn = patchedTypeMethodsTfn 1045 codeModule.patchedTypeMethodsMtyp = patchedTypeMethodsMtyp 1046 codeModule.deduplicatedTypes = dedupedTypes 1047 1048 if err != nil { 1049 return err 1050 } 1051 err = patchTypeMethodTextPtrs(uintptr(codeModule.codeBase), codeModule.patchedTypeMethodsIfn, codeModule.patchedTypeMethodsTfn) 1052 1053 return err 1054 } 1055 1056 func (linker *Linker) buildExports(codeModule *CodeModule, symbolMap map[string]uintptr) { 1057 codeModule.SymbolsByPkg = map[string]map[string]interface{}{} 1058 for _, pkg := range linker.pkgs { 1059 pkgSyms := map[string]interface{}{} 1060 for name, info := range pkg.Exports { 1061 reachable := linker.isSymbolReachable(info.SymName) 1062 typeAddr, ok := symbolMap[info.TypeName] 1063 if !ok { 1064 if !reachable { 1065 // Doesn't matter 1066 continue 1067 } 1068 // Only panic if a type is missing from the main JIT package - types might not be included for //go:linkname'd symbols, and that's ok 1069 if linker.pkgs[len(linker.pkgs)-1] == pkg { 1070 panic("could not find type symbol " + info.TypeName + " needed for " + info.SymName) 1071 } else { 1072 continue 1073 } 1074 } 1075 fmTypeAddr, ok := symbolMap[FirstModulePrefix+info.TypeName] 1076 if ok && fmTypeAddr != typeAddr { 1077 // Prefer firstmodule types if equal (i.e. deduplicate) 1078 seen := map[_typePair]struct{}{} 1079 fmTyp := (*_type)(unsafe.Pointer(fmTypeAddr)) 1080 newTyp := (*_type)(unsafe.Pointer(typeAddr)) 1081 if fmTyp.hash == newTyp.hash && typesEqual(fmTyp, newTyp, seen) { 1082 typeAddr = fmTypeAddr 1083 } 1084 } 1085 addr, ok := symbolMap[info.SymName] 1086 if !ok { 1087 if !reachable { 1088 continue 1089 } 1090 panic(fmt.Sprintf("could not find symbol %s in package %s", info.SymName, pkg.PkgPath)) 1091 } 1092 t := (*_type)(unsafe.Pointer(typeAddr)) 1093 if dup, ok := codeModule.deduplicatedTypes[info.TypeName]; ok { 1094 t = (*_type)(unsafe.Pointer(dup)) 1095 } 1096 1097 var val interface{} 1098 valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&val)) 1099 (*valp)[0] = unsafe.Pointer(t) 1100 1101 if t.Kind() == reflect.Func { 1102 (*valp)[1] = unsafe.Pointer(&addr) 1103 } else { 1104 (*valp)[1] = unsafe.Pointer(addr) 1105 } 1106 1107 pkgSyms[name] = val 1108 } 1109 if len(pkgSyms) > 0 { 1110 codeModule.SymbolsByPkg[pkg.PkgPath] = pkgSyms 1111 } 1112 } 1113 } 1114 1115 func (linker *Linker) UnresolvedExternalSymbols(symbolMap map[string]uintptr, ignorePackages []string, stdLibPkgs map[string]struct{}, unsafeBlindlyUseFirstModuleTypes bool) map[string]*obj.Sym { 1116 symMap := make(map[string]*obj.Sym) 1117 for symName, sym := range linker.symMap { 1118 shouldSkipDedup := false 1119 for _, pkgPath := range ignorePackages { 1120 if sym.Pkg == pkgPath { 1121 shouldSkipDedup = true 1122 } 1123 } 1124 if sym.Offset == InvalidOffset || shouldSkipDedup { 1125 if strings.HasPrefix(symName, TypePrefix) && 1126 !strings.HasPrefix(symName, TypeDoubleDotPrefix) { 1127 // Always force the rebuild of non-std lib types in case they've changed between firstmodule and JIT code 1128 // They can be checked for structural equality if the JIT code builds it, but not if we blindly use the firstmodule version of a _type 1129 if typeSym, ok := symbolMap[symName]; ok { 1130 t := (*_type)(unsafe.Pointer(typeSym)) 1131 firstModuleTypeHasUnreachableMethods := false 1132 if u := t.uncommon(); u != nil && linker.isTypeReachable(symName) { 1133 for _, method := range u.methods() { 1134 if method.tfn == -1 || method.ifn == -1 { 1135 // This first module method is unreachable, so check if JIT code calls this method, 1136 // and if it does, then mark the whole type as an unresolved symbol 1137 if linker.isSymbolReachable(fullyQualifiedMethodName(t, method)) { 1138 firstModuleTypeHasUnreachableMethods = true 1139 break 1140 } 1141 } 1142 } 1143 } 1144 _, isStdLibPkg := stdLibPkgs[t.PkgPath()] 1145 // Don't rebuild types in the stdlib, as these shouldn't be different (assuming same toolchain version for host and JIT) 1146 if t.PkgPath() != "" && (!isStdLibPkg || firstModuleTypeHasUnreachableMethods) { 1147 // Only rebuild types which are reachable (via relocs) from the main package, otherwise we'll end up building everything unnecessarily 1148 if (linker.isTypeReachable(symName) && !unsafeBlindlyUseFirstModuleTypes) || firstModuleTypeHasUnreachableMethods { 1149 symMap[symName] = sym 1150 } 1151 } 1152 } 1153 } 1154 if _, ok := symbolMap[symName]; !ok || shouldSkipDedup { 1155 if _, ok := linker.objsymbolMap[symName]; !ok || shouldSkipDedup { 1156 if linker.isSymbolReachable(symName) { 1157 symMap[symName] = sym 1158 } 1159 } 1160 } 1161 } 1162 } 1163 1164 for _, sym := range symMap { 1165 _, alreadyBuiltPkg := linker.pkgsByName[sym.Pkg] 1166 if alreadyBuiltPkg { 1167 // If we already built and loaded the package which this symbol came from, it's probably linknamed and implemented in runtime 1168 if sym.Pkg != "runtime" { 1169 sym.Pkg = "runtime" 1170 } else { 1171 // If we already built runtime and still can't find this sym, it may be a runtime/internal/* type 1172 // TODO - this doesn't seem robust 1173 if strings.HasPrefix(sym.Name, TypePrefix+"runtime/internal") { 1174 sym.Pkg = strings.Split(strings.TrimPrefix(sym.Name, TypePrefix), ".")[0] 1175 } 1176 } 1177 } 1178 } 1179 return symMap 1180 } 1181 1182 func (linker *Linker) UnresolvedPackageReferences(existingPkgs []string) []string { 1183 var pkgList []string 1184 outer: 1185 for pkgName := range linker.pkgNamesWithUnresolved { 1186 for _, existing := range existingPkgs { 1187 if pkgName == existing { 1188 continue outer 1189 } 1190 } 1191 pkgList = append(pkgList, pkgName) 1192 } 1193 outer2: 1194 for pkgName := range linker.pkgNamesToForceRebuild { 1195 for _, alreadyAdded := range pkgList { 1196 if alreadyAdded == pkgName { 1197 continue outer2 1198 } 1199 } 1200 pkgList = append(pkgList, pkgName) 1201 } 1202 return pkgList 1203 } 1204 1205 func (linker *Linker) UnresolvedExternalSymbolUsers(symbolMap map[string]uintptr) map[string][]string { 1206 requiredBy := map[string][]string{} 1207 for symName, sym := range linker.symMap { 1208 if sym.Offset == InvalidOffset { 1209 if _, ok := symbolMap[symName]; !ok { 1210 if _, ok := linker.objsymbolMap[symName]; !ok { 1211 if linker.isSymbolReachable(symName) { 1212 var requiredBySet = map[string]struct{}{} 1213 for _, otherSym := range linker.symMap { 1214 for _, reloc := range otherSym.Reloc { 1215 if reloc.Sym.Name == symName { 1216 requiredBySet[otherSym.Name] = struct{}{} 1217 } 1218 } 1219 } 1220 requiredByList := make([]string, 0, len(requiredBySet)) 1221 for k := range requiredBySet { 1222 requiredByList = append(requiredByList, k) 1223 } 1224 sort.Strings(requiredByList) 1225 requiredBy[sym.Name] = requiredByList 1226 } 1227 } 1228 } 1229 } 1230 } 1231 return requiredBy 1232 } 1233 1234 func (linker *Linker) UnloadStrings() { 1235 linker.heapStringMap = nil 1236 } 1237 1238 func Load(linker *Linker, symPtr map[string]uintptr) (codeModule *CodeModule, err error) { 1239 codeModule = &CodeModule{ 1240 Syms: make(map[string]uintptr), 1241 module: &moduledata{typemap: make(map[typeOff]*_type)}, 1242 } 1243 codeModule.codeLen = len(linker.code) 1244 codeModule.dataLen = len(linker.data) 1245 codeModule.noptrdataLen = len(linker.noptrdata) 1246 codeModule.bssLen = len(linker.bss) 1247 codeModule.noptrbssLen = len(linker.noptrbss) 1248 codeModule.sumDataLen = codeModule.dataLen + codeModule.noptrdataLen + codeModule.bssLen + codeModule.noptrbssLen 1249 codeModule.maxCodeLength = alignof(codeModule.codeLen, PageSize) 1250 codeModule.maxDataLength = alignof(codeModule.sumDataLen, PageSize) 1251 codeByte, err := Mmap(codeModule.maxCodeLength) 1252 if err != nil { 1253 return nil, err 1254 } 1255 dataByte, err := MmapData(codeModule.maxDataLength) 1256 if err != nil { 1257 return nil, err 1258 } 1259 1260 codeModule.codeByte = codeByte 1261 codeModule.codeBase = int((*sliceHeader)(unsafe.Pointer(&codeByte)).Data) 1262 copy(codeModule.codeByte, linker.code) 1263 codeModule.codeOff = codeModule.codeLen 1264 1265 codeModule.dataByte = dataByte 1266 codeModule.dataBase = int((*sliceHeader)(unsafe.Pointer(&dataByte)).Data) 1267 copy(codeModule.dataByte[codeModule.dataOff:], linker.data) 1268 codeModule.dataOff = codeModule.dataLen 1269 copy(codeModule.dataByte[codeModule.dataOff:], linker.noptrdata) 1270 codeModule.dataOff += codeModule.noptrdataLen 1271 copy(codeModule.dataByte[codeModule.dataOff:], linker.bss) 1272 codeModule.dataOff += codeModule.bssLen 1273 copy(codeModule.dataByte[codeModule.dataOff:], linker.noptrbss) 1274 codeModule.dataOff += codeModule.noptrbssLen 1275 1276 var symbolMap map[string]uintptr 1277 if symbolMap, err = linker.addSymbolMap(symPtr, codeModule); err == nil { 1278 if err = linker.relocate(codeModule, symbolMap); err == nil { 1279 if err = linker.buildModule(codeModule, symbolMap); err == nil { 1280 if err = linker.deduplicateTypeDescriptors(codeModule, symbolMap); err == nil { 1281 linker.buildExports(codeModule, symbolMap) 1282 MakeThreadJITCodeExecutable(uintptr(codeModule.codeBase), codeModule.maxCodeLength) 1283 if err = linker.doInitialize(codeModule, symbolMap); err == nil { 1284 return codeModule, err 1285 } 1286 } 1287 } 1288 } 1289 } 1290 if err != nil { 1291 err2 := Munmap(codeByte) 1292 err3 := Munmap(dataByte) 1293 if err2 != nil { 1294 err = fmt.Errorf("failed to munmap (%s) after linker error: %w", err2, err) 1295 } 1296 if err3 != nil { 1297 err = fmt.Errorf("failed to munmap (%s) after linker error: %w", err3, err) 1298 } 1299 } 1300 return nil, err 1301 } 1302 1303 func (cm *CodeModule) Unload() error { 1304 err := cm.revertPatchedTypeMethods() 1305 if err != nil { 1306 return err 1307 } 1308 removeitabs(cm.module) 1309 runtime.GC() 1310 modulesLock.Lock() 1311 removeModule(cm) 1312 modulesLock.Unlock() 1313 modulesinit() 1314 err1 := Munmap(cm.codeByte) 1315 err2 := Munmap(cm.dataByte) 1316 if err1 != nil { 1317 return err1 1318 } 1319 cm.heapStrings = nil 1320 return err2 1321 } 1322 1323 func (cm *CodeModule) TextAddr() (start, end uintptr) { 1324 if cm.module == nil { 1325 return 0, 0 1326 } 1327 return cm.module.text, cm.module.etext 1328 } 1329 1330 func (cm *CodeModule) DataAddr() (start, end uintptr) { 1331 if cm.module == nil { 1332 return 0, 0 1333 } 1334 return cm.module.data, cm.module.enoptrbss 1335 }