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.
5 // PE (Portable Executable) file writing
6 // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
13 "cmd/link/internal/loader"
14 "cmd/link/internal/sym"
24 type IMAGE_IMPORT_DESCRIPTOR struct {
25 OriginalFirstThunk uint32
32 type IMAGE_EXPORT_DIRECTORY struct {
33 Characteristics uint32
39 NumberOfFunctions uint32
41 AddressOfFunctions uint32
43 AddressOfNameOrdinals uint32
47 // PEBASE is the base address for the executable.
48 // It is small for 32-bit and large for 64-bit.
51 // SectionAlignment must be greater than or equal to FileAlignment.
52 // The default is the page size for the architecture.
53 PESECTALIGN int64 = 0x1000
55 // FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
56 // The default is 512. If the SectionAlignment is less than
57 // the architecture's page size, then FileAlignment must match SectionAlignment.
58 PEFILEALIGN int64 = 2 << 8
62 IMAGE_SCN_CNT_CODE = 0x00000020
63 IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040
64 IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
65 IMAGE_SCN_LNK_OTHER = 0x00000100
66 IMAGE_SCN_LNK_INFO = 0x00000200
67 IMAGE_SCN_LNK_REMOVE = 0x00000800
68 IMAGE_SCN_LNK_COMDAT = 0x00001000
69 IMAGE_SCN_GPREL = 0x00008000
70 IMAGE_SCN_MEM_PURGEABLE = 0x00020000
71 IMAGE_SCN_MEM_16BIT = 0x00020000
72 IMAGE_SCN_MEM_LOCKED = 0x00040000
73 IMAGE_SCN_MEM_PRELOAD = 0x00080000
74 IMAGE_SCN_ALIGN_1BYTES = 0x00100000
75 IMAGE_SCN_ALIGN_2BYTES = 0x00200000
76 IMAGE_SCN_ALIGN_4BYTES = 0x00300000
77 IMAGE_SCN_ALIGN_8BYTES = 0x00400000
78 IMAGE_SCN_ALIGN_16BYTES = 0x00500000
79 IMAGE_SCN_ALIGN_32BYTES = 0x00600000
80 IMAGE_SCN_ALIGN_64BYTES = 0x00700000
81 IMAGE_SCN_ALIGN_128BYTES = 0x00800000
82 IMAGE_SCN_ALIGN_256BYTES = 0x00900000
83 IMAGE_SCN_ALIGN_512BYTES = 0x00A00000
84 IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000
85 IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000
86 IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000
87 IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000
88 IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000
89 IMAGE_SCN_MEM_DISCARDABLE = 0x02000000
90 IMAGE_SCN_MEM_NOT_CACHED = 0x04000000
91 IMAGE_SCN_MEM_NOT_PAGED = 0x08000000
92 IMAGE_SCN_MEM_SHARED = 0x10000000
93 IMAGE_SCN_MEM_EXECUTE = 0x20000000
94 IMAGE_SCN_MEM_READ = 0x40000000
95 IMAGE_SCN_MEM_WRITE = 0x80000000
98 // See https://docs.microsoft.com/en-us/windows/win32/debug/pe-format.
99 // TODO(crawshaw): add these constants to debug/pe.
101 IMAGE_SYM_TYPE_NULL = 0
102 IMAGE_SYM_TYPE_STRUCT = 8
103 IMAGE_SYM_DTYPE_FUNCTION = 2
104 IMAGE_SYM_DTYPE_ARRAY = 3
105 IMAGE_SYM_CLASS_EXTERNAL = 2
106 IMAGE_SYM_CLASS_STATIC = 3
108 IMAGE_REL_I386_DIR32 = 0x0006
109 IMAGE_REL_I386_DIR32NB = 0x0007
110 IMAGE_REL_I386_SECREL = 0x000B
111 IMAGE_REL_I386_REL32 = 0x0014
113 IMAGE_REL_AMD64_ADDR64 = 0x0001
114 IMAGE_REL_AMD64_ADDR32 = 0x0002
115 IMAGE_REL_AMD64_ADDR32NB = 0x0003
116 IMAGE_REL_AMD64_REL32 = 0x0004
117 IMAGE_REL_AMD64_SECREL = 0x000B
119 IMAGE_REL_ARM_ABSOLUTE = 0x0000
120 IMAGE_REL_ARM_ADDR32 = 0x0001
121 IMAGE_REL_ARM_ADDR32NB = 0x0002
122 IMAGE_REL_ARM_BRANCH24 = 0x0003
123 IMAGE_REL_ARM_BRANCH11 = 0x0004
124 IMAGE_REL_ARM_SECREL = 0x000F
126 IMAGE_REL_ARM64_ABSOLUTE = 0x0000
127 IMAGE_REL_ARM64_ADDR32 = 0x0001
128 IMAGE_REL_ARM64_ADDR32NB = 0x0002
129 IMAGE_REL_ARM64_BRANCH26 = 0x0003
130 IMAGE_REL_ARM64_PAGEBASE_REL21 = 0x0004
131 IMAGE_REL_ARM64_REL21 = 0x0005
132 IMAGE_REL_ARM64_PAGEOFFSET_12A = 0x0006
133 IMAGE_REL_ARM64_PAGEOFFSET_12L = 0x0007
134 IMAGE_REL_ARM64_SECREL = 0x0008
135 IMAGE_REL_ARM64_SECREL_LOW12A = 0x0009
136 IMAGE_REL_ARM64_SECREL_HIGH12A = 0x000A
137 IMAGE_REL_ARM64_SECREL_LOW12L = 0x000B
138 IMAGE_REL_ARM64_TOKEN = 0x000C
139 IMAGE_REL_ARM64_SECTION = 0x000D
140 IMAGE_REL_ARM64_ADDR64 = 0x000E
141 IMAGE_REL_ARM64_BRANCH19 = 0x000F
142 IMAGE_REL_ARM64_BRANCH14 = 0x0010
143 IMAGE_REL_ARM64_REL32 = 0x0011
145 IMAGE_REL_BASED_HIGHLOW = 3
146 IMAGE_REL_BASED_DIR64 = 10
150 PeMinimumTargetMajorVersion = 6
151 PeMinimumTargetMinorVersion = 1
154 // DOS stub that prints out
155 // "This program cannot be run in DOS mode."
156 // See IMAGE_DOS_HEADER in the Windows SDK for the format of the header used here.
157 var dosstub = []uint8{
304 rsrcsyms []loader.Sym
310 dexport = make([]loader.Sym, 0, 1024)
313 // peStringTable is a COFF string table.
314 type peStringTable struct {
319 // size returns size of string table t.
320 func (t *peStringTable) size() int {
321 // string table starts with 4-byte length at the beginning
322 return t.stringsLen + 4
325 // add adds string str to string table t.
326 func (t *peStringTable) add(str string) int {
328 t.strings = append(t.strings, str)
329 t.stringsLen += len(str) + 1 // each string will have 0 appended to it
333 // write writes string table t into the output file.
334 func (t *peStringTable) write(out *OutBuf) {
335 out.Write32(uint32(t.size()))
336 for _, s := range t.strings {
342 // peSection represents section from COFF section table.
343 type peSection struct {
346 index int // one-based index into the Section Table
348 virtualAddress uint32
350 pointerToRawData uint32
351 pointerToRelocations uint32
352 numberOfRelocations uint16
353 characteristics uint32
356 // checkOffset verifies COFF section sect offset in the file.
357 func (sect *peSection) checkOffset(off int64) {
358 if off != int64(sect.pointerToRawData) {
359 Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(off))
364 // checkSegment verifies COFF section sect matches address
365 // and file offset provided in segment seg.
366 func (sect *peSection) checkSegment(seg *sym.Segment) {
367 if seg.Vaddr-uint64(PEBASE) != uint64(sect.virtualAddress) {
368 Errorf(nil, "%s.VirtualAddress = %#x, want %#x", sect.name, uint64(int64(sect.virtualAddress)), uint64(int64(seg.Vaddr-uint64(PEBASE))))
371 if seg.Fileoff != uint64(sect.pointerToRawData) {
372 Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(int64(seg.Fileoff)))
377 // pad adds zeros to the section sect. It writes as many bytes
378 // as necessary to make section sect.SizeOfRawData bytes long.
379 // It assumes that n bytes are already written to the file.
380 func (sect *peSection) pad(out *OutBuf, n uint32) {
381 out.WriteStringN("", int(sect.sizeOfRawData-n))
384 // write writes COFF section sect into the output file.
385 func (sect *peSection) write(out *OutBuf, linkmode LinkMode) error {
386 h := pe.SectionHeader32{
387 VirtualSize: sect.virtualSize,
388 SizeOfRawData: sect.sizeOfRawData,
389 PointerToRawData: sect.pointerToRawData,
390 PointerToRelocations: sect.pointerToRelocations,
391 NumberOfRelocations: sect.numberOfRelocations,
392 Characteristics: sect.characteristics,
394 if linkmode != LinkExternal {
395 h.VirtualAddress = sect.virtualAddress
397 copy(h.Name[:], sect.shortName)
398 return binary.Write(out, binary.LittleEndian, h)
401 // emitRelocations emits the relocation entries for the sect.
402 // The actual relocations are emitted by relocfn.
403 // This updates the corresponding PE section table entry
404 // with the relocation offset and count.
405 func (sect *peSection) emitRelocations(out *OutBuf, relocfn func() int) {
406 sect.pointerToRelocations = uint32(out.Offset())
407 // first entry: extended relocs
408 out.Write32(0) // placeholder for number of relocation + 1
415 out.SeekSet(int64(sect.pointerToRelocations))
416 out.Write32(uint32(n))
420 sect.characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
422 sect.pointerToRelocations += 10 // skip the extend reloc entry
424 sect.numberOfRelocations = uint16(n - 1)
427 // peFile is used to build COFF file.
429 sections []*peSection
430 stringTable peStringTable
438 nextSectOffset uint32
439 nextFileOffset uint32
440 symtabOffset int64 // offset to the start of symbol table
441 symbolCount int // number of symbol table records written
442 dataDirectory [16]pe.DataDirectory
445 // addSection adds section to the COFF file f.
446 func (f *peFile) addSection(name string, sectsize int, filesize int) *peSection {
450 index: len(f.sections) + 1,
451 virtualAddress: f.nextSectOffset,
452 pointerToRawData: f.nextFileOffset,
454 f.nextSectOffset = uint32(Rnd(int64(f.nextSectOffset)+int64(sectsize), PESECTALIGN))
456 sect.virtualSize = uint32(sectsize)
457 sect.sizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN))
458 f.nextFileOffset += sect.sizeOfRawData
460 sect.sizeOfRawData = uint32(sectsize)
462 f.sections = append(f.sections, sect)
466 // addDWARFSection adds DWARF section to the COFF file f.
467 // This function is similar to addSection, but DWARF section names are
468 // longer than 8 characters, so they need to be stored in the string table.
469 func (f *peFile) addDWARFSection(name string, size int) *peSection {
471 Exitf("DWARF section %q is empty", name)
473 // DWARF section names are longer than 8 characters.
474 // PE format requires such names to be stored in string table,
475 // and section names replaced with slash (/) followed by
476 // correspondent string table index.
477 // see http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx
479 off := f.stringTable.add(name)
480 h := f.addSection(name, size, size)
481 h.shortName = fmt.Sprintf("/%d", off)
482 h.characteristics = IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA
486 // addDWARF adds DWARF information to the COFF file f.
487 func (f *peFile) addDWARF() {
488 if *FlagS { // disable symbol table
491 if *FlagW { // disable dwarf
494 for _, sect := range Segdwarf.Sections {
495 h := f.addDWARFSection(sect.Name, int(sect.Length))
496 fileoff := sect.Vaddr - Segdwarf.Vaddr + Segdwarf.Fileoff
497 if uint64(h.pointerToRawData) != fileoff {
498 Exitf("%s.PointerToRawData = %#x, want %#x", sect.Name, h.pointerToRawData, fileoff)
503 // addSEH adds SEH information to the COFF file f.
504 func (f *peFile) addSEH(ctxt *Link) {
505 // .pdata section can exist without the .xdata section.
506 // .xdata section depends on the .pdata section.
507 if Segpdata.Length == 0 {
510 d := pefile.addSection(".pdata", int(Segpdata.Length), int(Segpdata.Length))
511 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
512 if ctxt.LinkMode == LinkExternal {
513 // Some gcc versions don't honor the default alignment for the .pdata section.
514 d.characteristics |= IMAGE_SCN_ALIGN_4BYTES
517 d.checkSegment(&Segpdata)
518 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = d.virtualAddress
519 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = d.virtualSize
521 if Segxdata.Length > 0 {
522 d = pefile.addSection(".xdata", int(Segxdata.Length), int(Segxdata.Length))
523 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
524 if ctxt.LinkMode == LinkExternal {
525 // Some gcc versions don't honor the default alignment for the .xdata section.
526 d.characteristics |= IMAGE_SCN_ALIGN_4BYTES
529 d.checkSegment(&Segxdata)
533 // addInitArray adds .ctors COFF section to the file f.
534 func (f *peFile) addInitArray(ctxt *Link) *peSection {
535 // The size below was determined by the specification for array relocations,
536 // and by observing what GCC writes here. If the initarray section grows to
537 // contain more than one constructor entry, the size will need to be 8 * constructor_count.
538 // However, the entire Go runtime is initialized from just one function, so it is unlikely
539 // that this will need to grow in the future.
542 switch buildcfg.GOARCH {
544 Exitf("peFile.addInitArray: unsupported GOARCH=%q\n", buildcfg.GOARCH)
547 alignment = IMAGE_SCN_ALIGN_4BYTES
548 case "amd64", "arm64":
550 alignment = IMAGE_SCN_ALIGN_8BYTES
552 sect := f.addSection(".ctors", size, size)
553 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | alignment
554 sect.sizeOfRawData = uint32(size)
555 ctxt.Out.SeekSet(int64(sect.pointerToRawData))
556 sect.checkOffset(ctxt.Out.Offset())
558 init_entry := ctxt.loader.Lookup(*flagEntrySymbol, 0)
559 addr := uint64(ctxt.loader.SymValue(init_entry)) - ctxt.loader.SymSect(init_entry).Vaddr
560 switch buildcfg.GOARCH {
562 ctxt.Out.Write32(uint32(addr))
563 case "amd64", "arm64":
564 ctxt.Out.Write64(addr)
569 // emitRelocations emits relocation entries for go.o in external linking.
570 func (f *peFile) emitRelocations(ctxt *Link) {
571 for ctxt.Out.Offset()&7 != 0 {
577 // relocsect relocates symbols from first in section sect, and returns
578 // the total number of relocations emitted.
579 relocsect := func(sect *sym.Section, syms []loader.Sym, base uint64) int {
580 // If main section has no bits, nothing to relocate.
581 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
584 sect.Reloff = uint64(ctxt.Out.Offset())
585 for i, s := range syms {
586 if !ldr.AttrReachable(s) {
589 if uint64(ldr.SymValue(s)) >= sect.Vaddr {
594 eaddr := int64(sect.Vaddr + sect.Length)
595 for _, s := range syms {
596 if !ldr.AttrReachable(s) {
599 if ldr.SymValue(s) >= eaddr {
602 // Compute external relocations on the go, and pass to PEreloc1
604 relocs := ldr.Relocs(s)
605 for ri := 0; ri < relocs.Count(); ri++ {
607 rr, ok := extreloc(ctxt, ldr, s, r)
612 ctxt.Errorf(s, "missing xsym in relocation")
615 if ldr.SymDynid(rr.Xsym) < 0 {
616 ctxt.Errorf(s, "reloc %d to non-coff symbol %s (outer=%s) %d", r.Type(), ldr.SymName(r.Sym()), ldr.SymName(rr.Xsym), ldr.SymType(r.Sym()))
618 if !thearch.PEreloc1(ctxt.Arch, ctxt.Out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-base)) {
619 ctxt.Errorf(s, "unsupported obj reloc %v/%d to %s", r.Type(), r.Siz(), ldr.SymName(r.Sym()))
623 sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
624 const relocLen = 4 + 4 + 2
625 return int(sect.Rellen / relocLen)
628 type relsect struct {
634 {f.textSect, &Segtext, ctxt.Textp},
635 {f.rdataSect, &Segrodata, ctxt.datap},
636 {f.dataSect, &Segdata, ctxt.datap},
639 sects = append(sects, relsect{f.pdataSect, &Segpdata, []loader.Sym{sehp.pdata}})
642 sects = append(sects, relsect{f.xdataSect, &Segxdata, []loader.Sym{sehp.xdata}})
644 for _, s := range sects {
645 s.peSect.emitRelocations(ctxt.Out, func() int {
647 for _, sect := range s.seg.Sections {
648 n += relocsect(sect, s.syms, s.seg.Vaddr)
655 for i := 0; i < len(Segdwarf.Sections); i++ {
656 sect := Segdwarf.Sections[i]
658 if si.secSym() != loader.Sym(sect.Sym) ||
659 ldr.SymSect(si.secSym()) != sect {
660 panic("inconsistency between dwarfp and Segdwarf")
662 for _, pesect := range f.sections {
663 if sect.Name == pesect.name {
664 pesect.emitRelocations(ctxt.Out, func() int {
665 return relocsect(sect, si.syms, sect.Vaddr)
670 Errorf(nil, "emitRelocations: could not find %q section", sect.Name)
673 if f.ctorsSect == nil {
677 f.ctorsSect.emitRelocations(ctxt.Out, func() int {
678 dottext := ldr.Lookup(".text", 0)
680 ctxt.Out.Write32(uint32(ldr.SymDynid(dottext)))
681 switch buildcfg.GOARCH {
683 ctxt.Errorf(dottext, "unknown architecture for PE: %q\n", buildcfg.GOARCH)
685 ctxt.Out.Write16(IMAGE_REL_I386_DIR32)
687 ctxt.Out.Write16(IMAGE_REL_AMD64_ADDR64)
689 ctxt.Out.Write16(IMAGE_REL_ARM_ADDR32)
691 ctxt.Out.Write16(IMAGE_REL_ARM64_ADDR64)
697 // writeSymbol appends symbol s to file f symbol table.
698 // It also sets s.Dynid to written symbol number.
699 func (f *peFile) writeSymbol(out *OutBuf, ldr *loader.Loader, s loader.Sym, name string, value int64, sectidx int, typ uint16, class uint8) {
702 out.Write32(uint32(f.stringTable.add(name)))
704 out.WriteStringN(name, 8)
706 out.Write32(uint32(value))
707 out.Write16(uint16(sectidx))
710 out.Write8(0) // no aux entries
712 ldr.SetSymDynid(s, int32(f.symbolCount))
717 // mapToPESection searches peFile f for s symbol's location.
718 // It returns PE section index, and offset within that section.
719 func (f *peFile) mapToPESection(ldr *loader.Loader, s loader.Sym, linkmode LinkMode) (pesectidx int, offset int64, err error) {
720 sect := ldr.SymSect(s)
722 return 0, 0, fmt.Errorf("could not map %s symbol with no section", ldr.SymName(s))
724 if sect.Seg == &Segtext {
725 return f.textSect.index, int64(uint64(ldr.SymValue(s)) - Segtext.Vaddr), nil
727 if sect.Seg == &Segrodata {
728 return f.rdataSect.index, int64(uint64(ldr.SymValue(s)) - Segrodata.Vaddr), nil
730 if sect.Seg != &Segdata {
731 return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .rdata or .data section", ldr.SymName(s))
733 v := uint64(ldr.SymValue(s)) - Segdata.Vaddr
734 if linkmode != LinkExternal {
735 return f.dataSect.index, int64(v), nil
737 if ldr.SymType(s) == sym.SDATA {
738 return f.dataSect.index, int64(v), nil
740 // Note: although address of runtime.edata (type sym.SDATA) is at the start of .bss section
741 // it still belongs to the .data section, not the .bss section.
742 if v < Segdata.Filelen {
743 return f.dataSect.index, int64(v), nil
745 return f.bssSect.index, int64(v - Segdata.Filelen), nil
748 var isLabel = make(map[loader.Sym]bool)
750 func AddPELabelSym(ldr *loader.Loader, s loader.Sym) {
754 // writeSymbols writes all COFF symbol table records.
755 func (f *peFile) writeSymbols(ctxt *Link) {
757 addsym := func(s loader.Sym) {
759 if ldr.SymSect(s) == nil && t != sym.SDYNIMPORT && t != sym.SHOSTOBJ && t != sym.SUNDEFEXT {
763 name := ldr.SymName(s)
765 // Only windows/386 requires underscore prefix on external symbols.
766 if ctxt.Is386() && ctxt.IsExternal() &&
767 (t == sym.SHOSTOBJ || t == sym.SUNDEFEXT || ldr.AttrCgoExport(s) ||
768 // TODO(cuonglm): remove this hack
770 // Previously, windows/386 requires underscore prefix on external symbols,
771 // but that's only applied for SHOSTOBJ/SUNDEFEXT or cgo export symbols.
772 // "go.buildid" is STEXT, "type.*" is STYPE, thus they are not prefixed
775 // In external linking mode, the external linker can't resolve them as
776 // external symbols. But we are lucky that they have "." in their name,
777 // so the external linker see them as Forwarder RVA exports. See:
779 // - https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#export-address-table
780 // - https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=ld/pe-dll.c;h=e7b82ba6ffadf74dc1b9ee71dc13d48336941e51;hb=HEAD#l972
782 // CL 317917 changes "." to ":" in symbols name, so these symbols can not be
783 // found by external linker anymore. So a hacky way is adding the
784 // underscore prefix for these 2 symbols. I don't have enough knowledge to
785 // verify whether adding the underscore for all STEXT/STYPE symbols are
786 // fine, even if it could be, that would be done in future CL.
787 name == "go:buildid" || name == "type:*") {
791 name = mangleABIName(ctxt, ldr, s, name)
793 var peSymType uint16 = IMAGE_SYM_TYPE_NULL
795 case sym.STEXT, sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
796 // Microsoft's PE documentation is contradictory. It says that the symbol's complex type
797 // is stored in the pesym.Type most significant byte, but MSVC, LLVM, and mingw store it
798 // in the 4 high bits of the less significant byte. Also, the PE documentation says that
799 // the basic type for a function should be IMAGE_SYM_TYPE_VOID,
800 // but the reality is that it uses IMAGE_SYM_TYPE_NULL instead.
801 peSymType = IMAGE_SYM_DTYPE_FUNCTION<<4 + IMAGE_SYM_TYPE_NULL
803 sect, value, err := f.mapToPESection(ldr, s, ctxt.LinkMode)
806 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
808 ctxt.Errorf(s, "addpesym: %v", err)
811 class := IMAGE_SYM_CLASS_EXTERNAL
812 if ldr.IsFileLocal(s) || ldr.AttrVisibilityHidden(s) || ldr.AttrLocal(s) {
813 class = IMAGE_SYM_CLASS_STATIC
815 f.writeSymbol(ctxt.Out, ldr, s, name, value, sect, peSymType, uint8(class))
818 if ctxt.LinkMode == LinkExternal {
819 // Include section symbols as external, because
820 // .ctors and .debug_* section relocations refer to it.
821 for _, pesect := range f.sections {
822 s := ldr.LookupOrCreateSym(pesect.name, 0)
823 f.writeSymbol(ctxt.Out, ldr, s, pesect.name, 0, pesect.index, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC)
827 // Add special runtime.text and runtime.etext symbols.
828 s := ldr.Lookup("runtime.text", 0)
829 if ldr.SymType(s) == sym.STEXT {
832 s = ldr.Lookup("runtime.etext", 0)
833 if ldr.SymType(s) == sym.STEXT {
838 for _, s := range ctxt.Textp {
842 shouldBeInSymbolTable := func(s loader.Sym) bool {
843 if ldr.AttrNotInSymbolTable(s) {
846 name := ldr.SymName(s) // TODO: try not to read the name
847 if name == "" || name[0] == '.' {
853 // Add data symbols and external references.
854 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
855 if !ldr.AttrReachable(s) {
859 if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
860 if t == sym.STLSBSS {
863 if !shouldBeInSymbolTable(s) {
870 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
873 if len(isLabel) > 0 && isLabel[s] {
880 // writeSymbolTableAndStringTable writes out symbol and string tables for peFile f.
881 func (f *peFile) writeSymbolTableAndStringTable(ctxt *Link) {
882 f.symtabOffset = ctxt.Out.Offset()
884 // write COFF symbol table
885 if !*FlagS || ctxt.LinkMode == LinkExternal {
889 // update COFF file header and section table
890 size := f.stringTable.size() + 18*f.symbolCount
892 if ctxt.LinkMode != LinkExternal {
893 // We do not really need .symtab for go.o, and if we have one, ld
894 // will also include it in the exe, and that will confuse windows.
895 h = f.addSection(".symtab", size, size)
896 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
897 h.checkOffset(f.symtabOffset)
900 // write COFF string table
901 f.stringTable.write(ctxt.Out)
902 if ctxt.LinkMode != LinkExternal {
903 h.pad(ctxt.Out, uint32(size))
907 // writeFileHeader writes COFF file header for peFile f.
908 func (f *peFile) writeFileHeader(ctxt *Link) {
911 switch ctxt.Arch.Family {
913 Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
915 fh.Machine = pe.IMAGE_FILE_MACHINE_AMD64
917 fh.Machine = pe.IMAGE_FILE_MACHINE_I386
919 fh.Machine = pe.IMAGE_FILE_MACHINE_ARMNT
921 fh.Machine = pe.IMAGE_FILE_MACHINE_ARM64
924 fh.NumberOfSections = uint16(len(f.sections))
926 // Being able to produce identical output for identical input is
927 // much more beneficial than having build timestamp in the header.
930 if ctxt.LinkMode != LinkExternal {
931 fh.Characteristics = pe.IMAGE_FILE_EXECUTABLE_IMAGE
932 switch ctxt.Arch.Family {
933 case sys.AMD64, sys.I386:
934 if ctxt.BuildMode != BuildModePIE {
935 fh.Characteristics |= pe.IMAGE_FILE_RELOCS_STRIPPED
940 var oh64 pe.OptionalHeader64
941 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
942 fh.Characteristics |= pe.IMAGE_FILE_LARGE_ADDRESS_AWARE
944 var oh pe.OptionalHeader32
945 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
946 fh.Characteristics |= pe.IMAGE_FILE_32BIT_MACHINE
949 fh.PointerToSymbolTable = uint32(f.symtabOffset)
950 fh.NumberOfSymbols = uint32(f.symbolCount)
952 binary.Write(ctxt.Out, binary.LittleEndian, &fh)
955 // writeOptionalHeader writes COFF optional header for peFile f.
956 func (f *peFile) writeOptionalHeader(ctxt *Link) {
957 var oh pe.OptionalHeader32
958 var oh64 pe.OptionalHeader64
961 oh64.Magic = 0x20b // PE32+
963 oh.Magic = 0x10b // PE32
964 oh.BaseOfData = f.dataSect.virtualAddress
967 // Fill out both oh64 and oh. We only use one. Oh well.
968 oh64.MajorLinkerVersion = 3
969 oh.MajorLinkerVersion = 3
970 oh64.MinorLinkerVersion = 0
971 oh.MinorLinkerVersion = 0
972 oh64.SizeOfCode = f.textSect.sizeOfRawData
973 oh.SizeOfCode = f.textSect.sizeOfRawData
974 oh64.SizeOfInitializedData = f.dataSect.sizeOfRawData
975 oh.SizeOfInitializedData = f.dataSect.sizeOfRawData
976 oh64.SizeOfUninitializedData = 0
977 oh.SizeOfUninitializedData = 0
978 if ctxt.LinkMode != LinkExternal {
979 oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
980 oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
982 oh64.BaseOfCode = f.textSect.virtualAddress
983 oh.BaseOfCode = f.textSect.virtualAddress
984 oh64.ImageBase = uint64(PEBASE)
985 oh.ImageBase = uint32(PEBASE)
986 oh64.SectionAlignment = uint32(PESECTALIGN)
987 oh.SectionAlignment = uint32(PESECTALIGN)
988 oh64.FileAlignment = uint32(PEFILEALIGN)
989 oh.FileAlignment = uint32(PEFILEALIGN)
990 oh64.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
991 oh.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
992 oh64.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
993 oh.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
994 oh64.MajorImageVersion = 1
995 oh.MajorImageVersion = 1
996 oh64.MinorImageVersion = 0
997 oh.MinorImageVersion = 0
998 oh64.MajorSubsystemVersion = PeMinimumTargetMajorVersion
999 oh.MajorSubsystemVersion = PeMinimumTargetMajorVersion
1000 oh64.MinorSubsystemVersion = PeMinimumTargetMinorVersion
1001 oh.MinorSubsystemVersion = PeMinimumTargetMinorVersion
1002 oh64.SizeOfImage = f.nextSectOffset
1003 oh.SizeOfImage = f.nextSectOffset
1004 oh64.SizeOfHeaders = uint32(PEFILEHEADR)
1005 oh.SizeOfHeaders = uint32(PEFILEHEADR)
1007 oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
1008 oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
1010 oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
1011 oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
1014 // Mark as having awareness of terminal services, to avoid ancient compatibility hacks.
1015 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
1016 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
1019 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
1020 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
1022 // The DLL can be relocated at load time.
1023 if needPEBaseReloc(ctxt) {
1024 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
1025 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
1028 // Image can handle a high entropy 64-bit virtual address space.
1029 if ctxt.BuildMode == BuildModePIE {
1030 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
1033 // Disable stack growth as we don't want Windows to
1034 // fiddle with the thread stack limits, which we set
1035 // ourselves to circumvent the stack checks in the
1036 // Windows exception dispatcher.
1037 // Commit size must be strictly less than reserve
1038 // size otherwise reserve will be rounded up to a
1039 // larger size, as verified with VMMap.
1041 // On 64-bit, we always reserve 2MB stacks. "Pure" Go code is
1042 // okay with much smaller stacks, but the syscall package
1043 // makes it easy to call into arbitrary C code without cgo,
1044 // and system calls even in "pure" Go code are actually C
1045 // calls that may need more stack than we think.
1047 // The default stack reserve size directly affects only the main
1050 // For other threads, the runtime explicitly asks the kernel
1051 // to use the default stack size so that all stacks are
1054 // At thread start, in minit, the runtime queries the OS for
1055 // the actual stack bounds so that the stack size doesn't need
1056 // to be hard-coded into the runtime.
1057 oh64.SizeOfStackReserve = 0x00200000
1059 oh64.SizeOfStackCommit = 0x00001000
1061 // TODO(brainman): Maybe remove optional header writing altogether for cgo.
1062 // For cgo it is the external linker that is building final executable.
1063 // And it probably does not use any information stored in optional header.
1064 oh64.SizeOfStackCommit = 0x00200000 - 0x2000 // account for 2 guard pages
1067 oh.SizeOfStackReserve = 0x00100000
1069 oh.SizeOfStackCommit = 0x00001000
1071 oh.SizeOfStackCommit = 0x00100000 - 0x2000 // account for 2 guard pages
1074 oh64.SizeOfHeapReserve = 0x00100000
1075 oh.SizeOfHeapReserve = 0x00100000
1076 oh64.SizeOfHeapCommit = 0x00001000
1077 oh.SizeOfHeapCommit = 0x00001000
1078 oh64.NumberOfRvaAndSizes = 16
1079 oh.NumberOfRvaAndSizes = 16
1082 oh64.DataDirectory = f.dataDirectory
1084 oh.DataDirectory = f.dataDirectory
1088 binary.Write(ctxt.Out, binary.LittleEndian, &oh64)
1090 binary.Write(ctxt.Out, binary.LittleEndian, &oh)
1096 func Peinit(ctxt *Link) {
1099 if ctxt.Arch.PtrSize == 8 {
1100 // 64-bit architectures
1103 if ctxt.Arch.Family == sys.AMD64 {
1104 // TODO(rsc): For cgo we currently use 32-bit relocations
1105 // that fail when PEBASE is too large.
1106 // We need to fix this, but for now, use a smaller PEBASE.
1109 var oh64 pe.OptionalHeader64
1110 l = binary.Size(&oh64)
1112 // 32-bit architectures
1114 var oh pe.OptionalHeader32
1115 l = binary.Size(&oh)
1118 if ctxt.LinkMode == LinkExternal {
1119 // .rdata section will contain "masks" and "shifts" symbols, and they
1120 // need to be aligned to 16-bytes. So make all sections aligned
1121 // to 32-byte and mark them all IMAGE_SCN_ALIGN_32BYTES so external
1122 // linker will honour that requirement.
1125 // We are creating an object file. The absolute address is irrelevant.
1129 var sh [16]pe.SectionHeader32
1130 var fh pe.FileHeader
1131 PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
1132 if ctxt.LinkMode != LinkExternal {
1133 PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
1137 pefile.nextSectOffset = uint32(PESECTHEADR)
1138 pefile.nextFileOffset = uint32(PEFILEHEADR)
1140 if ctxt.LinkMode == LinkInternal {
1141 // some mingw libs depend on this symbol, for example, FindPESectionByName
1142 for _, name := range [2]string{"__image_base__", "_image_base__"} {
1143 sb := ctxt.loader.CreateSymForUpdate(name, 0)
1144 sb.SetType(sym.SDATA)
1146 ctxt.loader.SetAttrSpecial(sb.Sym(), true)
1147 ctxt.loader.SetAttrLocal(sb.Sym(), true)
1152 if *FlagRound == -1 {
1153 *FlagRound = PESECTALIGN
1155 if *FlagTextAddr == -1 {
1156 *FlagTextAddr = Rnd(PEBASE, *FlagRound) + int64(PESECTHEADR)
1160 func pewrite(ctxt *Link) {
1162 if ctxt.LinkMode != LinkExternal {
1163 ctxt.Out.Write(dosstub)
1164 ctxt.Out.WriteStringN("PE", 4)
1167 pefile.writeFileHeader(ctxt)
1169 pefile.writeOptionalHeader(ctxt)
1171 for _, sect := range pefile.sections {
1172 sect.write(ctxt.Out, ctxt.LinkMode)
1176 func strput(out *OutBuf, s string) {
1179 // string must be padded to even size
1180 if (len(s)+1)%2 != 0 {
1185 func initdynimport(ctxt *Link) *Dll {
1191 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1192 if !ldr.AttrReachable(s) || ldr.SymType(s) != sym.SDYNIMPORT {
1195 dynlib := ldr.SymDynimplib(s)
1196 for d = dr; d != nil; d = d.next {
1197 if d.name == dynlib {
1211 // Because external link requires properly stdcall decorated name,
1212 // all external symbols in runtime use %n to denote that the number
1213 // of uinptrs this function consumes. Store the argsize and discard
1214 // the %n suffix if any.
1216 extName := ldr.SymExtname(s)
1217 if i := strings.IndexByte(extName, '%'); i >= 0 {
1219 m.argsize, err = strconv.Atoi(extName[i+1:])
1221 ctxt.Errorf(s, "failed to parse stdcall decoration: %v", err)
1223 m.argsize *= ctxt.Arch.PtrSize
1224 ldr.SetSymExtname(s, extName[:i])
1232 if ctxt.IsExternal() {
1233 // Add real symbol name
1234 for d := dr; d != nil; d = d.next {
1235 for m = d.ms; m != nil; m = m.next {
1236 sb := ldr.MakeSymbolUpdater(m.s)
1237 sb.SetType(sym.SDATA)
1238 sb.Grow(int64(ctxt.Arch.PtrSize))
1239 dynName := sb.Extname()
1240 // only windows/386 requires stdcall decoration
1241 if ctxt.Is386() && m.argsize >= 0 {
1242 dynName += fmt.Sprintf("@%d", m.argsize)
1244 dynSym := ldr.CreateSymForUpdate(dynName, 0)
1245 dynSym.SetType(sym.SHOSTOBJ)
1246 r, _ := sb.AddRel(objabi.R_ADDR)
1247 r.SetSym(dynSym.Sym())
1248 r.SetSiz(uint8(ctxt.Arch.PtrSize))
1252 dynamic := ldr.CreateSymForUpdate(".windynamic", 0)
1253 dynamic.SetType(sym.SWINDOWS)
1254 for d := dr; d != nil; d = d.next {
1255 for m = d.ms; m != nil; m = m.next {
1256 sb := ldr.MakeSymbolUpdater(m.s)
1257 sb.SetType(sym.SWINDOWS)
1258 sb.SetValue(dynamic.Size())
1259 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
1260 dynamic.AddInteriorSym(m.s)
1263 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
1270 // peimporteddlls returns the gcc command line argument to link all imported
1272 func peimporteddlls() []string {
1275 for d := dr; d != nil; d = d.next {
1276 dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
1282 func addimports(ctxt *Link, datsect *peSection) {
1284 startoff := ctxt.Out.Offset()
1285 dynamic := ldr.LookupOrCreateSym(".windynamic", 0)
1287 // skip import descriptor table (will write it later)
1290 for d := dr; d != nil; d = d.next {
1293 ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
1296 for d := dr; d != nil; d = d.next {
1297 d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff)
1298 strput(ctxt.Out, d.name)
1301 // write function names
1302 for d := dr; d != nil; d = d.next {
1303 for m := d.ms; m != nil; m = m.next {
1304 m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
1305 ctxt.Out.Write16(0) // hint
1306 strput(ctxt.Out, ldr.SymExtname(m.s))
1310 // write OriginalFirstThunks
1311 oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff)
1313 n = uint64(ctxt.Out.Offset())
1314 for d := dr; d != nil; d = d.next {
1315 d.thunkoff = uint64(ctxt.Out.Offset()) - n
1316 for m := d.ms; m != nil; m = m.next {
1318 ctxt.Out.Write64(m.off)
1320 ctxt.Out.Write32(uint32(m.off))
1331 // add pe section and pad it at the end
1332 n = uint64(ctxt.Out.Offset()) - uint64(startoff)
1334 isect := pefile.addSection(".idata", int(n), int(n))
1335 isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
1336 isect.checkOffset(startoff)
1337 isect.pad(ctxt.Out, uint32(n))
1338 endoff := ctxt.Out.Offset()
1340 // write FirstThunks (allocated in .data section)
1341 ftbase := uint64(ldr.SymValue(dynamic)) - uint64(datsect.virtualAddress) - uint64(PEBASE)
1343 ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase))
1344 for d := dr; d != nil; d = d.next {
1345 for m := d.ms; m != nil; m = m.next {
1347 ctxt.Out.Write64(m.off)
1349 ctxt.Out.Write32(uint32(m.off))
1360 // finally write import descriptor table
1362 out.SeekSet(startoff)
1364 for d := dr; d != nil; d = d.next {
1365 out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff))
1368 out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff))
1369 out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff))
1372 out.Write32(0) //end
1378 // update data directory
1379 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
1380 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
1381 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(ldr.SymValue(dynamic) - PEBASE)
1382 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(ldr.SymSize(dynamic))
1387 func initdynexport(ctxt *Link) {
1389 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1390 if !ldr.AttrReachable(s) || !ldr.AttrCgoExportDynamic(s) {
1393 if len(dexport)+1 > cap(dexport) {
1394 ctxt.Errorf(s, "pe dynexport table is full")
1398 dexport = append(dexport, s)
1401 sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) })
1404 func addexports(ctxt *Link) {
1406 var e IMAGE_EXPORT_DIRECTORY
1408 nexport := len(dexport)
1409 size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
1410 for _, s := range dexport {
1411 size += len(ldr.SymExtname(s)) + 1
1418 sect := pefile.addSection(".edata", size, size)
1419 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
1420 sect.checkOffset(ctxt.Out.Offset())
1421 va := int(sect.virtualAddress)
1422 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
1423 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
1425 vaName := va + binary.Size(&e) + nexport*4
1426 vaAddr := va + binary.Size(&e)
1427 vaNa := va + binary.Size(&e) + nexport*8
1429 e.Characteristics = 0
1432 e.NumberOfFunctions = uint32(nexport)
1433 e.NumberOfNames = uint32(nexport)
1434 e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
1436 e.AddressOfFunctions = uint32(vaAddr)
1437 e.AddressOfNames = uint32(vaName)
1438 e.AddressOfNameOrdinals = uint32(vaNa)
1442 // put IMAGE_EXPORT_DIRECTORY
1443 binary.Write(out, binary.LittleEndian, &e)
1445 // put EXPORT Address Table
1446 for _, s := range dexport {
1447 out.Write32(uint32(ldr.SymValue(s) - PEBASE))
1450 // put EXPORT Name Pointer Table
1451 v := int(e.Name + uint32(len(*flagOutfile)) + 1)
1453 for _, s := range dexport {
1454 out.Write32(uint32(v))
1455 v += len(ldr.SymExtname(s)) + 1
1458 // put EXPORT Ordinal Table
1459 for i := 0; i < nexport; i++ {
1460 out.Write16(uint16(i))
1464 out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
1466 for _, s := range dexport {
1467 name := ldr.SymExtname(s)
1468 out.WriteStringN(name, len(name)+1)
1470 sect.pad(out, uint32(size))
1473 // peBaseRelocEntry represents a single relocation entry.
1474 type peBaseRelocEntry struct {
1478 // peBaseRelocBlock represents a Base Relocation Block. A block
1479 // is a collection of relocation entries in a page, where each
1480 // entry describes a single relocation.
1481 // The block page RVA (Relative Virtual Address) is the index
1482 // into peBaseRelocTable.blocks.
1483 type peBaseRelocBlock struct {
1484 entries []peBaseRelocEntry
1487 // pePages is a type used to store the list of pages for which there
1488 // are base relocation blocks. This is defined as a type so that
1489 // it can be sorted.
1490 type pePages []uint32
1492 func (p pePages) Len() int { return len(p) }
1493 func (p pePages) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
1494 func (p pePages) Less(i, j int) bool { return p[i] < p[j] }
1496 // A PE base relocation table is a list of blocks, where each block
1497 // contains relocation information for a single page. The blocks
1498 // must be emitted in order of page virtual address.
1499 // See https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-reloc-section-image-only
1500 type peBaseRelocTable struct {
1501 blocks map[uint32]peBaseRelocBlock
1503 // pePages is a list of keys into blocks map.
1504 // It is stored separately for ease of sorting.
1508 func (rt *peBaseRelocTable) init(ctxt *Link) {
1509 rt.blocks = make(map[uint32]peBaseRelocBlock)
1512 func (rt *peBaseRelocTable) addentry(ldr *loader.Loader, s loader.Sym, r *loader.Reloc) {
1513 // pageSize is the size in bytes of a page
1514 // described by a base relocation block.
1515 const pageSize = 0x1000
1516 const pageMask = pageSize - 1
1518 addr := ldr.SymValue(s) + int64(r.Off()) - int64(PEBASE)
1519 page := uint32(addr &^ pageMask)
1520 off := uint32(addr & pageMask)
1522 b, ok := rt.blocks[page]
1524 rt.pages = append(rt.pages, page)
1527 e := peBaseRelocEntry{
1528 typeOff: uint16(off & 0xFFF),
1534 Exitf("unsupported relocation size %d\n", r.Siz)
1536 e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12)
1538 e.typeOff |= uint16(IMAGE_REL_BASED_DIR64 << 12)
1541 b.entries = append(b.entries, e)
1545 func (rt *peBaseRelocTable) write(ctxt *Link) {
1548 // sort the pages array
1551 for _, p := range rt.pages {
1553 const sizeOfPEbaseRelocBlock = 8 // 2 * sizeof(uint32)
1554 blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2)
1556 out.Write32(blockSize)
1558 for _, e := range b.entries {
1559 out.Write16(e.typeOff)
1564 func addPEBaseRelocSym(ldr *loader.Loader, s loader.Sym, rt *peBaseRelocTable) {
1565 relocs := ldr.Relocs(s)
1566 for ri := 0; ri < relocs.Count(); ri++ {
1568 if r.Type() >= objabi.ElfRelocOffset {
1571 if r.Siz() == 0 { // informational relocation
1574 if r.Type() == objabi.R_DWARFFILEREF {
1581 if !ldr.AttrReachable(s) {
1588 rt.addentry(ldr, s, &r)
1593 func needPEBaseReloc(ctxt *Link) bool {
1594 // Non-PIE x86 binaries don't need the base relocation table.
1595 // Everyone else does.
1596 if (ctxt.Arch.Family == sys.I386 || ctxt.Arch.Family == sys.AMD64) && ctxt.BuildMode != BuildModePIE {
1602 func addPEBaseReloc(ctxt *Link) {
1603 if !needPEBaseReloc(ctxt) {
1607 var rt peBaseRelocTable
1610 // Get relocation information
1612 for _, s := range ctxt.Textp {
1613 addPEBaseRelocSym(ldr, s, &rt)
1615 for _, s := range ctxt.datap {
1616 addPEBaseRelocSym(ldr, s, &rt)
1619 // Write relocation information
1620 startoff := ctxt.Out.Offset()
1622 size := ctxt.Out.Offset() - startoff
1624 // Add a PE section and pad it at the end
1625 rsect := pefile.addSection(".reloc", int(size), int(size))
1626 rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
1627 rsect.checkOffset(startoff)
1628 rsect.pad(ctxt.Out, uint32(size))
1630 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
1631 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
1634 func (ctxt *Link) dope() {
1640 func setpersrc(ctxt *Link, syms []loader.Sym) {
1641 if len(rsrcsyms) != 0 {
1642 Errorf(nil, "too many .rsrc sections")
1647 func addpersrc(ctxt *Link) {
1648 if len(rsrcsyms) == 0 {
1653 for _, rsrcsym := range rsrcsyms {
1654 size += ctxt.loader.SymSize(rsrcsym)
1656 h := pefile.addSection(".rsrc", int(size), int(size))
1657 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA
1658 h.checkOffset(ctxt.Out.Offset())
1660 for _, rsrcsym := range rsrcsyms {
1661 // A split resource happens when the actual resource data and its relocations are
1662 // split across multiple sections, denoted by a $01 or $02 at the end of the .rsrc
1664 splitResources := strings.Contains(ctxt.loader.SymName(rsrcsym), ".rsrc$")
1665 relocs := ctxt.loader.Relocs(rsrcsym)
1666 data := ctxt.loader.Data(rsrcsym)
1667 for ri := 0; ri < relocs.Count(); ri++ {
1670 val := uint32(int64(h.virtualAddress) + r.Add())
1672 // If we're a split resource section, and that section has relocation
1673 // symbols, then the data that it points to doesn't actually begin at
1674 // the virtual address listed in this current section, but rather
1675 // begins at the section immediately after this one. So, in order to
1676 // calculate the proper virtual address of the data it's pointing to,
1677 // we have to add the length of this section to the virtual address.
1678 // This works because .rsrc sections are divided into two (but not more)
1679 // of these sections.
1680 val += uint32(len(data))
1682 binary.LittleEndian.PutUint32(p, val)
1684 ctxt.Out.Write(data)
1686 h.pad(ctxt.Out, uint32(size))
1688 // update data directory
1689 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
1690 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
1693 func asmbPe(ctxt *Link) {
1694 t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length))
1695 t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
1696 if ctxt.LinkMode == LinkExternal {
1697 // some data symbols (e.g. masks) end up in the .text section, and they normally
1698 // expect larger alignment requirement than the default text section alignment.
1699 t.characteristics |= IMAGE_SCN_ALIGN_32BYTES
1701 t.checkSegment(&Segtext)
1704 ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length))
1705 ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
1706 if ctxt.LinkMode == LinkExternal {
1707 // some data symbols (e.g. masks) end up in the .rdata section, and they normally
1708 // expect larger alignment requirement than the default text section alignment.
1709 ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
1711 ro.checkSegment(&Segrodata)
1712 pefile.rdataSect = ro
1715 if ctxt.LinkMode != LinkExternal {
1716 d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
1717 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
1718 d.checkSegment(&Segdata)
1721 d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
1722 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
1723 d.checkSegment(&Segdata)
1726 b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
1727 b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
1728 b.pointerToRawData = 0
1735 if ctxt.LinkMode == LinkExternal {
1736 pefile.ctorsSect = pefile.addInitArray(ctxt)
1739 ctxt.Out.SeekSet(int64(pefile.nextFileOffset))
1740 if ctxt.LinkMode != LinkExternal {
1743 addPEBaseReloc(ctxt)
1745 pefile.writeSymbolTableAndStringTable(ctxt)
1747 if ctxt.LinkMode == LinkExternal {
1748 pefile.emitRelocations(ctxt)