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.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()) - int64(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  

View as plain text