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