Source file src/cmd/link/internal/ld/pe.go

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

View as plain text