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