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