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