github.com/Filosottile/go@v0.0.0-20170906193555-dbed9972d994/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 package ld 6 7 import ( 8 "cmd/internal/objabi" 9 "cmd/internal/sys" 10 "debug/pe" 11 "encoding/binary" 12 "fmt" 13 "sort" 14 "strconv" 15 "strings" 16 ) 17 18 type IMAGE_IMPORT_DESCRIPTOR struct { 19 OriginalFirstThunk uint32 20 TimeDateStamp uint32 21 ForwarderChain uint32 22 Name uint32 23 FirstThunk uint32 24 } 25 26 type IMAGE_EXPORT_DIRECTORY struct { 27 Characteristics uint32 28 TimeDateStamp uint32 29 MajorVersion uint16 30 MinorVersion uint16 31 Name uint32 32 Base uint32 33 NumberOfFunctions uint32 34 NumberOfNames uint32 35 AddressOfFunctions uint32 36 AddressOfNames uint32 37 AddressOfNameOrdinals uint32 38 } 39 40 const ( 41 PEBASE = 0x00400000 42 ) 43 44 var ( 45 // SectionAlignment must be greater than or equal to FileAlignment. 46 // The default is the page size for the architecture. 47 PESECTALIGN int64 = 0x1000 48 49 // FileAlignment should be a power of 2 between 512 and 64 K, inclusive. 50 // The default is 512. If the SectionAlignment is less than 51 // the architecture's page size, then FileAlignment must match SectionAlignment. 52 PEFILEALIGN int64 = 2 << 8 53 ) 54 55 const ( 56 IMAGE_FILE_MACHINE_I386 = 0x14c 57 IMAGE_FILE_MACHINE_AMD64 = 0x8664 58 IMAGE_FILE_RELOCS_STRIPPED = 0x0001 59 IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002 60 IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004 61 IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020 62 IMAGE_FILE_32BIT_MACHINE = 0x0100 63 IMAGE_FILE_DEBUG_STRIPPED = 0x0200 64 IMAGE_SCN_CNT_CODE = 0x00000020 65 IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 66 IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 67 IMAGE_SCN_MEM_EXECUTE = 0x20000000 68 IMAGE_SCN_MEM_READ = 0x40000000 69 IMAGE_SCN_MEM_WRITE = 0x80000000 70 IMAGE_SCN_MEM_DISCARDABLE = 0x2000000 71 IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000 72 IMAGE_SCN_ALIGN_32BYTES = 0x600000 73 IMAGE_DIRECTORY_ENTRY_EXPORT = 0 74 IMAGE_DIRECTORY_ENTRY_IMPORT = 1 75 IMAGE_DIRECTORY_ENTRY_RESOURCE = 2 76 IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3 77 IMAGE_DIRECTORY_ENTRY_SECURITY = 4 78 IMAGE_DIRECTORY_ENTRY_BASERELOC = 5 79 IMAGE_DIRECTORY_ENTRY_DEBUG = 6 80 IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7 81 IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7 82 IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8 83 IMAGE_DIRECTORY_ENTRY_TLS = 9 84 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10 85 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11 86 IMAGE_DIRECTORY_ENTRY_IAT = 12 87 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13 88 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14 89 IMAGE_SUBSYSTEM_WINDOWS_GUI = 2 90 IMAGE_SUBSYSTEM_WINDOWS_CUI = 3 91 ) 92 93 // Copyright 2009 The Go Authors. All rights reserved. 94 // Use of this source code is governed by a BSD-style 95 // license that can be found in the LICENSE file. 96 97 // PE (Portable Executable) file writing 98 // http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx 99 100 // DOS stub that prints out 101 // "This program cannot be run in DOS mode." 102 var dosstub = []uint8{ 103 0x4d, 104 0x5a, 105 0x90, 106 0x00, 107 0x03, 108 0x00, 109 0x04, 110 0x00, 111 0x00, 112 0x00, 113 0x00, 114 0x00, 115 0xff, 116 0xff, 117 0x00, 118 0x00, 119 0x8b, 120 0x00, 121 0x00, 122 0x00, 123 0x00, 124 0x00, 125 0x00, 126 0x00, 127 0x40, 128 0x00, 129 0x00, 130 0x00, 131 0x00, 132 0x00, 133 0x00, 134 0x00, 135 0x00, 136 0x00, 137 0x00, 138 0x00, 139 0x00, 140 0x00, 141 0x00, 142 0x00, 143 0x00, 144 0x00, 145 0x00, 146 0x00, 147 0x00, 148 0x00, 149 0x00, 150 0x00, 151 0x00, 152 0x00, 153 0x00, 154 0x00, 155 0x00, 156 0x00, 157 0x00, 158 0x00, 159 0x00, 160 0x00, 161 0x00, 162 0x00, 163 0x80, 164 0x00, 165 0x00, 166 0x00, 167 0x0e, 168 0x1f, 169 0xba, 170 0x0e, 171 0x00, 172 0xb4, 173 0x09, 174 0xcd, 175 0x21, 176 0xb8, 177 0x01, 178 0x4c, 179 0xcd, 180 0x21, 181 0x54, 182 0x68, 183 0x69, 184 0x73, 185 0x20, 186 0x70, 187 0x72, 188 0x6f, 189 0x67, 190 0x72, 191 0x61, 192 0x6d, 193 0x20, 194 0x63, 195 0x61, 196 0x6e, 197 0x6e, 198 0x6f, 199 0x74, 200 0x20, 201 0x62, 202 0x65, 203 0x20, 204 0x72, 205 0x75, 206 0x6e, 207 0x20, 208 0x69, 209 0x6e, 210 0x20, 211 0x44, 212 0x4f, 213 0x53, 214 0x20, 215 0x6d, 216 0x6f, 217 0x64, 218 0x65, 219 0x2e, 220 0x0d, 221 0x0d, 222 0x0a, 223 0x24, 224 0x00, 225 0x00, 226 0x00, 227 0x00, 228 0x00, 229 0x00, 230 0x00, 231 } 232 233 var rsrcsym *Symbol 234 235 var PESECTHEADR int32 236 237 var PEFILEHEADR int32 238 239 var pe64 int 240 241 type Imp struct { 242 s *Symbol 243 off uint64 244 next *Imp 245 argsize int 246 } 247 248 type Dll struct { 249 name string 250 nameoff uint64 251 thunkoff uint64 252 ms *Imp 253 next *Dll 254 } 255 256 var dr *Dll 257 258 var dexport [1024]*Symbol 259 260 var nexport int 261 262 // peStringTable is a COFF string table. 263 type peStringTable struct { 264 strings []string 265 stringsLen int 266 } 267 268 // size resturns size of string table t. 269 func (t *peStringTable) size() int { 270 // string table starts with 4-byte length at the beginning 271 return t.stringsLen + 4 272 } 273 274 // add adds string str to string table t. 275 func (t *peStringTable) add(str string) int { 276 off := t.size() 277 t.strings = append(t.strings, str) 278 t.stringsLen += len(str) + 1 // each string will have 0 appended to it 279 return off 280 } 281 282 // write writes string table t into the output file. 283 func (t *peStringTable) write() { 284 Lputl(uint32(t.size())) 285 for _, s := range t.strings { 286 Cwritestring(s) 287 Cput(0) 288 } 289 } 290 291 // peSection represents section from COFF section table. 292 type peSection struct { 293 name string 294 shortName string 295 index int // one-based index into the Section Table 296 virtualSize uint32 297 virtualAddress uint32 298 sizeOfRawData uint32 299 pointerToRawData uint32 300 pointerToRelocations uint32 301 numberOfRelocations uint16 302 characteristics uint32 303 } 304 305 // checkOffset verifies COFF section sect offset in the file. 306 func (sect *peSection) checkOffset(off int64) { 307 if off != int64(sect.pointerToRawData) { 308 Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(off)) 309 errorexit() 310 } 311 } 312 313 // checkSegment verifies COFF section sect matches address 314 // and file offset provided in segment seg. 315 func (sect *peSection) checkSegment(seg *Segment) { 316 if seg.Vaddr-PEBASE != uint64(sect.virtualAddress) { 317 Errorf(nil, "%s.VirtualAddress = %#x, want %#x", sect.name, uint64(int64(sect.virtualAddress)), uint64(int64(seg.Vaddr-PEBASE))) 318 errorexit() 319 } 320 if seg.Fileoff != uint64(sect.pointerToRawData) { 321 Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(int64(seg.Fileoff))) 322 errorexit() 323 } 324 } 325 326 // pad adds zeros to the section sect. It writes as many bytes 327 // as necessary to make section sect.SizeOfRawData bytes long. 328 // It assumes that n bytes are already written to the file. 329 func (sect *peSection) pad(n uint32) { 330 strnput("", int(sect.sizeOfRawData-n)) 331 } 332 333 // write writes COFF section sect into the output file. 334 func (sect *peSection) write() error { 335 h := pe.SectionHeader32{ 336 VirtualSize: sect.virtualSize, 337 SizeOfRawData: sect.sizeOfRawData, 338 PointerToRawData: sect.pointerToRawData, 339 PointerToRelocations: sect.pointerToRelocations, 340 NumberOfRelocations: sect.numberOfRelocations, 341 Characteristics: sect.characteristics, 342 } 343 if Linkmode != LinkExternal { 344 h.VirtualAddress = sect.virtualAddress 345 } 346 copy(h.Name[:], sect.shortName) 347 return binary.Write(&coutbuf, binary.LittleEndian, h) 348 } 349 350 // emitRelocations emits the relocation entries for the sect. 351 // The actual relocations are emitted by relocfn. 352 // This updates the corresponding PE section table entry 353 // with the relocation offset and count. 354 func (sect *peSection) emitRelocations(relocfn func() int) { 355 sect.pointerToRelocations = uint32(coutbuf.Offset()) 356 // first entry: extended relocs 357 Lputl(0) // placeholder for number of relocation + 1 358 Lputl(0) 359 Wputl(0) 360 361 n := relocfn() + 1 362 363 cpos := coutbuf.Offset() 364 Cseek(int64(sect.pointerToRelocations)) 365 Lputl(uint32(n)) 366 Cseek(cpos) 367 if n > 0x10000 { 368 n = 0x10000 369 sect.characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL 370 } else { 371 sect.pointerToRelocations += 10 // skip the extend reloc entry 372 } 373 sect.numberOfRelocations = uint16(n - 1) 374 } 375 376 // peFile is used to build COFF file. 377 type peFile struct { 378 sections []*peSection 379 stringTable peStringTable 380 textSect *peSection 381 dataSect *peSection 382 bssSect *peSection 383 ctorsSect *peSection 384 nextSectOffset uint32 385 nextFileOffset uint32 386 symtabOffset int64 // offset to the start of symbol table 387 symbolCount int // number of symbol table records written 388 dataDirectory [16]pe.DataDirectory 389 } 390 391 // addSection adds section to the COFF file f. 392 func (f *peFile) addSection(name string, sectsize int, filesize int) *peSection { 393 sect := &peSection{ 394 name: name, 395 shortName: name, 396 index: len(f.sections) + 1, 397 virtualSize: uint32(sectsize), 398 virtualAddress: f.nextSectOffset, 399 pointerToRawData: f.nextFileOffset, 400 } 401 f.nextSectOffset = uint32(Rnd(int64(f.nextSectOffset)+int64(sectsize), PESECTALIGN)) 402 if filesize > 0 { 403 sect.sizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN)) 404 f.nextFileOffset += sect.sizeOfRawData 405 } 406 f.sections = append(f.sections, sect) 407 return sect 408 } 409 410 // addDWARFSection adds DWARF section to the COFF file f. 411 // This function is similar to addSection, but DWARF section names are 412 // longer than 8 characters, so they need to be stored in the string table. 413 func (f *peFile) addDWARFSection(name string, size int) *peSection { 414 if size == 0 { 415 Exitf("DWARF section %q is empty", name) 416 } 417 // DWARF section names are longer than 8 characters. 418 // PE format requires such names to be stored in string table, 419 // and section names replaced with slash (/) followed by 420 // correspondent string table index. 421 // see http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx 422 // for details 423 off := f.stringTable.add(name) 424 h := f.addSection(name, size, size) 425 h.shortName = fmt.Sprintf("/%d", off) 426 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 427 return h 428 } 429 430 // addDWARF adds DWARF information to the COFF file f. 431 func (f *peFile) addDWARF() { 432 if *FlagS { // disable symbol table 433 return 434 } 435 if *FlagW { // disable dwarf 436 return 437 } 438 for _, sect := range Segdwarf.Sections { 439 h := f.addDWARFSection(sect.Name, int(sect.Length)) 440 fileoff := sect.Vaddr - Segdwarf.Vaddr + Segdwarf.Fileoff 441 if uint64(h.pointerToRawData) != fileoff { 442 Exitf("%s.PointerToRawData = %#x, want %#x", sect.Name, h.pointerToRawData, fileoff) 443 } 444 } 445 } 446 447 // addInitArray adds .ctors COFF section to the file f. 448 func (f *peFile) addInitArray(ctxt *Link) *peSection { 449 // The size below was determined by the specification for array relocations, 450 // and by observing what GCC writes here. If the initarray section grows to 451 // contain more than one constructor entry, the size will need to be 8 * constructor_count. 452 // However, the entire Go runtime is initialized from just one function, so it is unlikely 453 // that this will need to grow in the future. 454 var size int 455 switch objabi.GOARCH { 456 default: 457 Exitf("peFile.addInitArray: unsupported GOARCH=%q\n", objabi.GOARCH) 458 case "386": 459 size = 4 460 case "amd64": 461 size = 8 462 } 463 sect := f.addSection(".ctors", size, size) 464 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 465 sect.sizeOfRawData = uint32(size) 466 Cseek(int64(sect.pointerToRawData)) 467 sect.checkOffset(coutbuf.Offset()) 468 469 init_entry := ctxt.Syms.Lookup(*flagEntrySymbol, 0) 470 addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr 471 switch objabi.GOARCH { 472 case "386": 473 Lputl(uint32(addr)) 474 case "amd64": 475 Vputl(addr) 476 } 477 return sect 478 } 479 480 // emitRelocations emits relocation entries for go.o in external linking. 481 func (f *peFile) emitRelocations(ctxt *Link) { 482 for coutbuf.Offset()&7 != 0 { 483 Cput(0) 484 } 485 486 // relocsect relocates symbols from first in section sect, and returns 487 // the total number of relocations emitted. 488 relocsect := func(sect *Section, syms []*Symbol, base uint64) int { 489 // If main section has no bits, nothing to relocate. 490 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { 491 return 0 492 } 493 relocs := 0 494 sect.Reloff = uint64(coutbuf.Offset()) 495 for i, s := range syms { 496 if !s.Attr.Reachable() { 497 continue 498 } 499 if uint64(s.Value) >= sect.Vaddr { 500 syms = syms[i:] 501 break 502 } 503 } 504 eaddr := int32(sect.Vaddr + sect.Length) 505 for _, sym := range syms { 506 if !sym.Attr.Reachable() { 507 continue 508 } 509 if sym.Value >= int64(eaddr) { 510 break 511 } 512 for ri := 0; ri < len(sym.R); ri++ { 513 r := &sym.R[ri] 514 if r.Done { 515 continue 516 } 517 if r.Xsym == nil { 518 Errorf(sym, "missing xsym in relocation") 519 continue 520 } 521 if r.Xsym.Dynid < 0 { 522 Errorf(sym, "reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type) 523 } 524 if !Thearch.PEreloc1(sym, r, int64(uint64(sym.Value+int64(r.Off))-base)) { 525 Errorf(sym, "unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name) 526 } 527 relocs++ 528 } 529 } 530 sect.Rellen = uint64(coutbuf.Offset()) - sect.Reloff 531 return relocs 532 } 533 534 f.textSect.emitRelocations(func() int { 535 n := relocsect(Segtext.Sections[0], ctxt.Textp, Segtext.Vaddr) 536 for _, sect := range Segtext.Sections[1:] { 537 n += relocsect(sect, datap, Segtext.Vaddr) 538 } 539 return n 540 }) 541 542 f.dataSect.emitRelocations(func() int { 543 var n int 544 for _, sect := range Segdata.Sections { 545 n += relocsect(sect, datap, Segdata.Vaddr) 546 } 547 return n 548 }) 549 550 dwarfLoop: 551 for _, sect := range Segdwarf.Sections { 552 for _, pesect := range f.sections { 553 if sect.Name == pesect.name { 554 pesect.emitRelocations(func() int { 555 return relocsect(sect, dwarfp, sect.Vaddr) 556 }) 557 continue dwarfLoop 558 } 559 } 560 Errorf(nil, "emitRelocations: could not find %q section", sect.Name) 561 } 562 563 f.ctorsSect.emitRelocations(func() int { 564 dottext := ctxt.Syms.Lookup(".text", 0) 565 Lputl(0) 566 Lputl(uint32(dottext.Dynid)) 567 switch objabi.GOARCH { 568 default: 569 Errorf(dottext, "unknown architecture for PE: %q\n", objabi.GOARCH) 570 case "386": 571 Wputl(IMAGE_REL_I386_DIR32) 572 case "amd64": 573 Wputl(IMAGE_REL_AMD64_ADDR64) 574 } 575 return 1 576 }) 577 } 578 579 // writeSymbol appends symbol s to file f symbol table. 580 // It also sets s.Dynid to written symbol number. 581 func (f *peFile) writeSymbol(s *Symbol, value int64, sectidx int, typ uint16, class uint8) { 582 if len(s.Name) > 8 { 583 Lputl(0) 584 Lputl(uint32(f.stringTable.add(s.Name))) 585 } else { 586 strnput(s.Name, 8) 587 } 588 Lputl(uint32(value)) 589 Wputl(uint16(sectidx)) 590 Wputl(typ) 591 Cput(class) 592 Cput(0) // no aux entries 593 594 s.Dynid = int32(f.symbolCount) 595 596 f.symbolCount++ 597 } 598 599 // mapToPESection searches peFile f for s symbol's location. 600 // It returns PE section index, and offset within that section. 601 func (f *peFile) mapToPESection(s *Symbol) (pesectidx int, offset int64, err error) { 602 if s.Sect == nil { 603 return 0, 0, fmt.Errorf("could not map %s symbol with no section", s.Name) 604 } 605 if s.Sect.Seg == &Segtext { 606 return f.textSect.index, int64(uint64(s.Value) - Segtext.Vaddr), nil 607 } 608 if s.Sect.Seg != &Segdata { 609 return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .data section", s.Name) 610 } 611 v := uint64(s.Value) - Segdata.Vaddr 612 if Linkmode != LinkExternal { 613 return f.dataSect.index, int64(v), nil 614 } 615 if s.Type == SDATA { 616 return f.dataSect.index, int64(v), nil 617 } 618 // Note: although address of runtime.edata (type SDATA) is at the start of .bss section 619 // it still belongs to the .data section, not the .bss section. 620 if v < Segdata.Filelen { 621 return f.dataSect.index, int64(v), nil 622 } 623 return f.bssSect.index, int64(v - Segdata.Filelen), nil 624 } 625 626 // writeSymbols writes all COFF symbol table records. 627 func (f *peFile) writeSymbols(ctxt *Link) { 628 629 put := func(ctxt *Link, s *Symbol, name string, type_ SymbolType, addr int64, gotype *Symbol) { 630 if s == nil { 631 return 632 } 633 if s.Sect == nil && type_ != UndefinedSym { 634 return 635 } 636 switch type_ { 637 default: 638 return 639 case DataSym, BSSSym, TextSym, UndefinedSym: 640 } 641 642 // Only windows/386 requires underscore prefix on external symbols. 643 if SysArch.Family == sys.I386 && 644 Linkmode == LinkExternal && 645 (s.Type == SHOSTOBJ || s.Attr.CgoExport()) { 646 s.Name = "_" + s.Name 647 } 648 649 var typ uint16 650 if Linkmode == LinkExternal { 651 typ = IMAGE_SYM_TYPE_NULL 652 } else { 653 // TODO: fix IMAGE_SYM_DTYPE_ARRAY value and use following expression, instead of 0x0308 654 typ = IMAGE_SYM_DTYPE_ARRAY<<8 + IMAGE_SYM_TYPE_STRUCT 655 typ = 0x0308 // "array of structs" 656 } 657 sect, value, err := f.mapToPESection(s) 658 if err != nil { 659 if type_ == UndefinedSym { 660 typ = IMAGE_SYM_DTYPE_FUNCTION 661 } else { 662 Errorf(s, "addpesym: %v", err) 663 } 664 } 665 class := IMAGE_SYM_CLASS_EXTERNAL 666 if s.Version != 0 || (s.Type&SHIDDEN != 0) || s.Attr.Local() { 667 class = IMAGE_SYM_CLASS_STATIC 668 } 669 f.writeSymbol(s, value, sect, typ, uint8(class)) 670 } 671 672 if Linkmode == LinkExternal { 673 // Include section symbols as external, because 674 // .ctors and .debug_* section relocations refer to it. 675 for _, pesect := range f.sections { 676 sym := ctxt.Syms.Lookup(pesect.name, 0) 677 f.writeSymbol(sym, 0, pesect.index, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC) 678 } 679 } 680 681 genasmsym(ctxt, put) 682 } 683 684 // writeSymbolTableAndStringTable writes out symbol and string tables for peFile f. 685 func (f *peFile) writeSymbolTableAndStringTable(ctxt *Link) { 686 f.symtabOffset = coutbuf.Offset() 687 688 // write COFF symbol table 689 if !*FlagS || Linkmode == LinkExternal { 690 f.writeSymbols(ctxt) 691 } 692 693 // update COFF file header and section table 694 size := f.stringTable.size() + 18*f.symbolCount 695 var h *peSection 696 if Linkmode != LinkExternal { 697 // We do not really need .symtab for go.o, and if we have one, ld 698 // will also include it in the exe, and that will confuse windows. 699 h = f.addSection(".symtab", size, size) 700 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE 701 h.checkOffset(f.symtabOffset) 702 } 703 704 // write COFF string table 705 f.stringTable.write() 706 if Linkmode != LinkExternal { 707 h.pad(uint32(size)) 708 } 709 } 710 711 // writeFileHeader writes COFF file header for peFile f. 712 func (f *peFile) writeFileHeader() { 713 var fh pe.FileHeader 714 715 switch SysArch.Family { 716 default: 717 Exitf("unknown PE architecture: %v", SysArch.Family) 718 case sys.AMD64: 719 fh.Machine = IMAGE_FILE_MACHINE_AMD64 720 case sys.I386: 721 fh.Machine = IMAGE_FILE_MACHINE_I386 722 } 723 724 fh.NumberOfSections = uint16(len(f.sections)) 725 726 // Being able to produce identical output for identical input is 727 // much more beneficial than having build timestamp in the header. 728 fh.TimeDateStamp = 0 729 730 if Linkmode == LinkExternal { 731 fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED 732 } else { 733 fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED 734 } 735 if pe64 != 0 { 736 var oh64 pe.OptionalHeader64 737 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64)) 738 fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE 739 } else { 740 var oh pe.OptionalHeader32 741 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh)) 742 fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE 743 } 744 745 fh.PointerToSymbolTable = uint32(f.symtabOffset) 746 fh.NumberOfSymbols = uint32(f.symbolCount) 747 748 binary.Write(&coutbuf, binary.LittleEndian, &fh) 749 } 750 751 // writeOptionalHeader writes COFF optional header for peFile f. 752 func (f *peFile) writeOptionalHeader(ctxt *Link) { 753 var oh pe.OptionalHeader32 754 var oh64 pe.OptionalHeader64 755 756 if pe64 != 0 { 757 oh64.Magic = 0x20b // PE32+ 758 } else { 759 oh.Magic = 0x10b // PE32 760 oh.BaseOfData = f.dataSect.virtualAddress 761 } 762 763 // Fill out both oh64 and oh. We only use one. Oh well. 764 oh64.MajorLinkerVersion = 3 765 oh.MajorLinkerVersion = 3 766 oh64.MinorLinkerVersion = 0 767 oh.MinorLinkerVersion = 0 768 oh64.SizeOfCode = f.textSect.sizeOfRawData 769 oh.SizeOfCode = f.textSect.sizeOfRawData 770 oh64.SizeOfInitializedData = f.dataSect.sizeOfRawData 771 oh.SizeOfInitializedData = f.dataSect.sizeOfRawData 772 oh64.SizeOfUninitializedData = 0 773 oh.SizeOfUninitializedData = 0 774 if Linkmode != LinkExternal { 775 oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 776 oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE) 777 } 778 oh64.BaseOfCode = f.textSect.virtualAddress 779 oh.BaseOfCode = f.textSect.virtualAddress 780 oh64.ImageBase = PEBASE 781 oh.ImageBase = PEBASE 782 oh64.SectionAlignment = uint32(PESECTALIGN) 783 oh.SectionAlignment = uint32(PESECTALIGN) 784 oh64.FileAlignment = uint32(PEFILEALIGN) 785 oh.FileAlignment = uint32(PEFILEALIGN) 786 oh64.MajorOperatingSystemVersion = 4 787 oh.MajorOperatingSystemVersion = 4 788 oh64.MinorOperatingSystemVersion = 0 789 oh.MinorOperatingSystemVersion = 0 790 oh64.MajorImageVersion = 1 791 oh.MajorImageVersion = 1 792 oh64.MinorImageVersion = 0 793 oh.MinorImageVersion = 0 794 oh64.MajorSubsystemVersion = 4 795 oh.MajorSubsystemVersion = 4 796 oh64.MinorSubsystemVersion = 0 797 oh.MinorSubsystemVersion = 0 798 oh64.SizeOfImage = f.nextSectOffset 799 oh.SizeOfImage = f.nextSectOffset 800 oh64.SizeOfHeaders = uint32(PEFILEHEADR) 801 oh.SizeOfHeaders = uint32(PEFILEHEADR) 802 if windowsgui { 803 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 804 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI 805 } else { 806 oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 807 oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI 808 } 809 810 // Disable stack growth as we don't want Windows to 811 // fiddle with the thread stack limits, which we set 812 // ourselves to circumvent the stack checks in the 813 // Windows exception dispatcher. 814 // Commit size must be strictly less than reserve 815 // size otherwise reserve will be rounded up to a 816 // larger size, as verified with VMMap. 817 818 // On 64-bit, we always reserve 2MB stacks. "Pure" Go code is 819 // okay with much smaller stacks, but the syscall package 820 // makes it easy to call into arbitrary C code without cgo, 821 // and system calls even in "pure" Go code are actually C 822 // calls that may need more stack than we think. 823 // 824 // The default stack reserve size affects only the main 825 // thread, ctrlhandler thread, and profileloop thread. For 826 // these, it must be greater than the stack size assumed by 827 // externalthreadhandler. 828 // 829 // For other threads we specify stack size in runtime explicitly. 830 // For these, the reserve must match STACKSIZE in 831 // runtime/cgo/gcc_windows_{386,amd64}.c and the correspondent 832 // CreateThread parameter in runtime.newosproc. 833 oh64.SizeOfStackReserve = 0x00200000 834 oh64.SizeOfStackCommit = 0x00200000 - 0x2000 // account for 2 guard pages 835 836 // 32-bit is trickier since there much less address space to 837 // work with. Here we use large stacks only in cgo binaries as 838 // a compromise. 839 if !iscgo { 840 oh.SizeOfStackReserve = 0x00020000 841 oh.SizeOfStackCommit = 0x00001000 842 } else { 843 oh.SizeOfStackReserve = 0x00100000 844 oh.SizeOfStackCommit = 0x00100000 - 0x2000 845 } 846 847 oh64.SizeOfHeapReserve = 0x00100000 848 oh.SizeOfHeapReserve = 0x00100000 849 oh64.SizeOfHeapCommit = 0x00001000 850 oh.SizeOfHeapCommit = 0x00001000 851 oh64.NumberOfRvaAndSizes = 16 852 oh.NumberOfRvaAndSizes = 16 853 854 if pe64 != 0 { 855 oh64.DataDirectory = f.dataDirectory 856 } else { 857 oh.DataDirectory = f.dataDirectory 858 } 859 860 if pe64 != 0 { 861 binary.Write(&coutbuf, binary.LittleEndian, &oh64) 862 } else { 863 binary.Write(&coutbuf, binary.LittleEndian, &oh) 864 } 865 } 866 867 var pefile peFile 868 869 func Peinit(ctxt *Link) { 870 var l int 871 872 switch SysArch.Family { 873 // 64-bit architectures 874 case sys.AMD64: 875 pe64 = 1 876 var oh64 pe.OptionalHeader64 877 l = binary.Size(&oh64) 878 879 // 32-bit architectures 880 default: 881 var oh pe.OptionalHeader32 882 l = binary.Size(&oh) 883 884 } 885 886 if Linkmode == LinkExternal { 887 PESECTALIGN = 0 888 PEFILEALIGN = 0 889 } 890 891 var sh [16]pe.SectionHeader32 892 var fh pe.FileHeader 893 PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN)) 894 if Linkmode != LinkExternal { 895 PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN)) 896 } else { 897 PESECTHEADR = 0 898 } 899 pefile.nextSectOffset = uint32(PESECTHEADR) 900 pefile.nextFileOffset = uint32(PEFILEHEADR) 901 902 if Linkmode == LinkInternal { 903 // some mingw libs depend on this symbol, for example, FindPESectionByName 904 ctxt.xdefine("__image_base__", SDATA, PEBASE) 905 ctxt.xdefine("_image_base__", SDATA, PEBASE) 906 } 907 908 HEADR = PEFILEHEADR 909 if *FlagTextAddr == -1 { 910 *FlagTextAddr = PEBASE + int64(PESECTHEADR) 911 } 912 if *FlagDataAddr == -1 { 913 *FlagDataAddr = 0 914 } 915 if *FlagRound == -1 { 916 *FlagRound = int(PESECTALIGN) 917 } 918 if *FlagDataAddr != 0 && *FlagRound != 0 { 919 fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*FlagDataAddr), uint32(*FlagRound)) 920 } 921 } 922 923 func pewrite(ctxt *Link) { 924 Cseek(0) 925 if Linkmode != LinkExternal { 926 Cwrite(dosstub) 927 strnput("PE", 4) 928 } 929 930 pefile.writeFileHeader() 931 932 pefile.writeOptionalHeader(ctxt) 933 934 for _, sect := range pefile.sections { 935 sect.write() 936 } 937 } 938 939 func strput(s string) { 940 coutbuf.WriteString(s) 941 Cput(0) 942 // string must be padded to even size 943 if (len(s)+1)%2 != 0 { 944 Cput(0) 945 } 946 } 947 948 func initdynimport(ctxt *Link) *Dll { 949 var d *Dll 950 951 dr = nil 952 var m *Imp 953 for _, s := range ctxt.Syms.Allsym { 954 if !s.Attr.Reachable() || s.Type != SDYNIMPORT { 955 continue 956 } 957 for d = dr; d != nil; d = d.next { 958 if d.name == s.Dynimplib { 959 m = new(Imp) 960 break 961 } 962 } 963 964 if d == nil { 965 d = new(Dll) 966 d.name = s.Dynimplib 967 d.next = dr 968 dr = d 969 m = new(Imp) 970 } 971 972 // Because external link requires properly stdcall decorated name, 973 // all external symbols in runtime use %n to denote that the number 974 // of uinptrs this function consumes. Store the argsize and discard 975 // the %n suffix if any. 976 m.argsize = -1 977 if i := strings.IndexByte(s.Extname, '%'); i >= 0 { 978 var err error 979 m.argsize, err = strconv.Atoi(s.Extname[i+1:]) 980 if err != nil { 981 Errorf(s, "failed to parse stdcall decoration: %v", err) 982 } 983 m.argsize *= SysArch.PtrSize 984 s.Extname = s.Extname[:i] 985 } 986 987 m.s = s 988 m.next = d.ms 989 d.ms = m 990 } 991 992 if Linkmode == LinkExternal { 993 // Add real symbol name 994 for d := dr; d != nil; d = d.next { 995 for m = d.ms; m != nil; m = m.next { 996 m.s.Type = SDATA 997 Symgrow(m.s, int64(SysArch.PtrSize)) 998 dynName := m.s.Extname 999 // only windows/386 requires stdcall decoration 1000 if SysArch.Family == sys.I386 && m.argsize >= 0 { 1001 dynName += fmt.Sprintf("@%d", m.argsize) 1002 } 1003 dynSym := ctxt.Syms.Lookup(dynName, 0) 1004 dynSym.Attr |= AttrReachable 1005 dynSym.Type = SHOSTOBJ 1006 r := Addrel(m.s) 1007 r.Sym = dynSym 1008 r.Off = 0 1009 r.Siz = uint8(SysArch.PtrSize) 1010 r.Type = objabi.R_ADDR 1011 } 1012 } 1013 } else { 1014 dynamic := ctxt.Syms.Lookup(".windynamic", 0) 1015 dynamic.Attr |= AttrReachable 1016 dynamic.Type = SWINDOWS 1017 for d := dr; d != nil; d = d.next { 1018 for m = d.ms; m != nil; m = m.next { 1019 m.s.Type = SWINDOWS | SSUB 1020 m.s.Sub = dynamic.Sub 1021 dynamic.Sub = m.s 1022 m.s.Value = dynamic.Size 1023 dynamic.Size += int64(SysArch.PtrSize) 1024 } 1025 1026 dynamic.Size += int64(SysArch.PtrSize) 1027 } 1028 } 1029 1030 return dr 1031 } 1032 1033 // peimporteddlls returns the gcc command line argument to link all imported 1034 // DLLs. 1035 func peimporteddlls() []string { 1036 var dlls []string 1037 1038 for d := dr; d != nil; d = d.next { 1039 dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll")) 1040 } 1041 1042 return dlls 1043 } 1044 1045 func addimports(ctxt *Link, datsect *peSection) { 1046 startoff := coutbuf.Offset() 1047 dynamic := ctxt.Syms.Lookup(".windynamic", 0) 1048 1049 // skip import descriptor table (will write it later) 1050 n := uint64(0) 1051 1052 for d := dr; d != nil; d = d.next { 1053 n++ 1054 } 1055 Cseek(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1)) 1056 1057 // write dll names 1058 for d := dr; d != nil; d = d.next { 1059 d.nameoff = uint64(coutbuf.Offset()) - uint64(startoff) 1060 strput(d.name) 1061 } 1062 1063 // write function names 1064 var m *Imp 1065 for d := dr; d != nil; d = d.next { 1066 for m = d.ms; m != nil; m = m.next { 1067 m.off = uint64(pefile.nextSectOffset) + uint64(coutbuf.Offset()) - uint64(startoff) 1068 Wputl(0) // hint 1069 strput(m.s.Extname) 1070 } 1071 } 1072 1073 // write OriginalFirstThunks 1074 oftbase := uint64(coutbuf.Offset()) - uint64(startoff) 1075 1076 n = uint64(coutbuf.Offset()) 1077 for d := dr; d != nil; d = d.next { 1078 d.thunkoff = uint64(coutbuf.Offset()) - n 1079 for m = d.ms; m != nil; m = m.next { 1080 if pe64 != 0 { 1081 Vputl(m.off) 1082 } else { 1083 Lputl(uint32(m.off)) 1084 } 1085 } 1086 1087 if pe64 != 0 { 1088 Vputl(0) 1089 } else { 1090 Lputl(0) 1091 } 1092 } 1093 1094 // add pe section and pad it at the end 1095 n = uint64(coutbuf.Offset()) - uint64(startoff) 1096 1097 isect := pefile.addSection(".idata", int(n), int(n)) 1098 isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 1099 isect.checkOffset(startoff) 1100 isect.pad(uint32(n)) 1101 endoff := coutbuf.Offset() 1102 1103 // write FirstThunks (allocated in .data section) 1104 ftbase := uint64(dynamic.Value) - uint64(datsect.virtualAddress) - PEBASE 1105 1106 Cseek(int64(uint64(datsect.pointerToRawData) + ftbase)) 1107 for d := dr; d != nil; d = d.next { 1108 for m = d.ms; m != nil; m = m.next { 1109 if pe64 != 0 { 1110 Vputl(m.off) 1111 } else { 1112 Lputl(uint32(m.off)) 1113 } 1114 } 1115 1116 if pe64 != 0 { 1117 Vputl(0) 1118 } else { 1119 Lputl(0) 1120 } 1121 } 1122 1123 // finally write import descriptor table 1124 Cseek(startoff) 1125 1126 for d := dr; d != nil; d = d.next { 1127 Lputl(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff)) 1128 Lputl(0) 1129 Lputl(0) 1130 Lputl(uint32(uint64(isect.virtualAddress) + d.nameoff)) 1131 Lputl(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff)) 1132 } 1133 1134 Lputl(0) //end 1135 Lputl(0) 1136 Lputl(0) 1137 Lputl(0) 1138 Lputl(0) 1139 1140 // update data directory 1141 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress 1142 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize 1143 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE) 1144 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size) 1145 1146 Cseek(endoff) 1147 } 1148 1149 type byExtname []*Symbol 1150 1151 func (s byExtname) Len() int { return len(s) } 1152 func (s byExtname) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 1153 func (s byExtname) Less(i, j int) bool { return s[i].Extname < s[j].Extname } 1154 1155 func initdynexport(ctxt *Link) { 1156 nexport = 0 1157 for _, s := range ctxt.Syms.Allsym { 1158 if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() { 1159 continue 1160 } 1161 if nexport+1 > len(dexport) { 1162 Errorf(s, "pe dynexport table is full") 1163 errorexit() 1164 } 1165 1166 dexport[nexport] = s 1167 nexport++ 1168 } 1169 1170 sort.Sort(byExtname(dexport[:nexport])) 1171 } 1172 1173 func addexports(ctxt *Link) { 1174 var e IMAGE_EXPORT_DIRECTORY 1175 1176 size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1 1177 for i := 0; i < nexport; i++ { 1178 size += len(dexport[i].Extname) + 1 1179 } 1180 1181 if nexport == 0 { 1182 return 1183 } 1184 1185 sect := pefile.addSection(".edata", size, size) 1186 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ 1187 sect.checkOffset(coutbuf.Offset()) 1188 va := int(sect.virtualAddress) 1189 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va) 1190 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize 1191 1192 vaName := va + binary.Size(&e) + nexport*4 1193 vaAddr := va + binary.Size(&e) 1194 vaNa := va + binary.Size(&e) + nexport*8 1195 1196 e.Characteristics = 0 1197 e.MajorVersion = 0 1198 e.MinorVersion = 0 1199 e.NumberOfFunctions = uint32(nexport) 1200 e.NumberOfNames = uint32(nexport) 1201 e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names. 1202 e.Base = 1 1203 e.AddressOfFunctions = uint32(vaAddr) 1204 e.AddressOfNames = uint32(vaName) 1205 e.AddressOfNameOrdinals = uint32(vaNa) 1206 1207 // put IMAGE_EXPORT_DIRECTORY 1208 binary.Write(&coutbuf, binary.LittleEndian, &e) 1209 1210 // put EXPORT Address Table 1211 for i := 0; i < nexport; i++ { 1212 Lputl(uint32(dexport[i].Value - PEBASE)) 1213 } 1214 1215 // put EXPORT Name Pointer Table 1216 v := int(e.Name + uint32(len(*flagOutfile)) + 1) 1217 1218 for i := 0; i < nexport; i++ { 1219 Lputl(uint32(v)) 1220 v += len(dexport[i].Extname) + 1 1221 } 1222 1223 // put EXPORT Ordinal Table 1224 for i := 0; i < nexport; i++ { 1225 Wputl(uint16(i)) 1226 } 1227 1228 // put Names 1229 strnput(*flagOutfile, len(*flagOutfile)+1) 1230 1231 for i := 0; i < nexport; i++ { 1232 strnput(dexport[i].Extname, len(dexport[i].Extname)+1) 1233 } 1234 sect.pad(uint32(size)) 1235 } 1236 1237 func (ctxt *Link) dope() { 1238 /* relocation table */ 1239 rel := ctxt.Syms.Lookup(".rel", 0) 1240 1241 rel.Attr |= AttrReachable 1242 rel.Type = SELFROSECT 1243 1244 initdynimport(ctxt) 1245 initdynexport(ctxt) 1246 } 1247 1248 func setpersrc(ctxt *Link, sym *Symbol) { 1249 if rsrcsym != nil { 1250 Errorf(sym, "too many .rsrc sections") 1251 } 1252 1253 rsrcsym = sym 1254 } 1255 1256 func addpersrc(ctxt *Link) { 1257 if rsrcsym == nil { 1258 return 1259 } 1260 1261 h := pefile.addSection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size)) 1262 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA 1263 h.checkOffset(coutbuf.Offset()) 1264 1265 // relocation 1266 var p []byte 1267 var r *Reloc 1268 var val uint32 1269 for ri := 0; ri < len(rsrcsym.R); ri++ { 1270 r = &rsrcsym.R[ri] 1271 p = rsrcsym.P[r.Off:] 1272 val = uint32(int64(h.virtualAddress) + r.Add) 1273 1274 // 32-bit little-endian 1275 p[0] = byte(val) 1276 1277 p[1] = byte(val >> 8) 1278 p[2] = byte(val >> 16) 1279 p[3] = byte(val >> 24) 1280 } 1281 1282 Cwrite(rsrcsym.P) 1283 h.pad(uint32(rsrcsym.Size)) 1284 1285 // update data directory 1286 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress 1287 1288 pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize 1289 } 1290 1291 func Asmbpe(ctxt *Link) { 1292 switch SysArch.Family { 1293 default: 1294 Exitf("unknown PE architecture: %v", SysArch.Family) 1295 case sys.AMD64, sys.I386: 1296 } 1297 1298 t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length)) 1299 t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ 1300 if Linkmode == LinkExternal { 1301 // some data symbols (e.g. masks) end up in the .text section, and they normally 1302 // expect larger alignment requirement than the default text section alignment. 1303 t.characteristics |= IMAGE_SCN_ALIGN_32BYTES 1304 } 1305 t.checkSegment(&Segtext) 1306 pefile.textSect = t 1307 1308 var d *peSection 1309 if Linkmode != LinkExternal { 1310 d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen)) 1311 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE 1312 d.checkSegment(&Segdata) 1313 pefile.dataSect = d 1314 } else { 1315 d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen)) 1316 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1317 d.checkSegment(&Segdata) 1318 pefile.dataSect = d 1319 1320 b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0) 1321 b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES 1322 b.pointerToRawData = 0 1323 pefile.bssSect = b 1324 } 1325 1326 pefile.addDWARF() 1327 1328 if Linkmode == LinkExternal { 1329 pefile.ctorsSect = pefile.addInitArray(ctxt) 1330 } 1331 1332 Cseek(int64(pefile.nextFileOffset)) 1333 if Linkmode != LinkExternal { 1334 addimports(ctxt, d) 1335 addexports(ctxt) 1336 } 1337 pefile.writeSymbolTableAndStringTable(ctxt) 1338 addpersrc(ctxt) 1339 if Linkmode == LinkExternal { 1340 pefile.emitRelocations(ctxt) 1341 } 1342 1343 pewrite(ctxt) 1344 }