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  	"bytes"
    12  	"cmd/internal/objabi"
    13  	"cmd/internal/sys"
    14  	"cmd/link/internal/loader"
    15  	"cmd/link/internal/sym"
    16  	"debug/pe"
    17  	"encoding/binary"
    18  	"fmt"
    19  	"internal/buildcfg"
    20  	"math"
    21  	"os"
    22  	"path/filepath"
    23  	"slices"
    24  	"sort"
    25  	"strconv"
    26  	"strings"
    27  )
    28  
    29  type IMAGE_IMPORT_DESCRIPTOR struct {
    30  	OriginalFirstThunk uint32
    31  	TimeDateStamp      uint32
    32  	ForwarderChain     uint32
    33  	Name               uint32
    34  	FirstThunk         uint32
    35  }
    36  
    37  type IMAGE_EXPORT_DIRECTORY struct {
    38  	Characteristics       uint32
    39  	TimeDateStamp         uint32
    40  	MajorVersion          uint16
    41  	MinorVersion          uint16
    42  	Name                  uint32
    43  	Base                  uint32
    44  	NumberOfFunctions     uint32
    45  	NumberOfNames         uint32
    46  	AddressOfFunctions    uint32
    47  	AddressOfNames        uint32
    48  	AddressOfNameOrdinals uint32
    49  }
    50  
    51  var (
    52  	// PEBASE is the base address for the executable.
    53  	// It is small for 32-bit and large for 64-bit.
    54  	PEBASE int64
    55  
    56  	// SectionAlignment must be greater than or equal to FileAlignment.
    57  	// The default is the page size for the architecture.
    58  	PESECTALIGN int64 = 0x1000
    59  
    60  	// FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
    61  	// The default is 512. If the SectionAlignment is less than
    62  	// the architecture's page size, then FileAlignment must match SectionAlignment.
    63  	PEFILEALIGN int64 = 2 << 8
    64  )
    65  
    66  const (
    67  	IMAGE_SCN_CNT_CODE               = 0x00000020
    68  	IMAGE_SCN_CNT_INITIALIZED_DATA   = 0x00000040
    69  	IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
    70  	IMAGE_SCN_LNK_OTHER              = 0x00000100
    71  	IMAGE_SCN_LNK_INFO               = 0x00000200
    72  	IMAGE_SCN_LNK_REMOVE             = 0x00000800
    73  	IMAGE_SCN_LNK_COMDAT             = 0x00001000
    74  	IMAGE_SCN_GPREL                  = 0x00008000
    75  	IMAGE_SCN_MEM_PURGEABLE          = 0x00020000
    76  	IMAGE_SCN_MEM_16BIT              = 0x00020000
    77  	IMAGE_SCN_MEM_LOCKED             = 0x00040000
    78  	IMAGE_SCN_MEM_PRELOAD            = 0x00080000
    79  	IMAGE_SCN_ALIGN_1BYTES           = 0x00100000
    80  	IMAGE_SCN_ALIGN_2BYTES           = 0x00200000
    81  	IMAGE_SCN_ALIGN_4BYTES           = 0x00300000
    82  	IMAGE_SCN_ALIGN_8BYTES           = 0x00400000
    83  	IMAGE_SCN_ALIGN_16BYTES          = 0x00500000
    84  	IMAGE_SCN_ALIGN_32BYTES          = 0x00600000
    85  	IMAGE_SCN_ALIGN_64BYTES          = 0x00700000
    86  	IMAGE_SCN_ALIGN_128BYTES         = 0x00800000
    87  	IMAGE_SCN_ALIGN_256BYTES         = 0x00900000
    88  	IMAGE_SCN_ALIGN_512BYTES         = 0x00A00000
    89  	IMAGE_SCN_ALIGN_1024BYTES        = 0x00B00000
    90  	IMAGE_SCN_ALIGN_2048BYTES        = 0x00C00000
    91  	IMAGE_SCN_ALIGN_4096BYTES        = 0x00D00000
    92  	IMAGE_SCN_ALIGN_8192BYTES        = 0x00E00000
    93  	IMAGE_SCN_LNK_NRELOC_OVFL        = 0x01000000
    94  	IMAGE_SCN_MEM_DISCARDABLE        = 0x02000000
    95  	IMAGE_SCN_MEM_NOT_CACHED         = 0x04000000
    96  	IMAGE_SCN_MEM_NOT_PAGED          = 0x08000000
    97  	IMAGE_SCN_MEM_SHARED             = 0x10000000
    98  	IMAGE_SCN_MEM_EXECUTE            = 0x20000000
    99  	IMAGE_SCN_MEM_READ               = 0x40000000
   100  	IMAGE_SCN_MEM_WRITE              = 0x80000000
   101  )
   102  
   103  // See https://docs.microsoft.com/en-us/windows/win32/debug/pe-format.
   104  // TODO(crawshaw): add these constants to debug/pe.
   105  const (
   106  	IMAGE_SYM_TYPE_NULL      = 0
   107  	IMAGE_SYM_TYPE_STRUCT    = 8
   108  	IMAGE_SYM_DTYPE_FUNCTION = 2
   109  	IMAGE_SYM_DTYPE_ARRAY    = 3
   110  	IMAGE_SYM_CLASS_EXTERNAL = 2
   111  	IMAGE_SYM_CLASS_STATIC   = 3
   112  
   113  	IMAGE_REL_I386_DIR32   = 0x0006
   114  	IMAGE_REL_I386_DIR32NB = 0x0007
   115  	IMAGE_REL_I386_SECREL  = 0x000B
   116  	IMAGE_REL_I386_REL32   = 0x0014
   117  
   118  	IMAGE_REL_AMD64_ADDR64   = 0x0001
   119  	IMAGE_REL_AMD64_ADDR32   = 0x0002
   120  	IMAGE_REL_AMD64_ADDR32NB = 0x0003
   121  	IMAGE_REL_AMD64_REL32    = 0x0004
   122  	IMAGE_REL_AMD64_SECREL   = 0x000B
   123  
   124  	IMAGE_REL_ARM_ABSOLUTE = 0x0000
   125  	IMAGE_REL_ARM_ADDR32   = 0x0001
   126  	IMAGE_REL_ARM_ADDR32NB = 0x0002
   127  	IMAGE_REL_ARM_BRANCH24 = 0x0003
   128  	IMAGE_REL_ARM_BRANCH11 = 0x0004
   129  	IMAGE_REL_ARM_SECREL   = 0x000F
   130  
   131  	IMAGE_REL_ARM64_ABSOLUTE       = 0x0000
   132  	IMAGE_REL_ARM64_ADDR32         = 0x0001
   133  	IMAGE_REL_ARM64_ADDR32NB       = 0x0002
   134  	IMAGE_REL_ARM64_BRANCH26       = 0x0003
   135  	IMAGE_REL_ARM64_PAGEBASE_REL21 = 0x0004
   136  	IMAGE_REL_ARM64_REL21          = 0x0005
   137  	IMAGE_REL_ARM64_PAGEOFFSET_12A = 0x0006
   138  	IMAGE_REL_ARM64_PAGEOFFSET_12L = 0x0007
   139  	IMAGE_REL_ARM64_SECREL         = 0x0008
   140  	IMAGE_REL_ARM64_SECREL_LOW12A  = 0x0009
   141  	IMAGE_REL_ARM64_SECREL_HIGH12A = 0x000A
   142  	IMAGE_REL_ARM64_SECREL_LOW12L  = 0x000B
   143  	IMAGE_REL_ARM64_TOKEN          = 0x000C
   144  	IMAGE_REL_ARM64_SECTION        = 0x000D
   145  	IMAGE_REL_ARM64_ADDR64         = 0x000E
   146  	IMAGE_REL_ARM64_BRANCH19       = 0x000F
   147  	IMAGE_REL_ARM64_BRANCH14       = 0x0010
   148  	IMAGE_REL_ARM64_REL32          = 0x0011
   149  
   150  	IMAGE_REL_BASED_HIGHLOW = 3
   151  	IMAGE_REL_BASED_DIR64   = 10
   152  )
   153  
   154  const (
   155  	PeMinimumTargetMajorVersion = 6
   156  	PeMinimumTargetMinorVersion = 1
   157  )
   158  
   159  // DOS stub that prints out
   160  // "This program cannot be run in DOS mode."
   161  // See IMAGE_DOS_HEADER in the Windows SDK for the format of the header used here.
   162  var dosstub = []uint8{
   163  	0x4d,
   164  	0x5a,
   165  	0x90,
   166  	0x00,
   167  	0x03,
   168  	0x00,
   169  	0x00,
   170  	0x00,
   171  	0x04,
   172  	0x00,
   173  	0x00,
   174  	0x00,
   175  	0xff,
   176  	0xff,
   177  	0x00,
   178  	0x00,
   179  	0x8b,
   180  	0x00,
   181  	0x00,
   182  	0x00,
   183  	0x00,
   184  	0x00,
   185  	0x00,
   186  	0x00,
   187  	0x40,
   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  	0x00,
   221  	0x00,
   222  	0x00,
   223  	0x80,
   224  	0x00,
   225  	0x00,
   226  	0x00,
   227  	0x0e,
   228  	0x1f,
   229  	0xba,
   230  	0x0e,
   231  	0x00,
   232  	0xb4,
   233  	0x09,
   234  	0xcd,
   235  	0x21,
   236  	0xb8,
   237  	0x01,
   238  	0x4c,
   239  	0xcd,
   240  	0x21,
   241  	0x54,
   242  	0x68,
   243  	0x69,
   244  	0x73,
   245  	0x20,
   246  	0x70,
   247  	0x72,
   248  	0x6f,
   249  	0x67,
   250  	0x72,
   251  	0x61,
   252  	0x6d,
   253  	0x20,
   254  	0x63,
   255  	0x61,
   256  	0x6e,
   257  	0x6e,
   258  	0x6f,
   259  	0x74,
   260  	0x20,
   261  	0x62,
   262  	0x65,
   263  	0x20,
   264  	0x72,
   265  	0x75,
   266  	0x6e,
   267  	0x20,
   268  	0x69,
   269  	0x6e,
   270  	0x20,
   271  	0x44,
   272  	0x4f,
   273  	0x53,
   274  	0x20,
   275  	0x6d,
   276  	0x6f,
   277  	0x64,
   278  	0x65,
   279  	0x2e,
   280  	0x0d,
   281  	0x0d,
   282  	0x0a,
   283  	0x24,
   284  	0x00,
   285  	0x00,
   286  	0x00,
   287  	0x00,
   288  	0x00,
   289  	0x00,
   290  	0x00,
   291  }
   292  
   293  type Imp struct {
   294  	s       loader.Sym
   295  	off     uint64
   296  	next    *Imp
   297  	argsize int
   298  }
   299  
   300  type Dll struct {
   301  	name     string
   302  	nameoff  uint64
   303  	thunkoff uint64
   304  	ms       *Imp
   305  	next     *Dll
   306  }
   307  
   308  var (
   309  	rsrcsyms    []loader.Sym
   310  	PESECTHEADR int32
   311  	PEFILEHEADR int32
   312  	pe64        bool
   313  	dr          *Dll
   314  
   315  	dexport []loader.Sym
   316  )
   317  
   318  // peStringTable is a COFF string table.
   319  type peStringTable struct {
   320  	strings    []string
   321  	stringsLen int
   322  }
   323  
   324  // size returns size of string table t.
   325  func (t *peStringTable) size() int {
   326  	// string table starts with 4-byte length at the beginning
   327  	return t.stringsLen + 4
   328  }
   329  
   330  // add adds string str to string table t.
   331  func (t *peStringTable) add(str string) int {
   332  	off := t.size()
   333  	t.strings = append(t.strings, str)
   334  	t.stringsLen += len(str) + 1 // each string will have 0 appended to it
   335  	return off
   336  }
   337  
   338  // write writes string table t into the output file.
   339  func (t *peStringTable) write(out *OutBuf) {
   340  	out.Write32(uint32(t.size()))
   341  	for _, s := range t.strings {
   342  		out.WriteString(s)
   343  		out.Write8(0)
   344  	}
   345  }
   346  
   347  // peSection represents section from COFF section table.
   348  type peSection struct {
   349  	name                 string
   350  	shortName            string
   351  	index                int // one-based index into the Section Table
   352  	virtualSize          uint32
   353  	virtualAddress       uint32
   354  	sizeOfRawData        uint32
   355  	pointerToRawData     uint32
   356  	pointerToRelocations uint32
   357  	numberOfRelocations  uint16
   358  	characteristics      uint32
   359  }
   360  
   361  // checkOffset verifies COFF section sect offset in the file.
   362  func (sect *peSection) checkOffset(off int64) {
   363  	if off != int64(sect.pointerToRawData) {
   364  		Errorf("%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(off))
   365  		errorexit()
   366  	}
   367  }
   368  
   369  // checkSegment verifies COFF section sect matches address
   370  // and file offset provided in segment seg.
   371  func (sect *peSection) checkSegment(seg *sym.Segment) {
   372  	if seg.Vaddr-uint64(PEBASE) != uint64(sect.virtualAddress) {
   373  		Errorf("%s.VirtualAddress = %#x, want %#x", sect.name, uint64(int64(sect.virtualAddress)), uint64(int64(seg.Vaddr-uint64(PEBASE))))
   374  		errorexit()
   375  	}
   376  	if seg.Fileoff != uint64(sect.pointerToRawData) {
   377  		Errorf("%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(int64(seg.Fileoff)))
   378  		errorexit()
   379  	}
   380  }
   381  
   382  // pad adds zeros to the section sect. It writes as many bytes
   383  // as necessary to make section sect.SizeOfRawData bytes long.
   384  // It assumes that n bytes are already written to the file.
   385  func (sect *peSection) pad(out *OutBuf, n uint32) {
   386  	out.WriteStringN("", int(sect.sizeOfRawData-n))
   387  }
   388  
   389  // write writes COFF section sect into the output file.
   390  func (sect *peSection) write(out *OutBuf, linkmode LinkMode) error {
   391  	h := pe.SectionHeader32{
   392  		VirtualSize:          sect.virtualSize,
   393  		SizeOfRawData:        sect.sizeOfRawData,
   394  		PointerToRawData:     sect.pointerToRawData,
   395  		PointerToRelocations: sect.pointerToRelocations,
   396  		NumberOfRelocations:  sect.numberOfRelocations,
   397  		Characteristics:      sect.characteristics,
   398  	}
   399  	if linkmode != LinkExternal {
   400  		h.VirtualAddress = sect.virtualAddress
   401  	}
   402  	copy(h.Name[:], sect.shortName)
   403  	return binary.Write(out, binary.LittleEndian, h)
   404  }
   405  
   406  // emitRelocations emits the relocation entries for the sect.
   407  // The actual relocations are emitted by relocfn.
   408  // This updates the corresponding PE section table entry
   409  // with the relocation offset and count.
   410  func (sect *peSection) emitRelocations(out *OutBuf, relocfn func() int) {
   411  	sect.pointerToRelocations = uint32(out.Offset())
   412  	// first entry: extended relocs
   413  	out.Write32(0) // placeholder for number of relocation + 1
   414  	out.Write32(0)
   415  	out.Write16(0)
   416  
   417  	n := relocfn() + 1
   418  
   419  	cpos := out.Offset()
   420  	out.SeekSet(int64(sect.pointerToRelocations))
   421  	out.Write32(uint32(n))
   422  	out.SeekSet(cpos)
   423  	if n > 0x10000 {
   424  		n = 0x10000
   425  		sect.characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
   426  	} else {
   427  		sect.pointerToRelocations += 10 // skip the extend reloc entry
   428  	}
   429  	sect.numberOfRelocations = uint16(n - 1)
   430  }
   431  
   432  // peFile is used to build COFF file.
   433  type peFile struct {
   434  	sections       []*peSection
   435  	stringTable    peStringTable
   436  	textSect       *peSection
   437  	rdataSect      *peSection
   438  	dataSect       *peSection
   439  	bssSect        *peSection
   440  	ctorsSect      *peSection
   441  	pdataSect      *peSection
   442  	xdataSect      *peSection
   443  	nextSectOffset uint32
   444  	nextFileOffset uint32
   445  	symtabOffset   int64 // offset to the start of symbol table
   446  	symbolCount    int   // number of symbol table records written
   447  	dataDirectory  [16]pe.DataDirectory
   448  }
   449  
   450  // addSection adds section to the COFF file f.
   451  func (f *peFile) addSection(name string, sectsize int, filesize int) *peSection {
   452  	sect := &peSection{
   453  		name:             name,
   454  		shortName:        name,
   455  		index:            len(f.sections) + 1,
   456  		virtualAddress:   f.nextSectOffset,
   457  		pointerToRawData: f.nextFileOffset,
   458  	}
   459  	f.nextSectOffset = uint32(Rnd(int64(f.nextSectOffset)+int64(sectsize), PESECTALIGN))
   460  	if filesize > 0 {
   461  		sect.virtualSize = uint32(sectsize)
   462  		sect.sizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN))
   463  		f.nextFileOffset += sect.sizeOfRawData
   464  	} else {
   465  		sect.sizeOfRawData = uint32(sectsize)
   466  	}
   467  	f.sections = append(f.sections, sect)
   468  	return sect
   469  }
   470  
   471  // addDWARFSection adds DWARF section to the COFF file f.
   472  // This function is similar to addSection, but DWARF section names are
   473  // longer than 8 characters, so they need to be stored in the string table.
   474  func (f *peFile) addDWARFSection(name string, size int) *peSection {
   475  	if size == 0 {
   476  		Exitf("DWARF section %q is empty", name)
   477  	}
   478  	// DWARF section names are longer than 8 characters.
   479  	// PE format requires such names to be stored in string table,
   480  	// and section names replaced with slash (/) followed by
   481  	// correspondent string table index.
   482  	// see http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx
   483  	// for details
   484  	off := f.stringTable.add(name)
   485  	h := f.addSection(name, size, size)
   486  	h.shortName = fmt.Sprintf("/%d", off)
   487  	h.characteristics = IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA
   488  	return h
   489  }
   490  
   491  // addDWARF adds DWARF information to the COFF file f.
   492  func (f *peFile) addDWARF() {
   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() != 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.ARM64:
   917  		fh.Machine = pe.IMAGE_FILE_MACHINE_ARM64
   918  	}
   919  
   920  	fh.NumberOfSections = uint16(len(f.sections))
   921  
   922  	// Being able to produce identical output for identical input is
   923  	// much more beneficial than having build timestamp in the header.
   924  	fh.TimeDateStamp = 0
   925  
   926  	if ctxt.LinkMode != LinkExternal {
   927  		fh.Characteristics = pe.IMAGE_FILE_EXECUTABLE_IMAGE
   928  		switch ctxt.Arch.Family {
   929  		case sys.AMD64, sys.I386:
   930  			if ctxt.BuildMode != BuildModePIE {
   931  				fh.Characteristics |= pe.IMAGE_FILE_RELOCS_STRIPPED
   932  			}
   933  		}
   934  	}
   935  	if pe64 {
   936  		var oh64 pe.OptionalHeader64
   937  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
   938  		fh.Characteristics |= pe.IMAGE_FILE_LARGE_ADDRESS_AWARE
   939  	} else {
   940  		var oh pe.OptionalHeader32
   941  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
   942  		fh.Characteristics |= pe.IMAGE_FILE_32BIT_MACHINE
   943  	}
   944  
   945  	fh.PointerToSymbolTable = uint32(f.symtabOffset)
   946  	fh.NumberOfSymbols = uint32(f.symbolCount)
   947  
   948  	binary.Write(ctxt.Out, binary.LittleEndian, &fh)
   949  }
   950  
   951  // writeOptionalHeader writes COFF optional header for peFile f.
   952  func (f *peFile) writeOptionalHeader(ctxt *Link) {
   953  	var oh pe.OptionalHeader32
   954  	var oh64 pe.OptionalHeader64
   955  
   956  	if pe64 {
   957  		oh64.Magic = 0x20b // PE32+
   958  	} else {
   959  		oh.Magic = 0x10b // PE32
   960  		oh.BaseOfData = f.dataSect.virtualAddress
   961  	}
   962  
   963  	// Fill out both oh64 and oh. We only use one. Oh well.
   964  	oh64.MajorLinkerVersion = 3
   965  	oh.MajorLinkerVersion = 3
   966  	oh64.MinorLinkerVersion = 0
   967  	oh.MinorLinkerVersion = 0
   968  	oh64.SizeOfCode = f.textSect.sizeOfRawData
   969  	oh.SizeOfCode = f.textSect.sizeOfRawData
   970  	oh64.SizeOfInitializedData = f.dataSect.sizeOfRawData
   971  	oh.SizeOfInitializedData = f.dataSect.sizeOfRawData
   972  	oh64.SizeOfUninitializedData = 0
   973  	oh.SizeOfUninitializedData = 0
   974  	if ctxt.LinkMode != LinkExternal {
   975  		oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
   976  		oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
   977  	}
   978  	oh64.BaseOfCode = f.textSect.virtualAddress
   979  	oh.BaseOfCode = f.textSect.virtualAddress
   980  	oh64.ImageBase = uint64(PEBASE)
   981  	oh.ImageBase = uint32(PEBASE)
   982  	oh64.SectionAlignment = uint32(PESECTALIGN)
   983  	oh.SectionAlignment = uint32(PESECTALIGN)
   984  	oh64.FileAlignment = uint32(PEFILEALIGN)
   985  	oh.FileAlignment = uint32(PEFILEALIGN)
   986  	oh64.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
   987  	oh.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
   988  	oh64.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
   989  	oh.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
   990  	oh64.MajorImageVersion = 1
   991  	oh.MajorImageVersion = 1
   992  	oh64.MinorImageVersion = 0
   993  	oh.MinorImageVersion = 0
   994  	oh64.MajorSubsystemVersion = PeMinimumTargetMajorVersion
   995  	oh.MajorSubsystemVersion = PeMinimumTargetMajorVersion
   996  	oh64.MinorSubsystemVersion = PeMinimumTargetMinorVersion
   997  	oh.MinorSubsystemVersion = PeMinimumTargetMinorVersion
   998  	oh64.SizeOfImage = f.nextSectOffset
   999  	oh.SizeOfImage = f.nextSectOffset
  1000  	oh64.SizeOfHeaders = uint32(PEFILEHEADR)
  1001  	oh.SizeOfHeaders = uint32(PEFILEHEADR)
  1002  	if windowsgui {
  1003  		oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
  1004  		oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
  1005  	} else {
  1006  		oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
  1007  		oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
  1008  	}
  1009  
  1010  	// Mark as having awareness of terminal services, to avoid ancient compatibility hacks.
  1011  	oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
  1012  	oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
  1013  
  1014  	// Enable DEP
  1015  	oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
  1016  	oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
  1017  
  1018  	// The DLL can be relocated at load time.
  1019  	if needPEBaseReloc(ctxt) {
  1020  		oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
  1021  		oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
  1022  	}
  1023  
  1024  	// Image can handle a high entropy 64-bit virtual address space.
  1025  	if ctxt.BuildMode == BuildModePIE {
  1026  		oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
  1027  	}
  1028  
  1029  	// Disable stack growth as we don't want Windows to
  1030  	// fiddle with the thread stack limits, which we set
  1031  	// ourselves to circumvent the stack checks in the
  1032  	// Windows exception dispatcher.
  1033  	// Commit size must be strictly less than reserve
  1034  	// size otherwise reserve will be rounded up to a
  1035  	// larger size, as verified with VMMap.
  1036  
  1037  	// On 64-bit, we always reserve 2MB stacks. "Pure" Go code is
  1038  	// okay with much smaller stacks, but the syscall package
  1039  	// makes it easy to call into arbitrary C code without cgo,
  1040  	// and system calls even in "pure" Go code are actually C
  1041  	// calls that may need more stack than we think.
  1042  	//
  1043  	// The default stack reserve size directly affects only the main
  1044  	// thread.
  1045  	//
  1046  	// For other threads, the runtime explicitly asks the kernel
  1047  	// to use the default stack size so that all stacks are
  1048  	// consistent.
  1049  	//
  1050  	// At thread start, in minit, the runtime queries the OS for
  1051  	// the actual stack bounds so that the stack size doesn't need
  1052  	// to be hard-coded into the runtime.
  1053  	oh64.SizeOfStackReserve = 0x00200000
  1054  	if !iscgo {
  1055  		oh64.SizeOfStackCommit = 0x00001000
  1056  	} else {
  1057  		// TODO(brainman): Maybe remove optional header writing altogether for cgo.
  1058  		// For cgo it is the external linker that is building final executable.
  1059  		// And it probably does not use any information stored in optional header.
  1060  		oh64.SizeOfStackCommit = 0x00200000 - 0x2000 // account for 2 guard pages
  1061  	}
  1062  
  1063  	oh.SizeOfStackReserve = 0x00100000
  1064  	if !iscgo {
  1065  		oh.SizeOfStackCommit = 0x00001000
  1066  	} else {
  1067  		oh.SizeOfStackCommit = 0x00100000 - 0x2000 // account for 2 guard pages
  1068  	}
  1069  
  1070  	oh64.SizeOfHeapReserve = 0x00100000
  1071  	oh.SizeOfHeapReserve = 0x00100000
  1072  	oh64.SizeOfHeapCommit = 0x00001000
  1073  	oh.SizeOfHeapCommit = 0x00001000
  1074  	oh64.NumberOfRvaAndSizes = 16
  1075  	oh.NumberOfRvaAndSizes = 16
  1076  
  1077  	if pe64 {
  1078  		oh64.DataDirectory = f.dataDirectory
  1079  	} else {
  1080  		oh.DataDirectory = f.dataDirectory
  1081  	}
  1082  
  1083  	if pe64 {
  1084  		binary.Write(ctxt.Out, binary.LittleEndian, &oh64)
  1085  	} else {
  1086  		binary.Write(ctxt.Out, binary.LittleEndian, &oh)
  1087  	}
  1088  }
  1089  
  1090  var pefile peFile
  1091  
  1092  func Peinit(ctxt *Link) {
  1093  	var l int
  1094  
  1095  	if ctxt.Arch.PtrSize == 8 {
  1096  		// 64-bit architectures
  1097  		pe64 = true
  1098  		var oh64 pe.OptionalHeader64
  1099  		l = binary.Size(&oh64)
  1100  	} else {
  1101  		// 32-bit architectures
  1102  		var oh pe.OptionalHeader32
  1103  		l = binary.Size(&oh)
  1104  	}
  1105  
  1106  	if ctxt.LinkMode == LinkExternal {
  1107  		// .rdata section will contain "masks" and "shifts" symbols, and they
  1108  		// need to be aligned to 16-bytes. So make all sections aligned
  1109  		// to 32-byte and mark them all IMAGE_SCN_ALIGN_32BYTES so external
  1110  		// linker will honour that requirement.
  1111  		PESECTALIGN = 32
  1112  		PEFILEALIGN = 0
  1113  		// We are creating an object file. The absolute address is irrelevant.
  1114  		PEBASE = 0
  1115  	} else {
  1116  		// Use the same base image address as MSVC and LLVM.
  1117  		if pe64 {
  1118  			PEBASE = 0x140000000
  1119  		} else {
  1120  			PEBASE = 0x400000
  1121  		}
  1122  	}
  1123  
  1124  	var sh [16]pe.SectionHeader32
  1125  	var fh pe.FileHeader
  1126  	PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
  1127  	if ctxt.LinkMode != LinkExternal {
  1128  		PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
  1129  	} else {
  1130  		PESECTHEADR = 0
  1131  	}
  1132  	pefile.nextSectOffset = uint32(PESECTHEADR)
  1133  	pefile.nextFileOffset = uint32(PEFILEHEADR)
  1134  
  1135  	if ctxt.LinkMode == LinkInternal {
  1136  		// some mingw libs depend on this symbol, for example, FindPESectionByName
  1137  		for _, name := range [2]string{"__image_base__", "_image_base__"} {
  1138  			sb := ctxt.loader.CreateSymForUpdate(name, 0)
  1139  			sb.SetType(sym.SDATA)
  1140  			sb.SetValue(PEBASE)
  1141  			ctxt.loader.SetAttrSpecial(sb.Sym(), true)
  1142  			ctxt.loader.SetAttrLocal(sb.Sym(), true)
  1143  		}
  1144  	}
  1145  
  1146  	HEADR = PEFILEHEADR
  1147  	if *FlagRound == -1 {
  1148  		*FlagRound = PESECTALIGN
  1149  	}
  1150  	if *FlagTextAddr == -1 {
  1151  		*FlagTextAddr = Rnd(PEBASE, *FlagRound) + int64(PESECTHEADR)
  1152  	}
  1153  }
  1154  
  1155  func pewrite(ctxt *Link) {
  1156  	ctxt.Out.SeekSet(0)
  1157  	if ctxt.LinkMode != LinkExternal {
  1158  		ctxt.Out.Write(dosstub)
  1159  		ctxt.Out.WriteStringN("PE", 4)
  1160  	}
  1161  
  1162  	pefile.writeFileHeader(ctxt)
  1163  
  1164  	pefile.writeOptionalHeader(ctxt)
  1165  
  1166  	for _, sect := range pefile.sections {
  1167  		sect.write(ctxt.Out, ctxt.LinkMode)
  1168  	}
  1169  }
  1170  
  1171  func strput(out *OutBuf, s string) {
  1172  	out.WriteString(s)
  1173  	out.Write8(0)
  1174  	// string must be padded to even size
  1175  	if (len(s)+1)%2 != 0 {
  1176  		out.Write8(0)
  1177  	}
  1178  }
  1179  
  1180  func initdynimport(ctxt *Link) *Dll {
  1181  	ldr := ctxt.loader
  1182  	var d *Dll
  1183  
  1184  	dr = nil
  1185  	var m *Imp
  1186  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
  1187  		if !ldr.AttrReachable(s) || ldr.SymType(s) != sym.SDYNIMPORT {
  1188  			continue
  1189  		}
  1190  		dynlib := ldr.SymDynimplib(s)
  1191  		for d = dr; d != nil; d = d.next {
  1192  			if d.name == dynlib {
  1193  				m = new(Imp)
  1194  				break
  1195  			}
  1196  		}
  1197  
  1198  		if d == nil {
  1199  			d = new(Dll)
  1200  			d.name = dynlib
  1201  			d.next = dr
  1202  			dr = d
  1203  			m = new(Imp)
  1204  		}
  1205  
  1206  		// Because external link requires properly stdcall decorated name,
  1207  		// all external symbols in runtime use %n to denote that the number
  1208  		// of uinptrs this function consumes. Store the argsize and discard
  1209  		// the %n suffix if any.
  1210  		m.argsize = -1
  1211  		extName := ldr.SymExtname(s)
  1212  		if i := strings.IndexByte(extName, '%'); i >= 0 {
  1213  			var err error
  1214  			m.argsize, err = strconv.Atoi(extName[i+1:])
  1215  			if err != nil {
  1216  				ctxt.Errorf(s, "failed to parse stdcall decoration: %v", err)
  1217  			}
  1218  			m.argsize *= ctxt.Arch.PtrSize
  1219  			ldr.SetSymExtname(s, extName[:i])
  1220  		}
  1221  
  1222  		m.s = s
  1223  		m.next = d.ms
  1224  		d.ms = m
  1225  	}
  1226  
  1227  	if ctxt.IsExternal() {
  1228  		// Add real symbol name
  1229  		for d := dr; d != nil; d = d.next {
  1230  			for m = d.ms; m != nil; m = m.next {
  1231  				sb := ldr.MakeSymbolUpdater(m.s)
  1232  				sb.SetType(sym.SDATA)
  1233  				sb.Grow(int64(ctxt.Arch.PtrSize))
  1234  				dynName := sb.Extname()
  1235  				// only windows/386 requires stdcall decoration
  1236  				if ctxt.Is386() && m.argsize >= 0 {
  1237  					dynName += fmt.Sprintf("@%d", m.argsize)
  1238  				}
  1239  				dynSym := ldr.CreateSymForUpdate(dynName, 0)
  1240  				dynSym.SetType(sym.SHOSTOBJ)
  1241  				r, _ := sb.AddRel(objabi.R_ADDR)
  1242  				r.SetSym(dynSym.Sym())
  1243  				r.SetSiz(uint8(ctxt.Arch.PtrSize))
  1244  			}
  1245  		}
  1246  	} else {
  1247  		dynamic := ldr.CreateSymForUpdate(".windynamic", 0)
  1248  		dynamic.SetType(sym.SWINDOWS)
  1249  		for d := dr; d != nil; d = d.next {
  1250  			for m = d.ms; m != nil; m = m.next {
  1251  				sb := ldr.MakeSymbolUpdater(m.s)
  1252  				sb.SetType(sym.SWINDOWS)
  1253  				sb.SetValue(dynamic.Size())
  1254  				dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
  1255  				dynamic.AddInteriorSym(m.s)
  1256  			}
  1257  
  1258  			dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
  1259  		}
  1260  	}
  1261  
  1262  	return dr
  1263  }
  1264  
  1265  // peimporteddlls returns the gcc command line argument to link all imported
  1266  // DLLs.
  1267  func peimporteddlls() []string {
  1268  	var dlls []string
  1269  
  1270  	for d := dr; d != nil; d = d.next {
  1271  		dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
  1272  	}
  1273  
  1274  	return dlls
  1275  }
  1276  
  1277  func addimports(ctxt *Link, datsect *peSection) {
  1278  	ldr := ctxt.loader
  1279  	startoff := ctxt.Out.Offset()
  1280  	dynamic := ldr.LookupOrCreateSym(".windynamic", 0)
  1281  
  1282  	// skip import descriptor table (will write it later)
  1283  	n := uint64(0)
  1284  
  1285  	for d := dr; d != nil; d = d.next {
  1286  		n++
  1287  	}
  1288  	ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
  1289  
  1290  	// write dll names
  1291  	for d := dr; d != nil; d = d.next {
  1292  		d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff)
  1293  		strput(ctxt.Out, d.name)
  1294  	}
  1295  
  1296  	// write function names
  1297  	for d := dr; d != nil; d = d.next {
  1298  		for m := d.ms; m != nil; m = m.next {
  1299  			m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
  1300  			ctxt.Out.Write16(0) // hint
  1301  			strput(ctxt.Out, ldr.SymExtname(m.s))
  1302  		}
  1303  	}
  1304  
  1305  	// write OriginalFirstThunks
  1306  	oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff)
  1307  
  1308  	n = uint64(ctxt.Out.Offset())
  1309  	for d := dr; d != nil; d = d.next {
  1310  		d.thunkoff = uint64(ctxt.Out.Offset()) - n
  1311  		for m := d.ms; m != nil; m = m.next {
  1312  			if pe64 {
  1313  				ctxt.Out.Write64(m.off)
  1314  			} else {
  1315  				ctxt.Out.Write32(uint32(m.off))
  1316  			}
  1317  		}
  1318  
  1319  		if pe64 {
  1320  			ctxt.Out.Write64(0)
  1321  		} else {
  1322  			ctxt.Out.Write32(0)
  1323  		}
  1324  	}
  1325  
  1326  	// add pe section and pad it at the end
  1327  	n = uint64(ctxt.Out.Offset()) - uint64(startoff)
  1328  
  1329  	isect := pefile.addSection(".idata", int(n), int(n))
  1330  	isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1331  	isect.checkOffset(startoff)
  1332  	isect.pad(ctxt.Out, uint32(n))
  1333  	endoff := ctxt.Out.Offset()
  1334  
  1335  	// write FirstThunks (allocated in .data section)
  1336  	ftbase := uint64(ldr.SymValue(dynamic)) - uint64(datsect.virtualAddress) - uint64(PEBASE)
  1337  
  1338  	ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase))
  1339  	for d := dr; d != nil; d = d.next {
  1340  		for m := d.ms; m != nil; m = m.next {
  1341  			if pe64 {
  1342  				ctxt.Out.Write64(m.off)
  1343  			} else {
  1344  				ctxt.Out.Write32(uint32(m.off))
  1345  			}
  1346  		}
  1347  
  1348  		if pe64 {
  1349  			ctxt.Out.Write64(0)
  1350  		} else {
  1351  			ctxt.Out.Write32(0)
  1352  		}
  1353  	}
  1354  
  1355  	// finally write import descriptor table
  1356  	out := ctxt.Out
  1357  	out.SeekSet(startoff)
  1358  
  1359  	for d := dr; d != nil; d = d.next {
  1360  		out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff))
  1361  		out.Write32(0)
  1362  		out.Write32(0)
  1363  		out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff))
  1364  		out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff))
  1365  	}
  1366  
  1367  	out.Write32(0) //end
  1368  	out.Write32(0)
  1369  	out.Write32(0)
  1370  	out.Write32(0)
  1371  	out.Write32(0)
  1372  
  1373  	// update data directory
  1374  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
  1375  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
  1376  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(ldr.SymValue(dynamic) - PEBASE)
  1377  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(ldr.SymSize(dynamic))
  1378  
  1379  	out.SeekSet(endoff)
  1380  }
  1381  
  1382  func initdynexport(ctxt *Link) {
  1383  	ldr := ctxt.loader
  1384  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
  1385  		if !ldr.AttrReachable(s) || !ldr.AttrCgoExportDynamic(s) {
  1386  			continue
  1387  		}
  1388  		if len(dexport) >= math.MaxUint16 {
  1389  			ctxt.Errorf(s, "pe dynexport table is full")
  1390  			errorexit()
  1391  		}
  1392  
  1393  		dexport = append(dexport, s)
  1394  	}
  1395  
  1396  	sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) })
  1397  }
  1398  
  1399  func addexports(ctxt *Link) {
  1400  	ldr := ctxt.loader
  1401  	var e IMAGE_EXPORT_DIRECTORY
  1402  
  1403  	nexport := len(dexport)
  1404  	size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
  1405  	for _, s := range dexport {
  1406  		size += len(ldr.SymExtname(s)) + 1
  1407  	}
  1408  
  1409  	if nexport == 0 {
  1410  		return
  1411  	}
  1412  
  1413  	sect := pefile.addSection(".edata", size, size)
  1414  	sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
  1415  	sect.checkOffset(ctxt.Out.Offset())
  1416  	va := int(sect.virtualAddress)
  1417  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
  1418  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
  1419  
  1420  	vaName := va + binary.Size(&e) + nexport*4
  1421  	vaAddr := va + binary.Size(&e)
  1422  	vaNa := va + binary.Size(&e) + nexport*8
  1423  
  1424  	e.Characteristics = 0
  1425  	e.MajorVersion = 0
  1426  	e.MinorVersion = 0
  1427  	e.NumberOfFunctions = uint32(nexport)
  1428  	e.NumberOfNames = uint32(nexport)
  1429  	e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
  1430  	e.Base = 1
  1431  	e.AddressOfFunctions = uint32(vaAddr)
  1432  	e.AddressOfNames = uint32(vaName)
  1433  	e.AddressOfNameOrdinals = uint32(vaNa)
  1434  
  1435  	out := ctxt.Out
  1436  
  1437  	// put IMAGE_EXPORT_DIRECTORY
  1438  	binary.Write(out, binary.LittleEndian, &e)
  1439  
  1440  	// put EXPORT Address Table
  1441  	for _, s := range dexport {
  1442  		out.Write32(uint32(ldr.SymValue(s) - PEBASE))
  1443  	}
  1444  
  1445  	// put EXPORT Name Pointer Table
  1446  	v := int(e.Name + uint32(len(*flagOutfile)) + 1)
  1447  
  1448  	for _, s := range dexport {
  1449  		out.Write32(uint32(v))
  1450  		v += len(ldr.SymExtname(s)) + 1
  1451  	}
  1452  
  1453  	// put EXPORT Ordinal Table
  1454  	for i := 0; i < nexport; i++ {
  1455  		out.Write16(uint16(i))
  1456  	}
  1457  
  1458  	// put Names
  1459  	out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
  1460  
  1461  	for _, s := range dexport {
  1462  		name := ldr.SymExtname(s)
  1463  		out.WriteStringN(name, len(name)+1)
  1464  	}
  1465  	sect.pad(out, uint32(size))
  1466  }
  1467  
  1468  // peBaseRelocEntry represents a single relocation entry.
  1469  type peBaseRelocEntry struct {
  1470  	typeOff uint16
  1471  }
  1472  
  1473  // peBaseRelocBlock represents a Base Relocation Block. A block
  1474  // is a collection of relocation entries in a page, where each
  1475  // entry describes a single relocation.
  1476  // The block page RVA (Relative Virtual Address) is the index
  1477  // into peBaseRelocTable.blocks.
  1478  type peBaseRelocBlock struct {
  1479  	entries []peBaseRelocEntry
  1480  }
  1481  
  1482  // pePages is a type used to store the list of pages for which there
  1483  // are base relocation blocks. This is defined as a type so that
  1484  // it can be sorted.
  1485  type pePages []uint32
  1486  
  1487  // A PE base relocation table is a list of blocks, where each block
  1488  // contains relocation information for a single page. The blocks
  1489  // must be emitted in order of page virtual address.
  1490  // See https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-reloc-section-image-only
  1491  type peBaseRelocTable struct {
  1492  	blocks map[uint32]peBaseRelocBlock
  1493  
  1494  	// pePages is a list of keys into blocks map.
  1495  	// It is stored separately for ease of sorting.
  1496  	pages pePages
  1497  }
  1498  
  1499  func (rt *peBaseRelocTable) init(ctxt *Link) {
  1500  	rt.blocks = make(map[uint32]peBaseRelocBlock)
  1501  }
  1502  
  1503  func (rt *peBaseRelocTable) addentry(ldr *loader.Loader, s loader.Sym, r *loader.Reloc) {
  1504  	// pageSize is the size in bytes of a page
  1505  	// described by a base relocation block.
  1506  	const pageSize = 0x1000
  1507  	const pageMask = pageSize - 1
  1508  
  1509  	addr := ldr.SymValue(s) + int64(r.Off()) - PEBASE
  1510  	page := uint32(addr &^ pageMask)
  1511  	off := uint32(addr & pageMask)
  1512  
  1513  	b, ok := rt.blocks[page]
  1514  	if !ok {
  1515  		rt.pages = append(rt.pages, page)
  1516  	}
  1517  
  1518  	e := peBaseRelocEntry{
  1519  		typeOff: uint16(off & 0xFFF),
  1520  	}
  1521  
  1522  	// Set entry type
  1523  	switch r.Siz() {
  1524  	default:
  1525  		Exitf("unsupported relocation size %d\n", r.Siz)
  1526  	case 4:
  1527  		e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12)
  1528  	case 8:
  1529  		e.typeOff |= uint16(IMAGE_REL_BASED_DIR64 << 12)
  1530  	}
  1531  
  1532  	b.entries = append(b.entries, e)
  1533  	rt.blocks[page] = b
  1534  }
  1535  
  1536  func (rt *peBaseRelocTable) write(ctxt *Link) {
  1537  	out := ctxt.Out
  1538  
  1539  	// sort the pages array
  1540  	slices.Sort(rt.pages)
  1541  
  1542  	// .reloc section must be 32-bit aligned
  1543  	if out.Offset()&3 != 0 {
  1544  		Errorf("internal error, start of .reloc not 32-bit aligned")
  1545  	}
  1546  
  1547  	for _, p := range rt.pages {
  1548  		b := rt.blocks[p]
  1549  
  1550  		// Add a dummy entry at the end of the list if we have an
  1551  		// odd number of entries, so as to ensure that the next
  1552  		// block starts on a 32-bit boundary (see issue 68260).
  1553  		if len(b.entries)&1 != 0 {
  1554  			b.entries = append(b.entries, peBaseRelocEntry{})
  1555  		}
  1556  
  1557  		const sizeOfPEbaseRelocBlock = 8 // 2 * sizeof(uint32)
  1558  		blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2)
  1559  		out.Write32(p)
  1560  		out.Write32(blockSize)
  1561  
  1562  		for _, e := range b.entries {
  1563  			out.Write16(e.typeOff)
  1564  		}
  1565  	}
  1566  }
  1567  
  1568  func addPEBaseRelocSym(ldr *loader.Loader, s loader.Sym, rt *peBaseRelocTable) {
  1569  	relocs := ldr.Relocs(s)
  1570  	for ri := 0; ri < relocs.Count(); ri++ {
  1571  		r := relocs.At(ri)
  1572  		if r.Type() >= objabi.ElfRelocOffset {
  1573  			continue
  1574  		}
  1575  		if r.Siz() == 0 { // informational relocation
  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("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  }
  1754  
  1755  // peCreateExportFile creates a file with exported symbols for Windows .def files.
  1756  // ld will export all symbols, even those not marked for export, unless a .def file is provided.
  1757  func peCreateExportFile(ctxt *Link, libName string) (fname string) {
  1758  	fname = filepath.Join(*flagTmpdir, "export_file.def")
  1759  	var buf bytes.Buffer
  1760  
  1761  	if ctxt.BuildMode == BuildModeCShared {
  1762  		fmt.Fprintf(&buf, "LIBRARY %s\n", libName)
  1763  	}
  1764  	buf.WriteString("EXPORTS\n")
  1765  
  1766  	ldr := ctxt.loader
  1767  	var exports []string
  1768  	for s := range ldr.ForAllCgoExportStatic() {
  1769  		extname := ldr.SymExtname(s)
  1770  		if !strings.HasPrefix(extname, "_cgoexp_") {
  1771  			continue
  1772  		}
  1773  		if ldr.IsFileLocal(s) {
  1774  			continue // Only export non-static symbols
  1775  		}
  1776  		// Retrieve the name of the initial symbol
  1777  		// exported by cgo.
  1778  		// The corresponding Go symbol is:
  1779  		// _cgoexp_hashcode_symname.
  1780  		name := strings.SplitN(extname, "_", 4)[3]
  1781  		exports = append(exports, name)
  1782  	}
  1783  	if len(exports) == 0 {
  1784  		// See runtime/cgo/windows.go for details.
  1785  		exports = append(exports, "_cgo_stub_export")
  1786  	}
  1787  	sort.Strings(exports)
  1788  	buf.WriteString(strings.Join(exports, "\n"))
  1789  
  1790  	err := os.WriteFile(fname, buf.Bytes(), 0666)
  1791  	if err != nil {
  1792  		Errorf("WriteFile %s failed: %v", fname, err)
  1793  	}
  1794  
  1795  	return fname
  1796  }
  1797  

View as plain text