github.com/bir3/gocompiler@v0.9.2202/src/cmd/link/internal/loadpe/ldpe.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package loadpe implements a PE/COFF file reader. 6 package loadpe 7 8 import ( 9 "bytes" 10 "github.com/bir3/gocompiler/src/cmd/internal/bio" 11 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 12 "github.com/bir3/gocompiler/src/cmd/internal/sys" 13 "github.com/bir3/gocompiler/src/cmd/link/internal/loader" 14 "github.com/bir3/gocompiler/src/cmd/link/internal/sym" 15 "debug/pe" 16 "encoding/binary" 17 "errors" 18 "fmt" 19 "io" 20 "strings" 21 ) 22 23 const ( 24 IMAGE_SYM_UNDEFINED = 0 25 IMAGE_SYM_ABSOLUTE = -1 26 IMAGE_SYM_DEBUG = -2 27 IMAGE_SYM_TYPE_NULL = 0 28 IMAGE_SYM_TYPE_VOID = 1 29 IMAGE_SYM_TYPE_CHAR = 2 30 IMAGE_SYM_TYPE_SHORT = 3 31 IMAGE_SYM_TYPE_INT = 4 32 IMAGE_SYM_TYPE_LONG = 5 33 IMAGE_SYM_TYPE_FLOAT = 6 34 IMAGE_SYM_TYPE_DOUBLE = 7 35 IMAGE_SYM_TYPE_STRUCT = 8 36 IMAGE_SYM_TYPE_UNION = 9 37 IMAGE_SYM_TYPE_ENUM = 10 38 IMAGE_SYM_TYPE_MOE = 11 39 IMAGE_SYM_TYPE_BYTE = 12 40 IMAGE_SYM_TYPE_WORD = 13 41 IMAGE_SYM_TYPE_UINT = 14 42 IMAGE_SYM_TYPE_DWORD = 15 43 IMAGE_SYM_TYPE_PCODE = 32768 44 IMAGE_SYM_DTYPE_NULL = 0 45 IMAGE_SYM_DTYPE_POINTER = 1 46 IMAGE_SYM_DTYPE_FUNCTION = 2 47 IMAGE_SYM_DTYPE_ARRAY = 3 48 IMAGE_SYM_CLASS_END_OF_FUNCTION = -1 49 IMAGE_SYM_CLASS_NULL = 0 50 IMAGE_SYM_CLASS_AUTOMATIC = 1 51 IMAGE_SYM_CLASS_EXTERNAL = 2 52 IMAGE_SYM_CLASS_STATIC = 3 53 IMAGE_SYM_CLASS_REGISTER = 4 54 IMAGE_SYM_CLASS_EXTERNAL_DEF = 5 55 IMAGE_SYM_CLASS_LABEL = 6 56 IMAGE_SYM_CLASS_UNDEFINED_LABEL = 7 57 IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8 58 IMAGE_SYM_CLASS_ARGUMENT = 9 59 IMAGE_SYM_CLASS_STRUCT_TAG = 10 60 IMAGE_SYM_CLASS_MEMBER_OF_UNION = 11 61 IMAGE_SYM_CLASS_UNION_TAG = 12 62 IMAGE_SYM_CLASS_TYPE_DEFINITION = 13 63 IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14 64 IMAGE_SYM_CLASS_ENUM_TAG = 15 65 IMAGE_SYM_CLASS_MEMBER_OF_ENUM = 16 66 IMAGE_SYM_CLASS_REGISTER_PARAM = 17 67 IMAGE_SYM_CLASS_BIT_FIELD = 18 68 IMAGE_SYM_CLASS_FAR_EXTERNAL = 68 /* Not in PECOFF v8 spec */ 69 IMAGE_SYM_CLASS_BLOCK = 100 70 IMAGE_SYM_CLASS_FUNCTION = 101 71 IMAGE_SYM_CLASS_END_OF_STRUCT = 102 72 IMAGE_SYM_CLASS_FILE = 103 73 IMAGE_SYM_CLASS_SECTION = 104 74 IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105 75 IMAGE_SYM_CLASS_CLR_TOKEN = 107 76 IMAGE_REL_I386_ABSOLUTE = 0x0000 77 IMAGE_REL_I386_DIR16 = 0x0001 78 IMAGE_REL_I386_REL16 = 0x0002 79 IMAGE_REL_I386_DIR32 = 0x0006 80 IMAGE_REL_I386_DIR32NB = 0x0007 81 IMAGE_REL_I386_SEG12 = 0x0009 82 IMAGE_REL_I386_SECTION = 0x000A 83 IMAGE_REL_I386_SECREL = 0x000B 84 IMAGE_REL_I386_TOKEN = 0x000C 85 IMAGE_REL_I386_SECREL7 = 0x000D 86 IMAGE_REL_I386_REL32 = 0x0014 87 IMAGE_REL_AMD64_ABSOLUTE = 0x0000 88 IMAGE_REL_AMD64_ADDR64 = 0x0001 89 IMAGE_REL_AMD64_ADDR32 = 0x0002 90 IMAGE_REL_AMD64_ADDR32NB = 0x0003 91 IMAGE_REL_AMD64_REL32 = 0x0004 92 IMAGE_REL_AMD64_REL32_1 = 0x0005 93 IMAGE_REL_AMD64_REL32_2 = 0x0006 94 IMAGE_REL_AMD64_REL32_3 = 0x0007 95 IMAGE_REL_AMD64_REL32_4 = 0x0008 96 IMAGE_REL_AMD64_REL32_5 = 0x0009 97 IMAGE_REL_AMD64_SECTION = 0x000A 98 IMAGE_REL_AMD64_SECREL = 0x000B 99 IMAGE_REL_AMD64_SECREL7 = 0x000C 100 IMAGE_REL_AMD64_TOKEN = 0x000D 101 IMAGE_REL_AMD64_SREL32 = 0x000E 102 IMAGE_REL_AMD64_PAIR = 0x000F 103 IMAGE_REL_AMD64_SSPAN32 = 0x0010 104 IMAGE_REL_ARM_ABSOLUTE = 0x0000 105 IMAGE_REL_ARM_ADDR32 = 0x0001 106 IMAGE_REL_ARM_ADDR32NB = 0x0002 107 IMAGE_REL_ARM_BRANCH24 = 0x0003 108 IMAGE_REL_ARM_BRANCH11 = 0x0004 109 IMAGE_REL_ARM_SECTION = 0x000E 110 IMAGE_REL_ARM_SECREL = 0x000F 111 IMAGE_REL_ARM_MOV32 = 0x0010 112 IMAGE_REL_THUMB_MOV32 = 0x0011 113 IMAGE_REL_THUMB_BRANCH20 = 0x0012 114 IMAGE_REL_THUMB_BRANCH24 = 0x0014 115 IMAGE_REL_THUMB_BLX23 = 0x0015 116 IMAGE_REL_ARM_PAIR = 0x0016 117 IMAGE_REL_ARM64_ABSOLUTE = 0x0000 118 IMAGE_REL_ARM64_ADDR32 = 0x0001 119 IMAGE_REL_ARM64_ADDR32NB = 0x0002 120 IMAGE_REL_ARM64_BRANCH26 = 0x0003 121 IMAGE_REL_ARM64_PAGEBASE_REL21 = 0x0004 122 IMAGE_REL_ARM64_REL21 = 0x0005 123 IMAGE_REL_ARM64_PAGEOFFSET_12A = 0x0006 124 IMAGE_REL_ARM64_PAGEOFFSET_12L = 0x0007 125 IMAGE_REL_ARM64_SECREL = 0x0008 126 IMAGE_REL_ARM64_SECREL_LOW12A = 0x0009 127 IMAGE_REL_ARM64_SECREL_HIGH12A = 0x000A 128 IMAGE_REL_ARM64_SECREL_LOW12L = 0x000B 129 IMAGE_REL_ARM64_TOKEN = 0x000C 130 IMAGE_REL_ARM64_SECTION = 0x000D 131 IMAGE_REL_ARM64_ADDR64 = 0x000E 132 IMAGE_REL_ARM64_BRANCH19 = 0x000F 133 IMAGE_REL_ARM64_BRANCH14 = 0x0010 134 IMAGE_REL_ARM64_REL32 = 0x0011 135 ) 136 137 const ( 138 // When stored into the PLT value for a symbol, this token tells 139 // windynrelocsym to redirect direct references to this symbol to a stub 140 // that loads from the corresponding import symbol and then does 141 // a jump to the loaded value. 142 CreateImportStubPltToken = -2 143 144 // When stored into the GOT value for an import symbol __imp_X this 145 // token tells windynrelocsym to redirect references to the 146 // underlying DYNIMPORT symbol X. 147 RedirectToDynImportGotToken = -2 148 ) 149 150 // TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating peBiobuf 151 152 // peBiobuf makes bio.Reader look like io.ReaderAt. 153 type peBiobuf bio.Reader 154 155 func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) { 156 ret := ((*bio.Reader)(f)).MustSeek(off, 0) 157 if ret < 0 { 158 return 0, errors.New("fail to seek") 159 } 160 n, err := f.Read(p) 161 if err != nil { 162 return 0, err 163 } 164 return n, nil 165 } 166 167 // makeUpdater creates a loader.SymbolBuilder if one hasn't been created previously. 168 // We use this to lazily make SymbolBuilders as we don't always need a builder, and creating them for all symbols might be an error. 169 func makeUpdater(l *loader.Loader, bld *loader.SymbolBuilder, s loader.Sym) *loader.SymbolBuilder { 170 if bld != nil { 171 return bld 172 } 173 bld = l.MakeSymbolUpdater(s) 174 return bld 175 } 176 177 // peImportSymsState tracks the set of DLL import symbols we've seen 178 // while reading host objects. We create a singleton instance of this 179 // type, which will persist across multiple host objects. 180 type peImportSymsState struct { 181 182 // Text and non-text sections read in by the host object loader. 183 secSyms []loader.Sym 184 185 // Loader and arch, for use in postprocessing. 186 l *loader.Loader 187 arch *sys.Arch 188 } 189 190 var importSymsState *peImportSymsState 191 192 func createImportSymsState(l *loader.Loader, arch *sys.Arch) { 193 if importSymsState != nil { 194 return 195 } 196 importSymsState = &peImportSymsState{ 197 l: l, 198 arch: arch, 199 } 200 } 201 202 // peLoaderState holds various bits of useful state information needed 203 // while loading a single PE object file. 204 type peLoaderState struct { 205 l *loader.Loader 206 arch *sys.Arch 207 f *pe.File 208 pn string 209 sectsyms map[*pe.Section]loader.Sym 210 comdats map[uint16]int64 // key is section index, val is size 211 sectdata map[*pe.Section][]byte 212 localSymVersion int 213 } 214 215 // comdatDefinitions records the names of symbols for which we've 216 // previously seen a definition in COMDAT. Key is symbol name, value 217 // is symbol size (or -1 if we're using the "any" strategy). 218 var comdatDefinitions map[string]int64 219 220 // Symbols contains the symbols that can be loaded from a PE file. 221 type Symbols struct { 222 Textp []loader.Sym // text symbols 223 Resources []loader.Sym // .rsrc section or set of .rsrc$xx sections 224 PData loader.Sym 225 XData loader.Sym 226 } 227 228 // Load loads the PE file pn from input. 229 // Symbols from the object file are created via the loader 'l'. 230 func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (*Symbols, error) { 231 state := &peLoaderState{ 232 l: l, 233 arch: arch, 234 sectsyms: make(map[*pe.Section]loader.Sym), 235 sectdata: make(map[*pe.Section][]byte), 236 localSymVersion: localSymVersion, 237 pn: pn, 238 } 239 createImportSymsState(state.l, state.arch) 240 if comdatDefinitions == nil { 241 comdatDefinitions = make(map[string]int64) 242 } 243 244 // Some input files are archives containing multiple of 245 // object files, and pe.NewFile seeks to the start of 246 // input file and get confused. Create section reader 247 // to stop pe.NewFile looking before current position. 248 sr := io.NewSectionReader((*peBiobuf)(input), input.Offset(), 1<<63-1) 249 250 // TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details) 251 f, err := pe.NewFile(sr) 252 if err != nil { 253 return nil, err 254 } 255 defer f.Close() 256 state.f = f 257 258 var ls Symbols 259 260 // TODO return error if found .cormeta 261 262 // create symbols for mapped sections 263 for _, sect := range f.Sections { 264 if sect.Characteristics&pe.IMAGE_SCN_MEM_DISCARDABLE != 0 { 265 continue 266 } 267 268 if sect.Characteristics&(pe.IMAGE_SCN_CNT_CODE|pe.IMAGE_SCN_CNT_INITIALIZED_DATA|pe.IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 { 269 // This has been seen for .idata sections, which we 270 // want to ignore. See issues 5106 and 5273. 271 continue 272 } 273 274 name := fmt.Sprintf("%s(%s)", pkg, sect.Name) 275 s := state.l.LookupOrCreateCgoExport(name, localSymVersion) 276 bld := l.MakeSymbolUpdater(s) 277 278 switch sect.Characteristics & (pe.IMAGE_SCN_CNT_UNINITIALIZED_DATA | pe.IMAGE_SCN_CNT_INITIALIZED_DATA | pe.IMAGE_SCN_MEM_READ | pe.IMAGE_SCN_MEM_WRITE | pe.IMAGE_SCN_CNT_CODE | pe.IMAGE_SCN_MEM_EXECUTE) { 279 case pe.IMAGE_SCN_CNT_INITIALIZED_DATA | pe.IMAGE_SCN_MEM_READ: //.rdata 280 if issehsect(arch, sect) { 281 bld.SetType(sym.SSEHSECT) 282 bld.SetAlign(4) 283 } else { 284 bld.SetType(sym.SRODATA) 285 } 286 287 case pe.IMAGE_SCN_CNT_UNINITIALIZED_DATA | pe.IMAGE_SCN_MEM_READ | pe.IMAGE_SCN_MEM_WRITE: //.bss 288 bld.SetType(sym.SNOPTRBSS) 289 290 case pe.IMAGE_SCN_CNT_INITIALIZED_DATA | pe.IMAGE_SCN_MEM_READ | pe.IMAGE_SCN_MEM_WRITE: //.data 291 bld.SetType(sym.SNOPTRDATA) 292 293 case pe.IMAGE_SCN_CNT_CODE | pe.IMAGE_SCN_MEM_EXECUTE | pe.IMAGE_SCN_MEM_READ: //.text 294 bld.SetType(sym.STEXT) 295 296 default: 297 return nil, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name) 298 } 299 300 if bld.Type() != sym.SNOPTRBSS { 301 data, err := sect.Data() 302 if err != nil { 303 return nil, err 304 } 305 state.sectdata[sect] = data 306 bld.SetData(data) 307 } 308 bld.SetSize(int64(sect.Size)) 309 state.sectsyms[sect] = s 310 if sect.Name == ".rsrc" || strings.HasPrefix(sect.Name, ".rsrc$") { 311 ls.Resources = append(ls.Resources, s) 312 } else if bld.Type() == sym.SSEHSECT { 313 if sect.Name == ".pdata" { 314 ls.PData = s 315 } else if sect.Name == ".xdata" { 316 ls.XData = s 317 } 318 } 319 } 320 321 // Make a prepass over the symbols to collect info about COMDAT symbols. 322 if err := state.preprocessSymbols(); err != nil { 323 return nil, err 324 } 325 326 // load relocations 327 for _, rsect := range f.Sections { 328 if _, found := state.sectsyms[rsect]; !found { 329 continue 330 } 331 if rsect.NumberOfRelocations == 0 { 332 continue 333 } 334 if rsect.Characteristics&pe.IMAGE_SCN_MEM_DISCARDABLE != 0 { 335 continue 336 } 337 if rsect.Characteristics&(pe.IMAGE_SCN_CNT_CODE|pe.IMAGE_SCN_CNT_INITIALIZED_DATA|pe.IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 { 338 // This has been seen for .idata sections, which we 339 // want to ignore. See issues 5106 and 5273. 340 continue 341 } 342 343 splitResources := strings.HasPrefix(rsect.Name, ".rsrc$") 344 issehsect := issehsect(arch, rsect) 345 sb := l.MakeSymbolUpdater(state.sectsyms[rsect]) 346 for j, r := range rsect.Relocs { 347 if int(r.SymbolTableIndex) >= len(f.COFFSymbols) { 348 return nil, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols)) 349 } 350 pesym := &f.COFFSymbols[r.SymbolTableIndex] 351 _, gosym, err := state.readpesym(pesym) 352 if err != nil { 353 return nil, err 354 } 355 if gosym == 0 { 356 name, err := pesym.FullName(f.StringTable) 357 if err != nil { 358 name = string(pesym.Name[:]) 359 } 360 return nil, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type) 361 } 362 363 rSym := gosym 364 rSize := uint8(4) 365 rOff := int32(r.VirtualAddress) 366 var rAdd int64 367 var rType objabi.RelocType 368 switch arch.Family { 369 default: 370 return nil, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family) 371 case sys.I386, sys.AMD64: 372 switch r.Type { 373 default: 374 return nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, state.sectsyms[rsect], r.Type) 375 376 case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32, 377 IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32 378 IMAGE_REL_AMD64_ADDR32NB: 379 if r.Type == IMAGE_REL_AMD64_ADDR32NB { 380 rType = objabi.R_PEIMAGEOFF 381 } else { 382 rType = objabi.R_PCREL 383 } 384 385 rAdd = int64(int32(binary.LittleEndian.Uint32(state.sectdata[rsect][rOff:]))) 386 387 case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32: 388 if r.Type == IMAGE_REL_I386_DIR32NB { 389 rType = objabi.R_PEIMAGEOFF 390 } else { 391 rType = objabi.R_ADDR 392 } 393 394 // load addend from image 395 rAdd = int64(int32(binary.LittleEndian.Uint32(state.sectdata[rsect][rOff:]))) 396 397 case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 398 rSize = 8 399 400 rType = objabi.R_ADDR 401 402 // load addend from image 403 rAdd = int64(binary.LittleEndian.Uint64(state.sectdata[rsect][rOff:])) 404 } 405 406 case sys.ARM: 407 switch r.Type { 408 default: 409 return nil, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, state.sectsyms[rsect], r.Type) 410 411 case IMAGE_REL_ARM_SECREL: 412 rType = objabi.R_PCREL 413 414 rAdd = int64(int32(binary.LittleEndian.Uint32(state.sectdata[rsect][rOff:]))) 415 416 case IMAGE_REL_ARM_ADDR32, IMAGE_REL_ARM_ADDR32NB: 417 if r.Type == IMAGE_REL_ARM_ADDR32NB { 418 rType = objabi.R_PEIMAGEOFF 419 } else { 420 rType = objabi.R_ADDR 421 } 422 423 rAdd = int64(int32(binary.LittleEndian.Uint32(state.sectdata[rsect][rOff:]))) 424 425 case IMAGE_REL_ARM_BRANCH24: 426 rType = objabi.R_CALLARM 427 428 rAdd = int64(int32(binary.LittleEndian.Uint32(state.sectdata[rsect][rOff:]))) 429 } 430 431 case sys.ARM64: 432 switch r.Type { 433 default: 434 return nil, fmt.Errorf("%s: %v: unknown ARM64 relocation type %v", pn, state.sectsyms[rsect], r.Type) 435 436 case IMAGE_REL_ARM64_ADDR32, IMAGE_REL_ARM64_ADDR32NB: 437 if r.Type == IMAGE_REL_ARM64_ADDR32NB { 438 rType = objabi.R_PEIMAGEOFF 439 } else { 440 rType = objabi.R_ADDR 441 } 442 443 rAdd = int64(int32(binary.LittleEndian.Uint32(state.sectdata[rsect][rOff:]))) 444 } 445 } 446 447 // ld -r could generate multiple section symbols for the 448 // same section but with different values, we have to take 449 // that into account, or in the case of split resources, 450 // the section and its symbols are split into two sections. 451 if issect(pesym) || splitResources { 452 rAdd += int64(pesym.Value) 453 } 454 if issehsect { 455 // .pdata and .xdata sections can contain records 456 // associated to functions that won't be used in 457 // the final binary, in which case the relocation 458 // target symbol won't be reachable. 459 rType |= objabi.R_WEAK 460 } 461 462 rel, _ := sb.AddRel(rType) 463 rel.SetOff(rOff) 464 rel.SetSiz(rSize) 465 rel.SetSym(rSym) 466 rel.SetAdd(rAdd) 467 468 } 469 470 sb.SortRelocs() 471 } 472 473 // enter sub-symbols into symbol table. 474 for i, numaux := 0, 0; i < len(f.COFFSymbols); i += numaux + 1 { 475 pesym := &f.COFFSymbols[i] 476 477 numaux = int(pesym.NumberOfAuxSymbols) 478 479 name, err := pesym.FullName(f.StringTable) 480 if err != nil { 481 return nil, err 482 } 483 if name == "" { 484 continue 485 } 486 if issect(pesym) { 487 continue 488 } 489 if int(pesym.SectionNumber) > len(f.Sections) { 490 continue 491 } 492 if pesym.SectionNumber == IMAGE_SYM_DEBUG { 493 continue 494 } 495 if pesym.SectionNumber == IMAGE_SYM_ABSOLUTE && bytes.Equal(pesym.Name[:], []byte("@feat.00")) { 496 // The PE documentation says that, on x86 platforms, the absolute symbol named @feat.00 497 // is used to indicate that the COFF object supports SEH. 498 // Go doesn't support SEH on windows/386, so we can ignore this symbol. 499 // See https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#the-sxdata-section 500 continue 501 } 502 var sect *pe.Section 503 if pesym.SectionNumber > 0 { 504 sect = f.Sections[pesym.SectionNumber-1] 505 if _, found := state.sectsyms[sect]; !found { 506 continue 507 } 508 } 509 510 bld, s, err := state.readpesym(pesym) 511 if err != nil { 512 return nil, err 513 } 514 515 if pesym.SectionNumber == 0 { // extern 516 if l.SymType(s) == sym.SXREF && pesym.Value > 0 { // global data 517 bld = makeUpdater(l, bld, s) 518 bld.SetType(sym.SNOPTRDATA) 519 bld.SetSize(int64(pesym.Value)) 520 } 521 522 continue 523 } else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) { 524 sect = f.Sections[pesym.SectionNumber-1] 525 if _, found := state.sectsyms[sect]; !found { 526 return nil, fmt.Errorf("%s: %v: missing sect.sym", pn, s) 527 } 528 } else { 529 return nil, fmt.Errorf("%s: %v: sectnum < 0!", pn, s) 530 } 531 532 if sect == nil { 533 return nil, nil 534 } 535 536 // Check for COMDAT symbol. 537 if sz, ok1 := state.comdats[uint16(pesym.SectionNumber-1)]; ok1 { 538 if psz, ok2 := comdatDefinitions[l.SymName(s)]; ok2 { 539 if sz == psz { 540 // OK to discard, we've seen an instance 541 // already. 542 continue 543 } 544 } 545 } 546 if l.OuterSym(s) != 0 { 547 if l.AttrDuplicateOK(s) { 548 continue 549 } 550 outerName := l.SymName(l.OuterSym(s)) 551 sectName := l.SymName(state.sectsyms[sect]) 552 return nil, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, l.SymName(s), outerName, sectName) 553 } 554 555 bld = makeUpdater(l, bld, s) 556 sectsym := state.sectsyms[sect] 557 bld.SetType(l.SymType(sectsym)) 558 l.AddInteriorSym(sectsym, s) 559 bld.SetValue(int64(pesym.Value)) 560 bld.SetSize(4) 561 if l.SymType(sectsym) == sym.STEXT { 562 if bld.External() && !bld.DuplicateOK() { 563 return nil, fmt.Errorf("%s: duplicate symbol definition", l.SymName(s)) 564 } 565 bld.SetExternal(true) 566 } 567 if sz, ok := state.comdats[uint16(pesym.SectionNumber-1)]; ok { 568 // This is a COMDAT definition. Record that we're picking 569 // this instance so that we can ignore future defs. 570 if _, ok := comdatDefinitions[l.SymName(s)]; ok { 571 return nil, fmt.Errorf("internal error: preexisting COMDAT definition for %q", name) 572 } 573 comdatDefinitions[l.SymName(s)] = sz 574 } 575 } 576 577 // Sort outer lists by address, adding to textp. 578 // This keeps textp in increasing address order. 579 for _, sect := range f.Sections { 580 s := state.sectsyms[sect] 581 if s == 0 { 582 continue 583 } 584 l.SortSub(s) 585 importSymsState.secSyms = append(importSymsState.secSyms, s) 586 if l.SymType(s) == sym.STEXT { 587 for ; s != 0; s = l.SubSym(s) { 588 if l.AttrOnList(s) { 589 return nil, fmt.Errorf("symbol %s listed multiple times", l.SymName(s)) 590 } 591 l.SetAttrOnList(s, true) 592 ls.Textp = append(ls.Textp, s) 593 } 594 } 595 } 596 597 if ls.PData != 0 { 598 processSEH(l, arch, ls.PData, ls.XData) 599 } 600 601 return &ls, nil 602 } 603 604 // PostProcessImports works to resolve inconsistencies with DLL import 605 // symbols; it is needed when building with more "modern" C compilers 606 // with internal linkage. 607 // 608 // Background: DLL import symbols are data (SNOPTRDATA) symbols whose 609 // name is of the form "__imp_XXX", which contain a pointer/reference 610 // to symbol XXX. It's possible to have import symbols for both data 611 // symbols ("__imp__fmode") and text symbols ("__imp_CreateEventA"). 612 // In some case import symbols are just references to some external 613 // thing, and in other cases we see actual definitions of import 614 // symbols when reading host objects. 615 // 616 // Previous versions of the linker would in most cases immediately 617 // "forward" import symbol references, e.g. treat a references to 618 // "__imp_XXX" a references to "XXX", however this doesn't work well 619 // with more modern compilers, where you can sometimes see import 620 // symbols that are defs (as opposed to external refs). 621 // 622 // The main actions taken below are to search for references to 623 // SDYNIMPORT symbols in host object text/data sections and flag the 624 // symbols for later fixup. When we see a reference to an import 625 // symbol __imp_XYZ where XYZ corresponds to some SDYNIMPORT symbol, 626 // we flag the symbol (via GOT setting) so that it can be redirected 627 // to XYZ later in windynrelocsym. When we see a direct reference to 628 // an SDYNIMPORT symbol XYZ, we also flag the symbol (via PLT setting) 629 // to indicated that the reference will need to be redirected to a 630 // stub. 631 func PostProcessImports() error { 632 ldr := importSymsState.l 633 arch := importSymsState.arch 634 keeprelocneeded := make(map[loader.Sym]loader.Sym) 635 for _, s := range importSymsState.secSyms { 636 isText := ldr.SymType(s) == sym.STEXT 637 relocs := ldr.Relocs(s) 638 for i := 0; i < relocs.Count(); i++ { 639 r := relocs.At(i) 640 rs := r.Sym() 641 if ldr.SymType(rs) == sym.SDYNIMPORT { 642 // Tag the symbol for later stub generation. 643 ldr.SetPlt(rs, CreateImportStubPltToken) 644 continue 645 } 646 isym, err := LookupBaseFromImport(rs, ldr, arch) 647 if err != nil { 648 return err 649 } 650 if isym == 0 { 651 continue 652 } 653 if ldr.SymType(isym) != sym.SDYNIMPORT { 654 continue 655 } 656 // For non-text symbols, forward the reference from __imp_X to 657 // X immediately. 658 if !isText { 659 r.SetSym(isym) 660 continue 661 } 662 // Flag this imp symbol to be processed later in windynrelocsym. 663 ldr.SetGot(rs, RedirectToDynImportGotToken) 664 // Consistency check: should be no PLT token here. 665 splt := ldr.SymPlt(rs) 666 if splt != -1 { 667 return fmt.Errorf("internal error: import symbol %q has invalid PLT setting %d", ldr.SymName(rs), splt) 668 } 669 // Flag for dummy relocation. 670 keeprelocneeded[rs] = isym 671 } 672 } 673 for k, v := range keeprelocneeded { 674 sb := ldr.MakeSymbolUpdater(k) 675 r, _ := sb.AddRel(objabi.R_KEEP) 676 r.SetSym(v) 677 } 678 importSymsState = nil 679 return nil 680 } 681 682 func issehsect(arch *sys.Arch, s *pe.Section) bool { 683 return arch.Family == sys.AMD64 && (s.Name == ".pdata" || s.Name == ".xdata") 684 } 685 686 func issect(s *pe.COFFSymbol) bool { 687 return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.' 688 } 689 690 func (state *peLoaderState) readpesym(pesym *pe.COFFSymbol) (*loader.SymbolBuilder, loader.Sym, error) { 691 symname, err := pesym.FullName(state.f.StringTable) 692 if err != nil { 693 return nil, 0, err 694 } 695 var name string 696 if issect(pesym) { 697 name = state.l.SymName(state.sectsyms[state.f.Sections[pesym.SectionNumber-1]]) 698 } else { 699 name = symname 700 // A note on the "_main" exclusion below: the main routine 701 // defined by the Go runtime is named "_main", not "main", so 702 // when reading references to _main from a host object we want 703 // to avoid rewriting "_main" to "main" in this specific 704 // instance. See #issuecomment-1143698749 on #35006 for more 705 // details on this problem. 706 if state.arch.Family == sys.I386 && name[0] == '_' && name != "_main" && !strings.HasPrefix(name, "__imp_") { 707 name = name[1:] // _Name => Name 708 } 709 } 710 711 // remove last @XXX 712 if i := strings.LastIndex(name, "@"); i >= 0 { 713 name = name[:i] 714 } 715 716 var s loader.Sym 717 var bld *loader.SymbolBuilder 718 // Microsoft's PE documentation is contradictory. It says that the symbol's complex type 719 // is stored in the pesym.Type most significant byte, but MSVC, LLVM, and mingw store it 720 // in the 4 high bits of the less significant byte. 721 switch uint8(pesym.Type&0xf0) >> 4 { 722 default: 723 return nil, 0, fmt.Errorf("%s: invalid symbol type %d", symname, pesym.Type) 724 725 case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL: 726 switch pesym.StorageClass { 727 case IMAGE_SYM_CLASS_EXTERNAL: //global 728 s = state.l.LookupOrCreateCgoExport(name, 0) 729 730 case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL: 731 s = state.l.LookupOrCreateCgoExport(name, state.localSymVersion) 732 bld = makeUpdater(state.l, bld, s) 733 bld.SetDuplicateOK(true) 734 735 default: 736 return nil, 0, fmt.Errorf("%s: invalid symbol binding %d", symname, pesym.StorageClass) 737 } 738 } 739 740 if s != 0 && state.l.SymType(s) == 0 && (pesym.StorageClass != IMAGE_SYM_CLASS_STATIC || pesym.Value != 0) { 741 bld = makeUpdater(state.l, bld, s) 742 bld.SetType(sym.SXREF) 743 } 744 745 return bld, s, nil 746 } 747 748 // preprocessSymbols walks the COFF symbols for the PE file we're 749 // reading and looks for cases where we have both a symbol definition 750 // for "XXX" and an "__imp_XXX" symbol, recording these cases in a map 751 // in the state struct. This information will be used in readpesym() 752 // above to give such symbols special treatment. This function also 753 // gathers information about COMDAT sections/symbols for later use 754 // in readpesym(). 755 func (state *peLoaderState) preprocessSymbols() error { 756 757 // Locate comdat sections. 758 state.comdats = make(map[uint16]int64) 759 for i, s := range state.f.Sections { 760 if s.Characteristics&uint32(pe.IMAGE_SCN_LNK_COMDAT) != 0 { 761 state.comdats[uint16(i)] = int64(s.Size) 762 } 763 } 764 765 // Examine symbol defs. 766 for i, numaux := 0, 0; i < len(state.f.COFFSymbols); i += numaux + 1 { 767 pesym := &state.f.COFFSymbols[i] 768 numaux = int(pesym.NumberOfAuxSymbols) 769 if pesym.SectionNumber == 0 { // extern 770 continue 771 } 772 symname, err := pesym.FullName(state.f.StringTable) 773 if err != nil { 774 return err 775 } 776 if _, isc := state.comdats[uint16(pesym.SectionNumber-1)]; !isc { 777 continue 778 } 779 if pesym.StorageClass != uint8(IMAGE_SYM_CLASS_STATIC) { 780 continue 781 } 782 // This symbol corresponds to a COMDAT section. Read the 783 // aux data for it. 784 auxsymp, err := state.f.COFFSymbolReadSectionDefAux(i) 785 if err != nil { 786 return fmt.Errorf("unable to read aux info for section def symbol %d %s: pe.COFFSymbolReadComdatInfo returns %v", i, symname, err) 787 } 788 if auxsymp.Selection == pe.IMAGE_COMDAT_SELECT_SAME_SIZE { 789 // This is supported. 790 } else if auxsymp.Selection == pe.IMAGE_COMDAT_SELECT_ANY { 791 // Also supported. 792 state.comdats[uint16(pesym.SectionNumber-1)] = int64(-1) 793 } else { 794 // We don't support any of the other strategies at the 795 // moment. I suspect that we may need to also support 796 // "associative", we'll see. 797 return fmt.Errorf("internal error: unsupported COMDAT selection strategy found in path=%s sec=%d strategy=%d idx=%d, please file a bug", state.pn, auxsymp.SecNum, auxsymp.Selection, i) 798 } 799 } 800 return nil 801 } 802 803 // LookupBaseFromImport examines the symbol "s" to see if it 804 // corresponds to an import symbol (name of the form "__imp_XYZ") and 805 // if so, it looks up the underlying target of the import symbol and 806 // returns it. An error is returned if the symbol is of the form 807 // "__imp_XYZ" but no XYZ can be found. 808 func LookupBaseFromImport(s loader.Sym, ldr *loader.Loader, arch *sys.Arch) (loader.Sym, error) { 809 sname := ldr.SymName(s) 810 if !strings.HasPrefix(sname, "__imp_") { 811 return 0, nil 812 } 813 basename := sname[len("__imp_"):] 814 if arch.Family == sys.I386 && basename[0] == '_' { 815 basename = basename[1:] // _Name => Name 816 } 817 isym := ldr.Lookup(basename, 0) 818 if isym == 0 { 819 return 0, fmt.Errorf("internal error: import symbol %q with no underlying sym", sname) 820 } 821 return isym, nil 822 }