github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/link/ld/pe.go (about)

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