github.com/bir3/gocompiler@v0.3.205/src/cmd/link/internal/ld/pe.go (about) 1 // Copyright 2009 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 // PE (Portable Executable) file writing 6 // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format 7 8 package ld 9 10 import ( 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 "fmt" 18 "github.com/bir3/gocompiler/src/internal/buildcfg" 19 "sort" 20 "strconv" 21 "strings" 22 ) 23 24 type IMAGE_IMPORT_DESCRIPTOR struct { 25 OriginalFirstThunk uint32 26 TimeDateStamp uint32 27 ForwarderChain uint32 28 Name uint32 29 FirstThunk uint32 30 } 31 32 type IMAGE_EXPORT_DIRECTORY struct { 33 Characteristics uint32 34 TimeDateStamp uint32 35 MajorVersion uint16 36 MinorVersion uint16 37 Name uint32 38 Base uint32 39 NumberOfFunctions uint32 40 NumberOfNames uint32 41 AddressOfFunctions uint32 42 AddressOfNames uint32 43 AddressOfNameOrdinals uint32 44 } 45 46 var ( 47 // PEBASE is the base address for the executable. 48 // It is small for 32-bit and large for 64-bit. 49 PEBASE int64 50 51 // SectionAlignment must be greater than or equal to FileAlignment. 52 // The default is the page size for the architecture. 53 PESECTALIGN int64 = 0x1000 54 55 // FileAlignment should be a power of 2 between 512 and 64 K, inclusive. 56 // The default is 512. If the SectionAlignment is less than 57 // the architecture's page size, then FileAlignment must match SectionAlignment. 58 PEFILEALIGN int64 = 2 << 8 59 ) 60 61 const ( 62 IMAGE_SCN_CNT_CODE = 0x00000020 63 IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 64 IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 65 IMAGE_SCN_LNK_OTHER = 0x00000100 66 IMAGE_SCN_LNK_INFO = 0x00000200 67 IMAGE_SCN_LNK_REMOVE = 0x00000800 68 IMAGE_SCN_LNK_COMDAT = 0x00001000 69 IMAGE_SCN_GPREL = 0x00008000 70 IMAGE_SCN_MEM_PURGEABLE = 0x00020000 71 IMAGE_SCN_MEM_16BIT = 0x00020000 72 IMAGE_SCN_MEM_LOCKED = 0x00040000 73 IMAGE_SCN_MEM_PRELOAD = 0x00080000 74 IMAGE_SCN_ALIGN_1BYTES = 0x00100000 75 IMAGE_SCN_ALIGN_2BYTES = 0x00200000 76 IMAGE_SCN_ALIGN_4BYTES = 0x00300000 77 IMAGE_SCN_ALIGN_8BYTES = 0x00400000 78 IMAGE_SCN_ALIGN_16BYTES = 0x00500000 79 IMAGE_SCN_ALIGN_32BYTES = 0x00600000 80 IMAGE_SCN_ALIGN_64BYTES = 0x00700000 81 IMAGE_SCN_ALIGN_128BYTES = 0x00800000 82 IMAGE_SCN_ALIGN_256BYTES = 0x00900000 83 IMAGE_SCN_ALIGN_512BYTES = 0x00A00000 84 IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000 85 IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000 86 IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000 87 IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000 88 IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000 89 IMAGE_SCN_MEM_DISCARDABLE = 0x02000000 90 IMAGE_SCN_MEM_NOT_CACHED = 0x04000000 91 IMAGE_SCN_MEM_NOT_PAGED = 0x08000000 92 IMAGE_SCN_MEM_SHARED = 0x10000000 93 IMAGE_SCN_MEM_EXECUTE = 0x20000000 94 IMAGE_SCN_MEM_READ = 0x40000000 95 IMAGE_SCN_MEM_WRITE = 0x80000000 96 ) 97 98 // See https://docs.microsoft.com/en-us/windows/win32/debug/pe-format. 99 // TODO(crawshaw): add these constants to debug/pe. 100 const ( 101 // TODO: the Microsoft doco says IMAGE_SYM_DTYPE_ARRAY is 3 and IMAGE_SYM_DTYPE_FUNCTION is 2 102 IMAGE_SYM_TYPE_NULL = 0 103 IMAGE_SYM_TYPE_STRUCT = 8 104 IMAGE_SYM_DTYPE_FUNCTION = 0x20 105 IMAGE_SYM_DTYPE_ARRAY = 0x30 106 IMAGE_SYM_CLASS_EXTERNAL = 2 107 IMAGE_SYM_CLASS_STATIC = 3 108 109 IMAGE_REL_I386_DIR32 = 0x0006 110 IMAGE_REL_I386_SECREL = 0x000B 111 IMAGE_REL_I386_REL32 = 0x0014 112 113 IMAGE_REL_AMD64_ADDR64 = 0x0001 114 IMAGE_REL_AMD64_ADDR32 = 0x0002 115 IMAGE_REL_AMD64_REL32 = 0x0004 116 IMAGE_REL_AMD64_SECREL = 0x000B 117 118 IMAGE_REL_ARM_ABSOLUTE = 0x0000 119 IMAGE_REL_ARM_ADDR32 = 0x0001 120 IMAGE_REL_ARM_ADDR32NB = 0x0002 121 IMAGE_REL_ARM_BRANCH24 = 0x0003 122 IMAGE_REL_ARM_BRANCH11 = 0x0004 123 IMAGE_REL_ARM_SECREL = 0x000F 124 125 IMAGE_REL_ARM64_ABSOLUTE = 0x0000 126 IMAGE_REL_ARM64_ADDR32 = 0x0001 127 IMAGE_REL_ARM64_ADDR32NB = 0x0002 128 IMAGE_REL_ARM64_BRANCH26 = 0x0003 129 IMAGE_REL_ARM64_PAGEBASE_REL21 = 0x0004 130 IMAGE_REL_ARM64_REL21 = 0x0005 131 IMAGE_REL_ARM64_PAGEOFFSET_12A = 0x0006 132 IMAGE_REL_ARM64_PAGEOFFSET_12L = 0x0007 133 IMAGE_REL_ARM64_SECREL = 0x0008 134 IMAGE_REL_ARM64_SECREL_LOW12A = 0x0009 135 IMAGE_REL_ARM64_SECREL_HIGH12A = 0x000A 136 IMAGE_REL_ARM64_SECREL_LOW12L = 0x000B 137 IMAGE_REL_ARM64_TOKEN = 0x000C 138 IMAGE_REL_ARM64_SECTION = 0x000D 139 IMAGE_REL_ARM64_ADDR64 = 0x000E 140 IMAGE_REL_ARM64_BRANCH19 = 0x000F 141 IMAGE_REL_ARM64_BRANCH14 = 0x0010 142 IMAGE_REL_ARM64_REL32 = 0x0011 143 144 IMAGE_REL_BASED_HIGHLOW = 3 145 IMAGE_REL_BASED_DIR64 = 10 146 ) 147 148 const ( 149 PeMinimumTargetMajorVersion = 6 150 PeMinimumTargetMinorVersion = 1 151 ) 152 153 // DOS stub that prints out 154 // "This program cannot be run in DOS mode." 155 var dosstub = []uint8{ 156 0x4d, 157 0x5a, 158 0x90, 159 0x00, 160 0x03, 161 0x00, 162 0x04, 163 0x00, 164 0x00, 165 0x00, 166 0x00, 167 0x00, 168 0xff, 169 0xff, 170 0x00, 171 0x00, 172 0x8b, 173 0x00, 174 0x00, 175 0x00, 176 0x00, 177 0x00, 178 0x00, 179 0x00, 180 0x40, 181 0x00, 182 0x00, 183 0x00, 184 0x00, 185 0x00, 186 0x00, 187 0x00, 188 0x00, 189 0x00, 190 0x00, 191 0x00, 192 0x00, 193 0x00, 194 0x00, 195 0x00, 196 0x00, 197 0x00, 198 0x00, 199 0x00, 200 0x00, 201 0x00, 202 0x00, 203 0x00, 204 0x00, 205 0x00, 206 0x00, 207 0x00, 208 0x00, 209 0x00, 210 0x00, 211 0x00, 212 0x00, 213 0x00, 214 0x00, 215 0x00, 216 0x80, 217 0x00, 218 0x00, 219 0x00, 220 0x0e, 221 0x1f, 222 0xba, 223 0x0e, 224 0x00, 225 0xb4, 226 0x09, 227 0xcd, 228 0x21, 229 0xb8, 230 0x01, 231 0x4c, 232 0xcd, 233 0x21, 234 0x54, 235 0x68, 236 0x69, 237 0x73, 238 0x20, 239 0x70, 240 0x72, 241 0x6f, 242 0x67, 243 0x72, 244 0x61, 245 0x6d, 246 0x20, 247 0x63, 248 0x61, 249 0x6e, 250 0x6e, 251 0x6f, 252 0x74, 253 0x20, 254 0x62, 255 0x65, 256 0x20, 257 0x72, 258 0x75, 259 0x6e, 260 0x20, 261 0x69, 262 0x6e, 263 0x20, 264 0x44, 265 0x4f, 266 0x53, 267 0x20, 268 0x6d, 269 0x6f, 270 0x64, 271 0x65, 272 0x2e, 273 0x0d, 274 0x0d, 275 0x0a, 276 0x24, 277 0x00, 278 0x00, 279 0x00, 280 0x00, 281 0x00, 282 0x00, 283 0x00, 284 } 285 286 type Imp struct { 287 s loader.Sym 288 off uint64 289 next *Imp 290 argsize int 291 } 292 293 type Dll struct { 294 name string 295 nameoff uint64 296 thunkoff uint64 297 ms *Imp 298 next *Dll 299 } 300 301 var ( 302 rsrcsyms []loader.Sym 303 PESECTHEADR int32 304 PEFILEHEADR int32 305 pe64 int 306 dr *Dll 307 308 dexport = make([]loader.Sym, 0, 1024) 309 ) 310 311 // peStringTable is a COFF string table. 312 type peStringTable struct { 313 strings []string 314 stringsLen int 315 } 316 317 // size returns size of string table t. 318 func (t *peStringTable) size() int { 319 // string table starts with 4-byte length at the beginning 320 return t.stringsLen + 4 321 } 322 323 // add adds string str to string table t. 324 func (t *peStringTable) add(str string) int { 325 off := t.size() 326 t.strings = append(t.strings, str) 327 t.stringsLen += len(str) + 1 // each string will have 0 appended to it 328 return off 329 } 330 331 // write writes string table t into the output file. 332 func (t *peStringTable) write(out *OutBuf) { 333 out.Write32(uint32(t.size())) 334 for _, s := range t.strings { 335 out.WriteString(s) 336 out.Write8(0) 337 } 338 } 339 340 // peSection represents section from COFF section table. 341 type peSection struct { 342 name string 343 shortName string 344 index int // one-based index into the Section Table 345 virtualSize uint32 346 virtualAddress uint32 347 sizeOfRawData uint32 348 pointerToRawData uint32 349 pointerToRelocations uint32 350 numberOfRelocations uint16 351 characteristics uint32 352 } 353 354 // checkOffset verifies COFF section sect offset in the file. 355 func (sect *peSection) checkOffset(off int64) { 356 if off != int64(sect.pointerToRawData) { 357 Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(off)) 358 errorexit() 359 } 360 } 361 362 // checkSegment verifies COFF section sect matches address 363 // and file offset provided in segment seg. 364 func (sect *peSection) checkSegment(seg *sym.Segment) { 365 if seg.Vaddr-uint64(PEBASE) != uint64(sect.virtualAddress) { 366 Errorf(nil, "%s.VirtualAddress = %#x, want %#x", sect.name, uint64(int64(sect.virtualAddress)), uint64(int64(seg.Vaddr-uint64(PEBASE)))) 367 errorexit() 368 } 369 if seg.Fileoff != uint64(sect.pointerToRawData) { 370 Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(int64(seg.Fileoff))) 371 errorexit() 372 } 373 } 374 375 // pad adds zeros to the section sect. It writes as many bytes 376 // as necessary to make section sect.SizeOfRawData bytes long. 377 // It assumes that n bytes are already written to the file. 378 func (sect *peSection) pad(out *OutBuf, n uint32) { 379 out.WriteStringN("", int(sect.sizeOfRawData-n)) 380 } 381 382 // write writes COFF section sect into the output file. 383 func (sect *peSection) write(out *OutBuf, linkmode LinkMode) error { 384 h := pe.SectionHeader32{ 385 VirtualSize: sect.virtualSize, 386 SizeOfRawData: sect.sizeOfRawData, 387 PointerToRawData: sect.pointerToRawData, 388 PointerToRelocations: sect.pointerToRelocations, 389 NumberOfRelocations: sect.numberOfRelocations, 390 Characteristics: sect.characteristics, 391 } 392 if linkmode != LinkExternal { 393 h.VirtualAddress = sect.virtualAddress 394 } 395 copy(h.Name[:], sect.shortName) 396 return binary.Write(out, binary.LittleEndian, h) 397 } 398 399 // emitRelocations emits the relocation entries for the sect. 400 // The actual relocations are emitted by relocfn. 401 // This updates the corresponding PE section table entry 402 // with the relocation offset and count. 403 func (sect *peSection) emitRelocations(out *OutBuf, relocfn func() int) { 404 sect.pointerToRelocations = uint32(out.Offset()) 405 // first entry: extended relocs 406 out.Write32(0) // placeholder for number of relocation + 1 407 out.Write32(0) 408 out.Write16(0) 409 410 n := relocfn() + 1 411 412 cpos := out.Offset() 413 out.SeekSet(int64(sect.pointerToRelocations)) 414 out.Write32(uint32(n)) 415 out.SeekSet(cpos) 416 if n > 0x10000 { 417 n = 0x10000 418 sect.characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL 419 } else { 420 sect.pointerToRelocations += 10 // skip the extend reloc entry 421 } 422 sect.numberOfRelocations = uint16(n - 1) 423 } 424 425 // peFile is used to build COFF file. 426 type peFile struct { 427 sections []*peSection 428 stringTable peStringTable 429 textSect *peSection 430 rdataSect *peSection 431 dataSect *peSection 432 bssSect *peSection 433 ctorsSect *peSection 434 nextSectOffset uint32 435 nextFileOffset uint32 436 symtabOffset int64 // offset to the start of symbol table 437 symbolCount int // number of symbol table records written 438 dataDirectory [16]pe.DataDirectory 439 } 440 441 // addSection adds section to the COFF file f. 442 func (f *peFile) addSection(name string, sectsize int, filesize int) *peSection { 443 sect := &peSection{ 444 name: name, 445 shortName: name, 446 index: len(f.sections) + 1, 447 virtualAddress: f.nextSectOffset, 448 pointerToRawData: f.nextFileOffset, 449 } 450 f.nextSectOffset = uint32(Rnd(int64(f.nextSectOffset)+int64(sectsize), PESECTALIGN)) 451 if filesize > 0 { 452 sect.virtualSize = uint32(sectsize) 453 sect.sizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN)) 454 f.nextFileOffset += sect.sizeOfRawData 455 } else { 456 sect.sizeOfRawData = uint32(sectsize) 457 } 458 f.sections = append(f.sections, sect) 459 return sect 460 } 461 462 // addDWARFSection adds DWARF section to the COFF file f. 463 // This function is similar to addSection, but DWARF section names are 464 // longer than 8 characters, so they need to be stored in the string table. 465 func (f *peFile) addDWARFSection(name string, size int) *peSection { 466 if size == 0 { 467 Exitf("DWARF section %q is empty", name) 468 } 469 // DWARF section names are longer than 8 characters. 470 // PE format requires such names to be stored in string table, 471 // and section names replaced with slash (/) followed by 472 // correspondent string table index. 473 // see http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx 474 // for details 475 off := f.stringTable.add(name) 476 h := f.addSection(name, size, size) 477 h.shortName = fmt.Sprintf("/%d", off) 478 h.characteristics = IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA 479 return h 480 } 481 482 // addDWARF adds DWARF information to the COFF file f. 483 func (f *peFile) addDWARF() { 484 if *FlagS { // disable symbol table 485 return 486 } 487 if *FlagW { // disable dwarf 488 return 489 } 490 for _, sect := range Segdwarf.Sections { 491 h := f.addDWARFSection(sect.Name, int(sect.Length)) 492 fileoff := sect.Vaddr - Segdwarf.Vaddr + Segdwarf.Fileoff 493 if uint64(h.pointerToRawData) != fileoff { 494 Exitf("%s.PointerToRawData = %#x, want %#x", sect.Name, h.pointerToRawData, fileoff) 495 } 496 } 497 } 498 499 // addInitArray adds .ctors COFF section to the file f. 500 func (f *peFile) addInitArray(ctxt *Link) *peSection { 501 // The size below was determined by the specification for array relocations, 502 // and by observing what GCC writes here. If the initarray section grows to 503 // contain more than one constructor entry, the size will need to be 8 * constructor_count. 504 // However, the entire Go runtime is initialized from just one function, so it is unlikely 505 // that this will need to grow in the future. 506 var size int 507 var alignment uint32 508 switch buildcfg.GOARCH { 509 default: 510 Exitf("peFile.addInitArray: unsupported GOARCH=%q\n", buildcfg.GOARCH) 511 case "386", "arm": 512 size = 4 513 alignment = IMAGE_SCN_ALIGN_4BYTES 514 case "amd64", "arm64": 515 size = 8 516 alignment = IMAGE_SCN_ALIGN_8BYTES 517 } 518 sect := f.addSection(".ctors", size, size) 519 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | alignment 520 sect.sizeOfRawData = uint32(size) 521 ctxt.Out.SeekSet(int64(sect.pointerToRawData)) 522 sect.checkOffset(ctxt.Out.Offset()) 523 524 init_entry := ctxt.loader.Lookup(*flagEntrySymbol, 0) 525 addr := uint64(ctxt.loader.SymValue(init_entry)) - ctxt.loader.SymSect(init_entry).Vaddr 526 switch buildcfg.GOARCH { 527 case "386", "arm": 528 ctxt.Out.Write32(uint32(addr)) 529 case "amd64", "arm64": 530 ctxt.Out.Write64(addr) 531 } 532 return sect 533 } 534 535 // emitRelocations emits relocation entries for go.o in external linking. 536 func (f *peFile) emitRelocations(ctxt *Link) { 537 for ctxt.Out.Offset()&7 != 0 { 538 ctxt.Out.Write8(0) 539 } 540 541 ldr := ctxt.loader 542 543 // relocsect relocates symbols from first in section sect, and returns 544 // the total number of relocations emitted. 545 relocsect := func(sect *sym.Section, syms []loader.Sym, base uint64) int { 546 // If main section has no bits, nothing to relocate. 547 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 548 return 0 549 } 550 sect.Reloff = uint64(ctxt.Out.Offset()) 551 for i, s := range syms { 552 if !ldr.AttrReachable(s) { 553 continue 554 } 555 if uint64(ldr.SymValue(s)) >= sect.Vaddr { 556 syms = syms[i:] 557 break 558 } 559 } 560 eaddr := int64(sect.Vaddr + sect.Length) 561 for _, s := range syms { 562 if !ldr.AttrReachable(s) { 563 continue 564 } 565 if ldr.SymValue(s) >= eaddr { 566 break 567 } 568 // Compute external relocations on the go, and pass to PEreloc1 569 // to stream out. 570 relocs := ldr.Relocs(s) 571 for ri := 0; ri < relocs.Count(); ri++ { 572 r := relocs.At(ri) 573 rr, ok := extreloc(ctxt, ldr, s, r) 574 if !ok { 575 continue 576 } 577 if rr.Xsym == 0 { 578 ctxt.Errorf(s, "missing xsym in relocation") 579 continue 580 } 581 if ldr.SymDynid(rr.Xsym) < 0 { 582 ctxt.Errorf(s, "reloc %d to non-coff symbol %s (outer=%s) %d", r.Type(), ldr.SymName(r.Sym()), ldr.SymName(rr.Xsym), ldr.SymType(r.Sym())) 583 } 584 if !thearch.PEreloc1(ctxt.Arch, ctxt.Out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-base)) { 585 ctxt.Errorf(s, "unsupported obj reloc %v/%d to %s", r.Type(), r.Siz(), ldr.SymName(r.Sym())) 586 } 587 } 588 } 589 sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff 590 const relocLen = 4 + 4 + 2 591 return int(sect.Rellen / relocLen) 592 } 593 594 sects := []struct { 595 peSect *peSection 596 seg *sym.Segment 597 syms []loader.Sym 598 }{ 599 {f.textSect, &Segtext, ctxt.Textp}, 600 {f.rdataSect, &Segrodata, ctxt.datap}, 601 {f.dataSect, &Segdata, ctxt.datap}, 602 } 603 for _, s := range sects { 604 s.peSect.emitRelocations(ctxt.Out, func() int { 605 var n int 606 for _, sect := range s.seg.Sections { 607 n += relocsect(sect, s.syms, s.seg.Vaddr) 608 } 609 return n 610 }) 611 } 612 613 dwarfLoop: 614 for i := 0; i < len(Segdwarf.Sections); i++ { 615 sect := Segdwarf.Sections[i] 616 si := dwarfp[i] 617 if si.secSym() != loader.Sym(sect.Sym) || 618 ldr.SymSect(si.secSym()) != sect { 619 panic("inconsistency between dwarfp and Segdwarf") 620 } 621 for _, pesect := range f.sections { 622 if sect.Name == pesect.name { 623 pesect.emitRelocations(ctxt.Out, func() int { 624 return relocsect(sect, si.syms, sect.Vaddr) 625 }) 626 continue dwarfLoop 627 } 628 } 629 Errorf(nil, "emitRelocations: could not find %q section", sect.Name) 630 } 631 632 if f.ctorsSect == nil { 633 return 634 } 635 636 f.ctorsSect.emitRelocations(ctxt.Out, func() int { 637 dottext := ldr.Lookup(".text", 0) 638 ctxt.Out.Write32(0) 639 ctxt.Out.Write32(uint32(ldr.SymDynid(dottext))) 640 switch buildcfg.GOARCH { 641 default: 642 ctxt.Errorf(dottext, "unknown architecture for PE: %q\n", buildcfg.GOARCH) 643 case "386": 644 ctxt.Out.Write16(IMAGE_REL_I386_DIR32) 645 case "amd64": 646 ctxt.Out.Write16(IMAGE_REL_AMD64_ADDR64) 647 case "arm": 648 ctxt.Out.Write16(IMAGE_REL_ARM_ADDR32) 649 case "arm64": 650 ctxt.Out.Write16(IMAGE_REL_ARM64_ADDR64) 651 } 652 return 1 653 }) 654 } 655 656 // writeSymbol appends symbol s to file f symbol table. 657 // It also sets s.Dynid to written symbol number. 658 func (f *peFile) writeSymbol(out *OutBuf, ldr *loader.Loader, s loader.Sym, name string, value int64, sectidx int, typ uint16, class uint8) { 659 if len(name) > 8 { 660 out.Write32(0) 661 out.Write32(uint32(f.stringTable.add(name))) 662 } else { 663 out.WriteStringN(name, 8) 664 } 665 out.Write32(uint32(value)) 666 out.Write16(uint16(sectidx)) 667 out.Write16(typ) 668 out.Write8(class) 669 out.Write8(0) // no aux entries 670 671 ldr.SetSymDynid(s, int32(f.symbolCount)) 672 673 f.symbolCount++ 674 } 675 676 // mapToPESection searches peFile f for s symbol's location. 677 // It returns PE section index, and offset within that section. 678 func (f *peFile) mapToPESection(ldr *loader.Loader, s loader.Sym, linkmode LinkMode) (pesectidx int, offset int64, err error) { 679 sect := ldr.SymSect(s) 680 if sect == nil { 681 return 0, 0, fmt.Errorf("could not map %s symbol with no section", ldr.SymName(s)) 682 } 683 if sect.Seg == &Segtext { 684 return f.textSect.index, int64(uint64(ldr.SymValue(s)) - Segtext.Vaddr), nil 685 } 686 if sect.Seg == &Segrodata { 687 return f.rdataSect.index, int64(uint64(ldr.SymValue(s)) - Segrodata.Vaddr), nil 688 } 689 if sect.Seg != &Segdata { 690 return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .rdata or .data section", ldr.SymName(s)) 691 } 692 v := uint64(ldr.SymValue(s)) - Segdata.Vaddr 693 if linkmode != LinkExternal { 694 return f.dataSect.index, int64(v), nil 695 } 696 if ldr.SymType(s) == sym.SDATA { 697 return f.dataSect.index, int64(v), nil 698 } 699 // Note: although address of runtime.edata (type sym.SDATA) is at the start of .bss section 700 // it still belongs to the .data section, not the .bss section. 701 if v < Segdata.Filelen { 702 return f.dataSect.index, int64(v), nil 703 } 704 return f.bssSect.index, int64(v - Segdata.Filelen), nil 705 } 706 707 var isLabel = make(map[loader.Sym]bool) 708 709 func AddPELabelSym(ldr *loader.Loader, s loader.Sym) { 710 isLabel[s] = true 711 } 712 713 // writeSymbols writes all COFF symbol table records. 714 func (f *peFile) writeSymbols(ctxt *Link) { 715 ldr := ctxt.loader 716 addsym := func(s loader.Sym) { 717 t := ldr.SymType(s) 718 if ldr.SymSect(s) == nil && t != sym.SDYNIMPORT && t != sym.SHOSTOBJ && t != sym.SUNDEFEXT { 719 return 720 } 721 722 name := ldr.SymName(s) 723 724 // Only windows/386 requires underscore prefix on external symbols. 725 if ctxt.Is386() && ctxt.IsExternal() && 726 (t == sym.SHOSTOBJ || t == sym.SUNDEFEXT || ldr.AttrCgoExport(s) || 727 // TODO(cuonglm): remove this hack 728 // 729 // Previously, windows/386 requires underscore prefix on external symbols, 730 // but that's only applied for SHOSTOBJ/SUNDEFEXT or cgo export symbols. 731 // "go.buildid" is STEXT, "type.*" is STYPE, thus they are not prefixed 732 // with underscore. 733 // 734 // In external linking mode, the external linker can't resolve them as 735 // external symbols. But we are lucky that they have "." in their name, 736 // so the external linker see them as Forwarder RVA exports. See: 737 // 738 // - https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#export-address-table 739 // - https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=ld/pe-dll.c;h=e7b82ba6ffadf74dc1b9ee71dc13d48336941e51;hb=HEAD#l972) 740 // 741 // CL 317917 changes "." to ":" in symbols name, so theses symbols can not be 742 // found by external linker anymore. So a hacky way is adding the 743 // underscore prefix for these 2 symbols. I don't have enough knowledge to 744 // verify whether adding the underscore for all STEXT/STYPE symbols are 745 // fine, even if it could be, that would be done in future CL. 746 name == "go:buildid" || name == "type:*") { 747 name = "_" + name 748 } 749 750 name = mangleABIName(ctxt, ldr, s, name) 751 752 var peSymType uint16 753 if ctxt.IsExternal() { 754 peSymType = IMAGE_SYM_TYPE_NULL 755 } else { 756 // TODO: fix IMAGE_SYM_DTYPE_ARRAY value and use following expression, instead of 0x0308 757 // peSymType = IMAGE_SYM_DTYPE_ARRAY<<8 + IMAGE_SYM_TYPE_STRUCT 758 peSymType = 0x0308 // "array of structs" 759 } 760 sect, value, err := f.mapToPESection(ldr, s, ctxt.LinkMode) 761 if err != nil { 762 if t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT { 763 peSymType = IMAGE_SYM_DTYPE_FUNCTION 764 } else { 765 ctxt.Errorf(s, "addpesym: %v", err) 766 } 767 } 768 class := IMAGE_SYM_CLASS_EXTERNAL 769 if ldr.IsFileLocal(s) || ldr.AttrVisibilityHidden(s) || ldr.AttrLocal(s) { 770 class = IMAGE_SYM_CLASS_STATIC 771 } 772 f.writeSymbol(ctxt.Out, ldr, s, name, value, sect, peSymType, uint8(class)) 773 } 774 775 if ctxt.LinkMode == LinkExternal { 776 // Include section symbols as external, because 777 // .ctors and .debug_* section relocations refer to it. 778 for _, pesect := range f.sections { 779 s := ldr.LookupOrCreateSym(pesect.name, 0) 780 f.writeSymbol(ctxt.Out, ldr, s, pesect.name, 0, pesect.index, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC) 781 } 782 } 783 784 // Add special runtime.text and runtime.etext symbols. 785 s := ldr.Lookup("runtime.text", 0) 786 if ldr.SymType(s) == sym.STEXT { 787 addsym(s) 788 } 789 s = ldr.Lookup("runtime.etext", 0) 790 if ldr.SymType(s) == sym.STEXT { 791 addsym(s) 792 } 793 794 // Add text symbols. 795 for _, s := range ctxt.Textp { 796 addsym(s) 797 } 798 799 shouldBeInSymbolTable := func(s loader.Sym) bool { 800 if ldr.AttrNotInSymbolTable(s) { 801 return false 802 } 803 name := ldr.SymName(s) // TODO: try not to read the name 804 if name == "" || name[0] == '.' { 805 return false 806 } 807 return true 808 } 809 810 // Add data symbols and external references. 811 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ { 812 if !ldr.AttrReachable(s) { 813 continue 814 } 815 t := ldr.SymType(s) 816 if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata 817 if t == sym.STLSBSS { 818 continue 819 } 820 if !shouldBeInSymbolTable(s) { 821 continue 822 } 823 addsym(s) 824 } 825 826 switch t { 827 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT: 828 addsym(s) 829 default: 830 if len(isLabel) > 0 && isLabel[s] { 831 addsym(s) 832 } 833 } 834 } 835 } 836 837 // writeSymbolTableAndStringTable writes out symbol and string tables for peFile f. 838 func (f *peFile) writeSymbolTableAndStringTable(ctxt *Link) { 839 f.symtabOffset = ctxt.Out.Offset() 840 841 // write COFF symbol table 842 if !*FlagS || ctxt.LinkMode == LinkExternal { 843 f.writeSymbols(ctxt) 844 } 845 846 // update COFF file header and section table 847 size := f.stringTable.size() + 18*f.symbolCount 848 var h *peSection 849 if ctxt.LinkMode != LinkExternal { 850 // We do not really need .symtab for go.o, and if we have one, ld 851 // will also include it in the exe, and that will confuse windows. 852 h = f.addSection(".symtab", size, size) 853 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 854 h.checkOffset(f.symtabOffset) 855 } 856 857 // write COFF string table 858 f.stringTable.write(ctxt.Out) 859 if ctxt.LinkMode != LinkExternal { 860 h.pad(ctxt.Out, uint32(size)) 861 } 862 } 863 864 // writeFileHeader writes COFF file header for peFile f. 865 func (f *peFile) writeFileHeader(ctxt *Link) { 866 var fh pe.FileHeader 867 868 switch ctxt.Arch.Family { 869 default: 870 Exitf("unknown PE architecture: %v", ctxt.Arch.Family) 871 case sys.AMD64: 872 fh.Machine = pe.IMAGE_FILE_MACHINE_AMD64 873 case sys.I386: 874 fh.Machine = pe.IMAGE_FILE_MACHINE_I386 875 case sys.ARM: 876 fh.Machine = pe.IMAGE_FILE_MACHINE_ARMNT 877 case sys.ARM64: 878 fh.Machine = pe.IMAGE_FILE_MACHINE_ARM64 879 } 880 881 fh.NumberOfSections = uint16(len(f.sections)) 882 883 // Being able to produce identical output for identical input is 884 // much more beneficial than having build timestamp in the header. 885 fh.TimeDateStamp = 0 886 887 if ctxt.LinkMode == LinkExternal { 888 fh.Characteristics = pe.IMAGE_FILE_LINE_NUMS_STRIPPED 889 } else { 890 fh.Characteristics = pe.IMAGE_FILE_EXECUTABLE_IMAGE | pe.IMAGE_FILE_DEBUG_STRIPPED 891 switch ctxt.Arch.Family { 892 case sys.AMD64, sys.I386: 893 if ctxt.BuildMode != BuildModePIE { 894 fh.Characteristics |= pe.IMAGE_FILE_RELOCS_STRIPPED 895 } 896 } 897 } 898 if pe64 != 0 { 899 var oh64 pe.OptionalHeader64 900 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64)) 901 fh.Characteristics |= pe.IMAGE_FILE_LARGE_ADDRESS_AWARE 902 } else { 903 var oh pe.OptionalHeader32 904 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh)) 905 fh.Characteristics |= pe.IMAGE_FILE_32BIT_MACHINE 906 } 907 908 fh.PointerToSymbolTable = uint32(f.symtabOffset) 909 fh.NumberOfSymbols = uint32(f.symbolCount) 910 911 binary.Write(ctxt.Out, binary.LittleEndian, &fh) 912 } 913 914 // writeOptionalHeader writes COFF optional header for peFile f. 915 func (f *peFile) writeOptionalHeader(ctxt *Link) { 916 var oh pe.OptionalHeader32 917 var oh64 pe.OptionalHeader64 918 919 if pe64 != 0 { 920 oh64.Magic = 0x20b // PE32+ 921 } else { 922 oh.Magic = 0x10b // PE32 923 oh.BaseOfData = f.dataSect.virtualAddress 924 } 925 926 // Fill out both oh64 and oh. We only use one. Oh well. 927 oh64.MajorLinkerVersion = 3 928 oh.MajorLinkerVersion = 3 929 oh64.MinorLinkerVersion = 0 930 oh.MinorLinkerVersion = 0 931 oh64.SizeOfCode = f.textSect.sizeOfRawData 932 oh.SizeOfCode = f.textSect.sizeOfRawData 933 oh64.SizeOfInitializedData = f.dataSect.sizeOfRawData 934 oh.SizeOfInitializedData = f.dataSect.sizeOfRawData 935 oh64.SizeOfUninitializedData = 0 936 oh.SizeOfUninitializedData = 0 937 if ctxt.LinkMode != LinkExternal { 938 oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 939 oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 940 } 941 oh64.BaseOfCode = f.textSect.virtualAddress 942 oh.BaseOfCode = f.textSect.virtualAddress 943 oh64.ImageBase = uint64(PEBASE) 944 oh.ImageBase = uint32(PEBASE) 945 oh64.SectionAlignment = uint32(PESECTALIGN) 946 oh.SectionAlignment = uint32(PESECTALIGN) 947 oh64.FileAlignment = uint32(PEFILEALIGN) 948 oh.FileAlignment = uint32(PEFILEALIGN) 949 oh64.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion 950 oh.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion 951 oh64.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion 952 oh.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion 953 oh64.MajorImageVersion = 1 954 oh.MajorImageVersion = 1 955 oh64.MinorImageVersion = 0 956 oh.MinorImageVersion = 0 957 oh64.MajorSubsystemVersion = PeMinimumTargetMajorVersion 958 oh.MajorSubsystemVersion = PeMinimumTargetMajorVersion 959 oh64.MinorSubsystemVersion = PeMinimumTargetMinorVersion 960 oh.MinorSubsystemVersion = PeMinimumTargetMinorVersion 961 oh64.SizeOfImage = f.nextSectOffset 962 oh.SizeOfImage = f.nextSectOffset 963 oh64.SizeOfHeaders = uint32(PEFILEHEADR) 964 oh.SizeOfHeaders = uint32(PEFILEHEADR) 965 if windowsgui { 966 oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI 967 oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI 968 } else { 969 oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI 970 oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI 971 } 972 973 // Mark as having awareness of terminal services, to avoid ancient compatibility hacks. 974 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 975 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 976 977 // Enable DEP 978 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT 979 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT 980 981 // The DLL can be relocated at load time. 982 if needPEBaseReloc(ctxt) { 983 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 984 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 985 } 986 987 // Image can handle a high entropy 64-bit virtual address space. 988 if ctxt.BuildMode == BuildModePIE { 989 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 990 } 991 992 // Disable stack growth as we don't want Windows to 993 // fiddle with the thread stack limits, which we set 994 // ourselves to circumvent the stack checks in the 995 // Windows exception dispatcher. 996 // Commit size must be strictly less than reserve 997 // size otherwise reserve will be rounded up to a 998 // larger size, as verified with VMMap. 999 1000 // On 64-bit, we always reserve 2MB stacks. "Pure" Go code is 1001 // okay with much smaller stacks, but the syscall package 1002 // makes it easy to call into arbitrary C code without cgo, 1003 // and system calls even in "pure" Go code are actually C 1004 // calls that may need more stack than we think. 1005 // 1006 // The default stack reserve size directly affects only the main 1007 // thread. 1008 // 1009 // For other threads, the runtime explicitly asks the kernel 1010 // to use the default stack size so that all stacks are 1011 // consistent. 1012 // 1013 // At thread start, in minit, the runtime queries the OS for 1014 // the actual stack bounds so that the stack size doesn't need 1015 // to be hard-coded into the runtime. 1016 oh64.SizeOfStackReserve = 0x00200000 1017 if !iscgo { 1018 oh64.SizeOfStackCommit = 0x00001000 1019 } else { 1020 // TODO(brainman): Maybe remove optional header writing altogether for cgo. 1021 // For cgo it is the external linker that is building final executable. 1022 // And it probably does not use any information stored in optional header. 1023 oh64.SizeOfStackCommit = 0x00200000 - 0x2000 // account for 2 guard pages 1024 } 1025 1026 oh.SizeOfStackReserve = 0x00100000 1027 if !iscgo { 1028 oh.SizeOfStackCommit = 0x00001000 1029 } else { 1030 oh.SizeOfStackCommit = 0x00100000 - 0x2000 // account for 2 guard pages 1031 } 1032 1033 oh64.SizeOfHeapReserve = 0x00100000 1034 oh.SizeOfHeapReserve = 0x00100000 1035 oh64.SizeOfHeapCommit = 0x00001000 1036 oh.SizeOfHeapCommit = 0x00001000 1037 oh64.NumberOfRvaAndSizes = 16 1038 oh.NumberOfRvaAndSizes = 16 1039 1040 if pe64 != 0 { 1041 oh64.DataDirectory = f.dataDirectory 1042 } else { 1043 oh.DataDirectory = f.dataDirectory 1044 } 1045 1046 if pe64 != 0 { 1047 binary.Write(ctxt.Out, binary.LittleEndian, &oh64) 1048 } else { 1049 binary.Write(ctxt.Out, binary.LittleEndian, &oh) 1050 } 1051 } 1052 1053 var pefile peFile 1054 1055 func Peinit(ctxt *Link) { 1056 var l int 1057 1058 if ctxt.Arch.PtrSize == 8 { 1059 // 64-bit architectures 1060 pe64 = 1 1061 PEBASE = 1 << 32 1062 if ctxt.Arch.Family == sys.AMD64 { 1063 // TODO(rsc): For cgo we currently use 32-bit relocations 1064 // that fail when PEBASE is too large. 1065 // We need to fix this, but for now, use a smaller PEBASE. 1066 PEBASE = 1 << 22 1067 } 1068 var oh64 pe.OptionalHeader64 1069 l = binary.Size(&oh64) 1070 } else { 1071 // 32-bit architectures 1072 PEBASE = 1 << 22 1073 var oh pe.OptionalHeader32 1074 l = binary.Size(&oh) 1075 } 1076 1077 if ctxt.LinkMode == LinkExternal { 1078 // .rdata section will contain "masks" and "shifts" symbols, and they 1079 // need to be aligned to 16-bytes. So make all sections aligned 1080 // to 32-byte and mark them all IMAGE_SCN_ALIGN_32BYTES so external 1081 // linker will honour that requirement. 1082 PESECTALIGN = 32 1083 PEFILEALIGN = 0 1084 // We are creating an object file. The absolute address is irrelevant. 1085 PEBASE = 0 1086 } 1087 1088 var sh [16]pe.SectionHeader32 1089 var fh pe.FileHeader 1090 PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN)) 1091 if ctxt.LinkMode != LinkExternal { 1092 PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN)) 1093 } else { 1094 PESECTHEADR = 0 1095 } 1096 pefile.nextSectOffset = uint32(PESECTHEADR) 1097 pefile.nextFileOffset = uint32(PEFILEHEADR) 1098 1099 if ctxt.LinkMode == LinkInternal { 1100 // some mingw libs depend on this symbol, for example, FindPESectionByName 1101 for _, name := range [2]string{"__image_base__", "_image_base__"} { 1102 sb := ctxt.loader.CreateSymForUpdate(name, 0) 1103 sb.SetType(sym.SDATA) 1104 sb.SetValue(PEBASE) 1105 ctxt.loader.SetAttrSpecial(sb.Sym(), true) 1106 ctxt.loader.SetAttrLocal(sb.Sym(), true) 1107 } 1108 } 1109 1110 HEADR = PEFILEHEADR 1111 if *FlagTextAddr == -1 { 1112 *FlagTextAddr = PEBASE + int64(PESECTHEADR) 1113 } 1114 if *FlagRound == -1 { 1115 *FlagRound = int(PESECTALIGN) 1116 } 1117 } 1118 1119 func pewrite(ctxt *Link) { 1120 ctxt.Out.SeekSet(0) 1121 if ctxt.LinkMode != LinkExternal { 1122 ctxt.Out.Write(dosstub) 1123 ctxt.Out.WriteStringN("PE", 4) 1124 } 1125 1126 pefile.writeFileHeader(ctxt) 1127 1128 pefile.writeOptionalHeader(ctxt) 1129 1130 for _, sect := range pefile.sections { 1131 sect.write(ctxt.Out, ctxt.LinkMode) 1132 } 1133 } 1134 1135 func strput(out *OutBuf, s string) { 1136 out.WriteString(s) 1137 out.Write8(0) 1138 // string must be padded to even size 1139 if (len(s)+1)%2 != 0 { 1140 out.Write8(0) 1141 } 1142 } 1143 1144 func initdynimport(ctxt *Link) *Dll { 1145 ldr := ctxt.loader 1146 var d *Dll 1147 1148 dr = nil 1149 var m *Imp 1150 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ { 1151 if !ldr.AttrReachable(s) || ldr.SymType(s) != sym.SDYNIMPORT { 1152 continue 1153 } 1154 dynlib := ldr.SymDynimplib(s) 1155 for d = dr; d != nil; d = d.next { 1156 if d.name == dynlib { 1157 m = new(Imp) 1158 break 1159 } 1160 } 1161 1162 if d == nil { 1163 d = new(Dll) 1164 d.name = dynlib 1165 d.next = dr 1166 dr = d 1167 m = new(Imp) 1168 } 1169 1170 // Because external link requires properly stdcall decorated name, 1171 // all external symbols in runtime use %n to denote that the number 1172 // of uinptrs this function consumes. Store the argsize and discard 1173 // the %n suffix if any. 1174 m.argsize = -1 1175 extName := ldr.SymExtname(s) 1176 if i := strings.IndexByte(extName, '%'); i >= 0 { 1177 var err error 1178 m.argsize, err = strconv.Atoi(extName[i+1:]) 1179 if err != nil { 1180 ctxt.Errorf(s, "failed to parse stdcall decoration: %v", err) 1181 } 1182 m.argsize *= ctxt.Arch.PtrSize 1183 ldr.SetSymExtname(s, extName[:i]) 1184 } 1185 1186 m.s = s 1187 m.next = d.ms 1188 d.ms = m 1189 } 1190 1191 if ctxt.IsExternal() { 1192 // Add real symbol name 1193 for d := dr; d != nil; d = d.next { 1194 for m = d.ms; m != nil; m = m.next { 1195 sb := ldr.MakeSymbolUpdater(m.s) 1196 sb.SetType(sym.SDATA) 1197 sb.Grow(int64(ctxt.Arch.PtrSize)) 1198 dynName := sb.Extname() 1199 // only windows/386 requires stdcall decoration 1200 if ctxt.Is386() && m.argsize >= 0 { 1201 dynName += fmt.Sprintf("@%d", m.argsize) 1202 } 1203 dynSym := ldr.CreateSymForUpdate(dynName, 0) 1204 dynSym.SetType(sym.SHOSTOBJ) 1205 r, _ := sb.AddRel(objabi.R_ADDR) 1206 r.SetSym(dynSym.Sym()) 1207 r.SetSiz(uint8(ctxt.Arch.PtrSize)) 1208 } 1209 } 1210 } else { 1211 dynamic := ldr.CreateSymForUpdate(".windynamic", 0) 1212 dynamic.SetType(sym.SWINDOWS) 1213 for d := dr; d != nil; d = d.next { 1214 for m = d.ms; m != nil; m = m.next { 1215 sb := ldr.MakeSymbolUpdater(m.s) 1216 sb.SetType(sym.SWINDOWS) 1217 sb.SetValue(dynamic.Size()) 1218 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize)) 1219 dynamic.AddInteriorSym(m.s) 1220 } 1221 1222 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize)) 1223 } 1224 } 1225 1226 return dr 1227 } 1228 1229 // peimporteddlls returns the gcc command line argument to link all imported 1230 // DLLs. 1231 func peimporteddlls() []string { 1232 var dlls []string 1233 1234 for d := dr; d != nil; d = d.next { 1235 dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll")) 1236 } 1237 1238 return dlls 1239 } 1240 1241 func addimports(ctxt *Link, datsect *peSection) { 1242 ldr := ctxt.loader 1243 startoff := ctxt.Out.Offset() 1244 dynamic := ldr.LookupOrCreateSym(".windynamic", 0) 1245 1246 // skip import descriptor table (will write it later) 1247 n := uint64(0) 1248 1249 for d := dr; d != nil; d = d.next { 1250 n++ 1251 } 1252 ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1)) 1253 1254 // write dll names 1255 for d := dr; d != nil; d = d.next { 1256 d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff) 1257 strput(ctxt.Out, d.name) 1258 } 1259 1260 // write function names 1261 for d := dr; d != nil; d = d.next { 1262 for m := d.ms; m != nil; m = m.next { 1263 m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff) 1264 ctxt.Out.Write16(0) // hint 1265 strput(ctxt.Out, ldr.SymExtname(m.s)) 1266 } 1267 } 1268 1269 // write OriginalFirstThunks 1270 oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff) 1271 1272 n = uint64(ctxt.Out.Offset()) 1273 for d := dr; d != nil; d = d.next { 1274 d.thunkoff = uint64(ctxt.Out.Offset()) - n 1275 for m := d.ms; m != nil; m = m.next { 1276 if pe64 != 0 { 1277 ctxt.Out.Write64(m.off) 1278 } else { 1279 ctxt.Out.Write32(uint32(m.off)) 1280 } 1281 } 1282 1283 if pe64 != 0 { 1284 ctxt.Out.Write64(0) 1285 } else { 1286 ctxt.Out.Write32(0) 1287 } 1288 } 1289 1290 // add pe section and pad it at the end 1291 n = uint64(ctxt.Out.Offset()) - uint64(startoff) 1292 1293 isect := pefile.addSection(".idata", int(n), int(n)) 1294 isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 1295 isect.checkOffset(startoff) 1296 isect.pad(ctxt.Out, uint32(n)) 1297 endoff := ctxt.Out.Offset() 1298 1299 // write FirstThunks (allocated in .data section) 1300 ftbase := uint64(ldr.SymValue(dynamic)) - uint64(datsect.virtualAddress) - uint64(PEBASE) 1301 1302 ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase)) 1303 for d := dr; d != nil; d = d.next { 1304 for m := d.ms; m != nil; m = m.next { 1305 if pe64 != 0 { 1306 ctxt.Out.Write64(m.off) 1307 } else { 1308 ctxt.Out.Write32(uint32(m.off)) 1309 } 1310 } 1311 1312 if pe64 != 0 { 1313 ctxt.Out.Write64(0) 1314 } else { 1315 ctxt.Out.Write32(0) 1316 } 1317 } 1318 1319 // finally write import descriptor table 1320 out := ctxt.Out 1321 out.SeekSet(startoff) 1322 1323 for d := dr; d != nil; d = d.next { 1324 out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff)) 1325 out.Write32(0) 1326 out.Write32(0) 1327 out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff)) 1328 out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff)) 1329 } 1330 1331 out.Write32(0) //end 1332 out.Write32(0) 1333 out.Write32(0) 1334 out.Write32(0) 1335 out.Write32(0) 1336 1337 // update data directory 1338 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress 1339 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize 1340 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(ldr.SymValue(dynamic) - PEBASE) 1341 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(ldr.SymSize(dynamic)) 1342 1343 out.SeekSet(endoff) 1344 } 1345 1346 func initdynexport(ctxt *Link) { 1347 ldr := ctxt.loader 1348 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ { 1349 if !ldr.AttrReachable(s) || !ldr.AttrCgoExportDynamic(s) { 1350 continue 1351 } 1352 if len(dexport)+1 > cap(dexport) { 1353 ctxt.Errorf(s, "pe dynexport table is full") 1354 errorexit() 1355 } 1356 1357 dexport = append(dexport, s) 1358 } 1359 1360 sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) }) 1361 } 1362 1363 func addexports(ctxt *Link) { 1364 ldr := ctxt.loader 1365 var e IMAGE_EXPORT_DIRECTORY 1366 1367 nexport := len(dexport) 1368 size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1 1369 for _, s := range dexport { 1370 size += len(ldr.SymExtname(s)) + 1 1371 } 1372 1373 if nexport == 0 { 1374 return 1375 } 1376 1377 sect := pefile.addSection(".edata", size, size) 1378 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 1379 sect.checkOffset(ctxt.Out.Offset()) 1380 va := int(sect.virtualAddress) 1381 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va) 1382 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize 1383 1384 vaName := va + binary.Size(&e) + nexport*4 1385 vaAddr := va + binary.Size(&e) 1386 vaNa := va + binary.Size(&e) + nexport*8 1387 1388 e.Characteristics = 0 1389 e.MajorVersion = 0 1390 e.MinorVersion = 0 1391 e.NumberOfFunctions = uint32(nexport) 1392 e.NumberOfNames = uint32(nexport) 1393 e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names. 1394 e.Base = 1 1395 e.AddressOfFunctions = uint32(vaAddr) 1396 e.AddressOfNames = uint32(vaName) 1397 e.AddressOfNameOrdinals = uint32(vaNa) 1398 1399 out := ctxt.Out 1400 1401 // put IMAGE_EXPORT_DIRECTORY 1402 binary.Write(out, binary.LittleEndian, &e) 1403 1404 // put EXPORT Address Table 1405 for _, s := range dexport { 1406 out.Write32(uint32(ldr.SymValue(s) - PEBASE)) 1407 } 1408 1409 // put EXPORT Name Pointer Table 1410 v := int(e.Name + uint32(len(*flagOutfile)) + 1) 1411 1412 for _, s := range dexport { 1413 out.Write32(uint32(v)) 1414 v += len(ldr.SymExtname(s)) + 1 1415 } 1416 1417 // put EXPORT Ordinal Table 1418 for i := 0; i < nexport; i++ { 1419 out.Write16(uint16(i)) 1420 } 1421 1422 // put Names 1423 out.WriteStringN(*flagOutfile, len(*flagOutfile)+1) 1424 1425 for _, s := range dexport { 1426 name := ldr.SymExtname(s) 1427 out.WriteStringN(name, len(name)+1) 1428 } 1429 sect.pad(out, uint32(size)) 1430 } 1431 1432 // peBaseRelocEntry represents a single relocation entry. 1433 type peBaseRelocEntry struct { 1434 typeOff uint16 1435 } 1436 1437 // peBaseRelocBlock represents a Base Relocation Block. A block 1438 // is a collection of relocation entries in a page, where each 1439 // entry describes a single relocation. 1440 // The block page RVA (Relative Virtual Address) is the index 1441 // into peBaseRelocTable.blocks. 1442 type peBaseRelocBlock struct { 1443 entries []peBaseRelocEntry 1444 } 1445 1446 // pePages is a type used to store the list of pages for which there 1447 // are base relocation blocks. This is defined as a type so that 1448 // it can be sorted. 1449 type pePages []uint32 1450 1451 func (p pePages) Len() int { return len(p) } 1452 func (p pePages) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 1453 func (p pePages) Less(i, j int) bool { return p[i] < p[j] } 1454 1455 // A PE base relocation table is a list of blocks, where each block 1456 // contains relocation information for a single page. The blocks 1457 // must be emitted in order of page virtual address. 1458 // See https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-reloc-section-image-only 1459 type peBaseRelocTable struct { 1460 blocks map[uint32]peBaseRelocBlock 1461 1462 // pePages is a list of keys into blocks map. 1463 // It is stored separately for ease of sorting. 1464 pages pePages 1465 } 1466 1467 func (rt *peBaseRelocTable) init(ctxt *Link) { 1468 rt.blocks = make(map[uint32]peBaseRelocBlock) 1469 } 1470 1471 func (rt *peBaseRelocTable) addentry(ldr *loader.Loader, s loader.Sym, r *loader.Reloc) { 1472 // pageSize is the size in bytes of a page 1473 // described by a base relocation block. 1474 const pageSize = 0x1000 1475 const pageMask = pageSize - 1 1476 1477 addr := ldr.SymValue(s) + int64(r.Off()) - int64(PEBASE) 1478 page := uint32(addr &^ pageMask) 1479 off := uint32(addr & pageMask) 1480 1481 b, ok := rt.blocks[page] 1482 if !ok { 1483 rt.pages = append(rt.pages, page) 1484 } 1485 1486 e := peBaseRelocEntry{ 1487 typeOff: uint16(off & 0xFFF), 1488 } 1489 1490 // Set entry type 1491 switch r.Siz() { 1492 default: 1493 Exitf("unsupported relocation size %d\n", r.Siz) 1494 case 4: 1495 e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12) 1496 case 8: 1497 e.typeOff |= uint16(IMAGE_REL_BASED_DIR64 << 12) 1498 } 1499 1500 b.entries = append(b.entries, e) 1501 rt.blocks[page] = b 1502 } 1503 1504 func (rt *peBaseRelocTable) write(ctxt *Link) { 1505 out := ctxt.Out 1506 1507 // sort the pages array 1508 sort.Sort(rt.pages) 1509 1510 for _, p := range rt.pages { 1511 b := rt.blocks[p] 1512 const sizeOfPEbaseRelocBlock = 8 // 2 * sizeof(uint32) 1513 blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2) 1514 out.Write32(p) 1515 out.Write32(blockSize) 1516 1517 for _, e := range b.entries { 1518 out.Write16(e.typeOff) 1519 } 1520 } 1521 } 1522 1523 func addPEBaseRelocSym(ldr *loader.Loader, s loader.Sym, rt *peBaseRelocTable) { 1524 relocs := ldr.Relocs(s) 1525 for ri := 0; ri < relocs.Count(); ri++ { 1526 r := relocs.At(ri) 1527 if r.Type() >= objabi.ElfRelocOffset { 1528 continue 1529 } 1530 if r.Siz() == 0 { // informational relocation 1531 continue 1532 } 1533 if r.Type() == objabi.R_DWARFFILEREF { 1534 continue 1535 } 1536 rs := r.Sym() 1537 if rs == 0 { 1538 continue 1539 } 1540 if !ldr.AttrReachable(s) { 1541 continue 1542 } 1543 1544 switch r.Type() { 1545 default: 1546 case objabi.R_ADDR: 1547 rt.addentry(ldr, s, &r) 1548 } 1549 } 1550 } 1551 1552 func needPEBaseReloc(ctxt *Link) bool { 1553 // Non-PIE x86 binaries don't need the base relocation table. 1554 // Everyone else does. 1555 if (ctxt.Arch.Family == sys.I386 || ctxt.Arch.Family == sys.AMD64) && ctxt.BuildMode != BuildModePIE { 1556 return false 1557 } 1558 return true 1559 } 1560 1561 func addPEBaseReloc(ctxt *Link) { 1562 if !needPEBaseReloc(ctxt) { 1563 return 1564 } 1565 1566 var rt peBaseRelocTable 1567 rt.init(ctxt) 1568 1569 // Get relocation information 1570 ldr := ctxt.loader 1571 for _, s := range ctxt.Textp { 1572 addPEBaseRelocSym(ldr, s, &rt) 1573 } 1574 for _, s := range ctxt.datap { 1575 addPEBaseRelocSym(ldr, s, &rt) 1576 } 1577 1578 // Write relocation information 1579 startoff := ctxt.Out.Offset() 1580 rt.write(ctxt) 1581 size := ctxt.Out.Offset() - startoff 1582 1583 // Add a PE section and pad it at the end 1584 rsect := pefile.addSection(".reloc", int(size), int(size)) 1585 rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 1586 rsect.checkOffset(startoff) 1587 rsect.pad(ctxt.Out, uint32(size)) 1588 1589 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress 1590 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize 1591 } 1592 1593 func (ctxt *Link) dope() { 1594 initdynimport(ctxt) 1595 initdynexport(ctxt) 1596 } 1597 1598 func setpersrc(ctxt *Link, syms []loader.Sym) { 1599 if len(rsrcsyms) != 0 { 1600 Errorf(nil, "too many .rsrc sections") 1601 } 1602 rsrcsyms = syms 1603 } 1604 1605 func addpersrc(ctxt *Link) { 1606 if len(rsrcsyms) == 0 { 1607 return 1608 } 1609 1610 var size int64 1611 for _, rsrcsym := range rsrcsyms { 1612 size += ctxt.loader.SymSize(rsrcsym) 1613 } 1614 h := pefile.addSection(".rsrc", int(size), int(size)) 1615 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA 1616 h.checkOffset(ctxt.Out.Offset()) 1617 1618 for _, rsrcsym := range rsrcsyms { 1619 // A split resource happens when the actual resource data and its relocations are 1620 // split across multiple sections, denoted by a $01 or $02 at the end of the .rsrc 1621 // section name. 1622 splitResources := strings.Contains(ctxt.loader.SymName(rsrcsym), ".rsrc$") 1623 relocs := ctxt.loader.Relocs(rsrcsym) 1624 data := ctxt.loader.Data(rsrcsym) 1625 for ri := 0; ri < relocs.Count(); ri++ { 1626 r := relocs.At(ri) 1627 p := data[r.Off():] 1628 val := uint32(int64(h.virtualAddress) + r.Add()) 1629 if splitResources { 1630 // If we're a split resource section, and that section has relocation 1631 // symbols, then the data that it points to doesn't actually begin at 1632 // the virtual address listed in this current section, but rather 1633 // begins at the section immediately after this one. So, in order to 1634 // calculate the proper virtual address of the data it's pointing to, 1635 // we have to add the length of this section to the virtual address. 1636 // This works because .rsrc sections are divided into two (but not more) 1637 // of these sections. 1638 val += uint32(len(data)) 1639 } 1640 binary.LittleEndian.PutUint32(p, val) 1641 } 1642 ctxt.Out.Write(data) 1643 } 1644 h.pad(ctxt.Out, uint32(size)) 1645 1646 // update data directory 1647 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress 1648 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize 1649 } 1650 1651 func asmbPe(ctxt *Link) { 1652 t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length)) 1653 t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ 1654 if ctxt.LinkMode == LinkExternal { 1655 // some data symbols (e.g. masks) end up in the .text section, and they normally 1656 // expect larger alignment requirement than the default text section alignment. 1657 t.characteristics |= IMAGE_SCN_ALIGN_32BYTES 1658 } 1659 t.checkSegment(&Segtext) 1660 pefile.textSect = t 1661 1662 ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length)) 1663 ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 1664 if ctxt.LinkMode == LinkExternal { 1665 // some data symbols (e.g. masks) end up in the .rdata section, and they normally 1666 // expect larger alignment requirement than the default text section alignment. 1667 ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES 1668 } 1669 ro.checkSegment(&Segrodata) 1670 pefile.rdataSect = ro 1671 1672 var d *peSection 1673 if ctxt.LinkMode != LinkExternal { 1674 d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen)) 1675 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 1676 d.checkSegment(&Segdata) 1677 pefile.dataSect = d 1678 } else { 1679 d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen)) 1680 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1681 d.checkSegment(&Segdata) 1682 pefile.dataSect = d 1683 1684 b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0) 1685 b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1686 b.pointerToRawData = 0 1687 pefile.bssSect = b 1688 } 1689 1690 pefile.addDWARF() 1691 1692 if ctxt.LinkMode == LinkExternal { 1693 pefile.ctorsSect = pefile.addInitArray(ctxt) 1694 } 1695 1696 ctxt.Out.SeekSet(int64(pefile.nextFileOffset)) 1697 if ctxt.LinkMode != LinkExternal { 1698 addimports(ctxt, d) 1699 addexports(ctxt) 1700 addPEBaseReloc(ctxt) 1701 } 1702 pefile.writeSymbolTableAndStringTable(ctxt) 1703 addpersrc(ctxt) 1704 if ctxt.LinkMode == LinkExternal { 1705 pefile.emitRelocations(ctxt) 1706 } 1707 1708 pewrite(ctxt) 1709 }