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        int
   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  	switch buildcfg.GOARCH {
   545  	default:
   546  		Exitf("peFile.addInitArray: unsupported GOARCH=%q\n", buildcfg.GOARCH)
   547  	case "386", "arm":
   548  		size = 4
   549  		alignment = IMAGE_SCN_ALIGN_4BYTES
   550  	case "amd64", "arm64":
   551  		size = 8
   552  		alignment = IMAGE_SCN_ALIGN_8BYTES
   553  	}
   554  	sect := f.addSection(".ctors", size, size)
   555  	sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | alignment
   556  	sect.sizeOfRawData = uint32(size)
   557  	ctxt.Out.SeekSet(int64(sect.pointerToRawData))
   558  	sect.checkOffset(ctxt.Out.Offset())
   559  
   560  	init_entry := ctxt.loader.Lookup(*flagEntrySymbol, 0)
   561  	addr := uint64(ctxt.loader.SymValue(init_entry)) - ctxt.loader.SymSect(init_entry).Vaddr
   562  	switch buildcfg.GOARCH {
   563  	case "386", "arm":
   564  		ctxt.Out.Write32(uint32(addr))
   565  	case "amd64", "arm64":
   566  		ctxt.Out.Write64(addr)
   567  	}
   568  	return sect
   569  }
   570  
   571  // emitRelocations emits relocation entries for go.o in external linking.
   572  func (f *peFile) emitRelocations(ctxt *Link) {
   573  	for ctxt.Out.Offset()&7 != 0 {
   574  		ctxt.Out.Write8(0)
   575  	}
   576  
   577  	ldr := ctxt.loader
   578  
   579  	// relocsect relocates symbols from first in section sect, and returns
   580  	// the total number of relocations emitted.
   581  	relocsect := func(sect *sym.Section, syms []loader.Sym, base uint64) int {
   582  		// If main section has no bits, nothing to relocate.
   583  		if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
   584  			return 0
   585  		}
   586  		sect.Reloff = uint64(ctxt.Out.Offset())
   587  		for i, s := range syms {
   588  			if !ldr.AttrReachable(s) {
   589  				continue
   590  			}
   591  			if uint64(ldr.SymValue(s)) >= sect.Vaddr {
   592  				syms = syms[i:]
   593  				break
   594  			}
   595  		}
   596  		eaddr := int64(sect.Vaddr + sect.Length)
   597  		for _, s := range syms {
   598  			if !ldr.AttrReachable(s) {
   599  				continue
   600  			}
   601  			if ldr.SymValue(s) >= eaddr {
   602  				break
   603  			}
   604  			// Compute external relocations on the go, and pass to PEreloc1
   605  			// to stream out.
   606  			relocs := ldr.Relocs(s)
   607  			for ri := 0; ri < relocs.Count(); ri++ {
   608  				r := relocs.At(ri)
   609  				rr, ok := extreloc(ctxt, ldr, s, r)
   610  				if !ok {
   611  					continue
   612  				}
   613  				if rr.Xsym == 0 {
   614  					ctxt.Errorf(s, "missing xsym in relocation")
   615  					continue
   616  				}
   617  				if ldr.SymDynid(rr.Xsym) < 0 {
   618  					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()))
   619  				}
   620  				if !thearch.PEreloc1(ctxt.Arch, ctxt.Out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-base)) {
   621  					ctxt.Errorf(s, "unsupported obj reloc %v/%d to %s", r.Type(), r.Siz(), ldr.SymName(r.Sym()))
   622  				}
   623  			}
   624  		}
   625  		sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
   626  		const relocLen = 4 + 4 + 2
   627  		return int(sect.Rellen / relocLen)
   628  	}
   629  
   630  	type relsect struct {
   631  		peSect *peSection
   632  		seg    *sym.Segment
   633  		syms   []loader.Sym
   634  	}
   635  	sects := []relsect{
   636  		{f.textSect, &Segtext, ctxt.Textp},
   637  		{f.rdataSect, &Segrodata, ctxt.datap},
   638  		{f.dataSect, &Segdata, ctxt.datap},
   639  	}
   640  	if len(sehp.pdata) != 0 {
   641  		sects = append(sects, relsect{f.pdataSect, &Segpdata, sehp.pdata})
   642  	}
   643  	if len(sehp.xdata) != 0 {
   644  		sects = append(sects, relsect{f.xdataSect, &Segxdata, sehp.xdata})
   645  	}
   646  	for _, s := range sects {
   647  		s.peSect.emitRelocations(ctxt.Out, func() int {
   648  			var n int
   649  			for _, sect := range s.seg.Sections {
   650  				n += relocsect(sect, s.syms, s.seg.Vaddr)
   651  			}
   652  			return n
   653  		})
   654  	}
   655  
   656  dwarfLoop:
   657  	for i := 0; i < len(Segdwarf.Sections); i++ {
   658  		sect := Segdwarf.Sections[i]
   659  		si := dwarfp[i]
   660  		if si.secSym() != loader.Sym(sect.Sym) ||
   661  			ldr.SymSect(si.secSym()) != sect {
   662  			panic("inconsistency between dwarfp and Segdwarf")
   663  		}
   664  		for _, pesect := range f.sections {
   665  			if sect.Name == pesect.name {
   666  				pesect.emitRelocations(ctxt.Out, func() int {
   667  					return relocsect(sect, si.syms, sect.Vaddr)
   668  				})
   669  				continue dwarfLoop
   670  			}
   671  		}
   672  		Errorf("emitRelocations: could not find %q section", sect.Name)
   673  	}
   674  
   675  	if f.ctorsSect == nil {
   676  		return
   677  	}
   678  
   679  	f.ctorsSect.emitRelocations(ctxt.Out, func() int {
   680  		dottext := ldr.Lookup(".text", 0)
   681  		ctxt.Out.Write32(0)
   682  		ctxt.Out.Write32(uint32(ldr.SymDynid(dottext)))
   683  		switch buildcfg.GOARCH {
   684  		default:
   685  			ctxt.Errorf(dottext, "unknown architecture for PE: %q\n", buildcfg.GOARCH)
   686  		case "386":
   687  			ctxt.Out.Write16(IMAGE_REL_I386_DIR32)
   688  		case "amd64":
   689  			ctxt.Out.Write16(IMAGE_REL_AMD64_ADDR64)
   690  		case "arm":
   691  			ctxt.Out.Write16(IMAGE_REL_ARM_ADDR32)
   692  		case "arm64":
   693  			ctxt.Out.Write16(IMAGE_REL_ARM64_ADDR64)
   694  		}
   695  		return 1
   696  	})
   697  }
   698  
   699  // writeSymbol appends symbol s to file f symbol table.
   700  // It also sets s.Dynid to written symbol number.
   701  func (f *peFile) writeSymbol(out *OutBuf, ldr *loader.Loader, s loader.Sym, name string, value int64, sectidx int, typ uint16, class uint8) {
   702  	if len(name) > 8 {
   703  		out.Write32(0)
   704  		out.Write32(uint32(f.stringTable.add(name)))
   705  	} else {
   706  		out.WriteStringN(name, 8)
   707  	}
   708  	out.Write32(uint32(value))
   709  	out.Write16(uint16(sectidx))
   710  	out.Write16(typ)
   711  	out.Write8(class)
   712  	out.Write8(0) // no aux entries
   713  
   714  	ldr.SetSymDynid(s, int32(f.symbolCount))
   715  
   716  	f.symbolCount++
   717  }
   718  
   719  // mapToPESection searches peFile f for s symbol's location.
   720  // It returns PE section index, and offset within that section.
   721  func (f *peFile) mapToPESection(ldr *loader.Loader, s loader.Sym, linkmode LinkMode) (pesectidx int, offset int64, err error) {
   722  	sect := ldr.SymSect(s)
   723  	if sect == nil {
   724  		return 0, 0, fmt.Errorf("could not map %s symbol with no section", ldr.SymName(s))
   725  	}
   726  	if sect.Seg == &Segtext {
   727  		return f.textSect.index, int64(uint64(ldr.SymValue(s)) - Segtext.Vaddr), nil
   728  	}
   729  	if sect.Seg == &Segrodata {
   730  		return f.rdataSect.index, int64(uint64(ldr.SymValue(s)) - Segrodata.Vaddr), nil
   731  	}
   732  	if sect.Seg != &Segdata {
   733  		return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .rdata or .data section", ldr.SymName(s))
   734  	}
   735  	v := uint64(ldr.SymValue(s)) - Segdata.Vaddr
   736  	if linkmode != LinkExternal {
   737  		return f.dataSect.index, int64(v), nil
   738  	}
   739  	if ldr.SymType(s).IsDATA() {
   740  		return f.dataSect.index, int64(v), nil
   741  	}
   742  	// Note: although address of runtime.edata (type sym.SDATA) is at the start of .bss section
   743  	// it still belongs to the .data section, not the .bss section.
   744  	if v < Segdata.Filelen {
   745  		return f.dataSect.index, int64(v), nil
   746  	}
   747  	return f.bssSect.index, int64(v - Segdata.Filelen), nil
   748  }
   749  
   750  var isLabel = make(map[loader.Sym]bool)
   751  
   752  func AddPELabelSym(ldr *loader.Loader, s loader.Sym) {
   753  	isLabel[s] = true
   754  }
   755  
   756  // writeSymbols writes all COFF symbol table records.
   757  func (f *peFile) writeSymbols(ctxt *Link) {
   758  	ldr := ctxt.loader
   759  	addsym := func(s loader.Sym) {
   760  		t := ldr.SymType(s)
   761  		if ldr.SymSect(s) == nil && t != sym.SDYNIMPORT && t != sym.SHOSTOBJ && t != sym.SUNDEFEXT {
   762  			return
   763  		}
   764  
   765  		name := ldr.SymName(s)
   766  
   767  		// Only windows/386 requires underscore prefix on external symbols.
   768  		if ctxt.Is386() && ctxt.IsExternal() &&
   769  			(t == sym.SHOSTOBJ || t == sym.SUNDEFEXT || ldr.AttrCgoExport(s) ||
   770  				// TODO(cuonglm): remove this hack
   771  				//
   772  				// Previously, windows/386 requires underscore prefix on external symbols,
   773  				// but that's only applied for SHOSTOBJ/SUNDEFEXT or cgo export symbols.
   774  				// "go.buildid" is STEXT, "type.*" is STYPE, thus they are not prefixed
   775  				// with underscore.
   776  				//
   777  				// In external linking mode, the external linker can't resolve them as
   778  				// external symbols. But we are lucky that they have "." in their name,
   779  				// so the external linker see them as Forwarder RVA exports. See:
   780  				//
   781  				//  - https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#export-address-table
   782  				//  - https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=ld/pe-dll.c;h=e7b82ba6ffadf74dc1b9ee71dc13d48336941e51;hb=HEAD#l972
   783  				//
   784  				// CL 317917 changes "." to ":" in symbols name, so these symbols can not be
   785  				// found by external linker anymore. So a hacky way is adding the
   786  				// underscore prefix for these 2 symbols. I don't have enough knowledge to
   787  				// verify whether adding the underscore for all STEXT/STYPE symbols are
   788  				// fine, even if it could be, that would be done in future CL.
   789  				name == "go:buildid" || name == "type:*") {
   790  			name = "_" + name
   791  		}
   792  
   793  		name = mangleABIName(ctxt, ldr, s, name)
   794  
   795  		var peSymType uint16 = IMAGE_SYM_TYPE_NULL
   796  		switch {
   797  		case t.IsText(), t == sym.SDYNIMPORT, t == sym.SHOSTOBJ, t == sym.SUNDEFEXT:
   798  			// Microsoft's PE documentation is contradictory. It says that the symbol's complex type
   799  			// is stored in the pesym.Type most significant byte, but MSVC, LLVM, and mingw store it
   800  			// in the 4 high bits of the less significant byte. Also, the PE documentation says that
   801  			// the basic type for a function should be IMAGE_SYM_TYPE_VOID,
   802  			// but the reality is that it uses IMAGE_SYM_TYPE_NULL instead.
   803  			peSymType = IMAGE_SYM_DTYPE_FUNCTION<<4 + IMAGE_SYM_TYPE_NULL
   804  		}
   805  		sect, value, err := f.mapToPESection(ldr, s, ctxt.LinkMode)
   806  		if err != nil {
   807  			switch t {
   808  			case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
   809  			default:
   810  				ctxt.Errorf(s, "addpesym: %v", err)
   811  			}
   812  		}
   813  		class := IMAGE_SYM_CLASS_EXTERNAL
   814  		if ldr.IsFileLocal(s) || ldr.AttrVisibilityHidden(s) || ldr.AttrLocal(s) {
   815  			class = IMAGE_SYM_CLASS_STATIC
   816  		}
   817  		f.writeSymbol(ctxt.Out, ldr, s, name, value, sect, peSymType, uint8(class))
   818  	}
   819  
   820  	if ctxt.LinkMode == LinkExternal {
   821  		// Include section symbols as external, because
   822  		// .ctors and .debug_* section relocations refer to it.
   823  		for _, pesect := range f.sections {
   824  			s := ldr.LookupOrCreateSym(pesect.name, 0)
   825  			f.writeSymbol(ctxt.Out, ldr, s, pesect.name, 0, pesect.index, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC)
   826  		}
   827  	}
   828  
   829  	// Add special runtime.text and runtime.etext symbols.
   830  	s := ldr.Lookup("runtime.text", 0)
   831  	if ldr.SymType(s).IsText() {
   832  		addsym(s)
   833  	}
   834  	s = ldr.Lookup("runtime.etext", 0)
   835  	if ldr.SymType(s).IsText() {
   836  		addsym(s)
   837  	}
   838  
   839  	// Add text symbols.
   840  	for _, s := range ctxt.Textp {
   841  		addsym(s)
   842  	}
   843  
   844  	shouldBeInSymbolTable := func(s loader.Sym) bool {
   845  		if ldr.AttrNotInSymbolTable(s) {
   846  			return false
   847  		}
   848  		name := ldr.SymName(s) // TODO: try not to read the name
   849  		if name == "" || name[0] == '.' {
   850  			return false
   851  		}
   852  		return true
   853  	}
   854  
   855  	// Add data symbols and external references.
   856  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
   857  		if !ldr.AttrReachable(s) {
   858  			continue
   859  		}
   860  		t := ldr.SymType(s)
   861  		if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
   862  			if t == sym.STLSBSS {
   863  				continue
   864  			}
   865  			if !shouldBeInSymbolTable(s) {
   866  				continue
   867  			}
   868  			addsym(s)
   869  		}
   870  
   871  		switch t {
   872  		case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
   873  			addsym(s)
   874  		default:
   875  			if len(isLabel) > 0 && isLabel[s] {
   876  				addsym(s)
   877  			}
   878  		}
   879  	}
   880  }
   881  
   882  // writeSymbolTableAndStringTable writes out symbol and string tables for peFile f.
   883  func (f *peFile) writeSymbolTableAndStringTable(ctxt *Link) {
   884  	f.symtabOffset = ctxt.Out.Offset()
   885  
   886  	// write COFF symbol table
   887  	if !*FlagS || ctxt.LinkMode == LinkExternal {
   888  		f.writeSymbols(ctxt)
   889  	}
   890  
   891  	// update COFF file header and section table
   892  	size := f.stringTable.size() + 18*f.symbolCount
   893  	var h *peSection
   894  	if ctxt.LinkMode != LinkExternal {
   895  		// We do not really need .symtab for go.o, and if we have one, ld
   896  		// will also include it in the exe, and that will confuse windows.
   897  		h = f.addSection(".symtab", size, size)
   898  		h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
   899  		h.checkOffset(f.symtabOffset)
   900  	}
   901  
   902  	// write COFF string table
   903  	f.stringTable.write(ctxt.Out)
   904  	if ctxt.LinkMode != LinkExternal {
   905  		h.pad(ctxt.Out, uint32(size))
   906  	}
   907  }
   908  
   909  // writeFileHeader writes COFF file header for peFile f.
   910  func (f *peFile) writeFileHeader(ctxt *Link) {
   911  	var fh pe.FileHeader
   912  
   913  	switch ctxt.Arch.Family {
   914  	default:
   915  		Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
   916  	case sys.AMD64:
   917  		fh.Machine = pe.IMAGE_FILE_MACHINE_AMD64
   918  	case sys.I386:
   919  		fh.Machine = pe.IMAGE_FILE_MACHINE_I386
   920  	case sys.ARM:
   921  		fh.Machine = pe.IMAGE_FILE_MACHINE_ARMNT
   922  	case sys.ARM64:
   923  		fh.Machine = pe.IMAGE_FILE_MACHINE_ARM64
   924  	}
   925  
   926  	fh.NumberOfSections = uint16(len(f.sections))
   927  
   928  	// Being able to produce identical output for identical input is
   929  	// much more beneficial than having build timestamp in the header.
   930  	fh.TimeDateStamp = 0
   931  
   932  	if ctxt.LinkMode != LinkExternal {
   933  		fh.Characteristics = pe.IMAGE_FILE_EXECUTABLE_IMAGE
   934  		switch ctxt.Arch.Family {
   935  		case sys.AMD64, sys.I386:
   936  			if ctxt.BuildMode != BuildModePIE {
   937  				fh.Characteristics |= pe.IMAGE_FILE_RELOCS_STRIPPED
   938  			}
   939  		}
   940  	}
   941  	if pe64 != 0 {
   942  		var oh64 pe.OptionalHeader64
   943  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
   944  		fh.Characteristics |= pe.IMAGE_FILE_LARGE_ADDRESS_AWARE
   945  	} else {
   946  		var oh pe.OptionalHeader32
   947  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
   948  		fh.Characteristics |= pe.IMAGE_FILE_32BIT_MACHINE
   949  	}
   950  
   951  	fh.PointerToSymbolTable = uint32(f.symtabOffset)
   952  	fh.NumberOfSymbols = uint32(f.symbolCount)
   953  
   954  	binary.Write(ctxt.Out, binary.LittleEndian, &fh)
   955  }
   956  
   957  // writeOptionalHeader writes COFF optional header for peFile f.
   958  func (f *peFile) writeOptionalHeader(ctxt *Link) {
   959  	var oh pe.OptionalHeader32
   960  	var oh64 pe.OptionalHeader64
   961  
   962  	if pe64 != 0 {
   963  		oh64.Magic = 0x20b // PE32+
   964  	} else {
   965  		oh.Magic = 0x10b // PE32
   966  		oh.BaseOfData = f.dataSect.virtualAddress
   967  	}
   968  
   969  	// Fill out both oh64 and oh. We only use one. Oh well.
   970  	oh64.MajorLinkerVersion = 3
   971  	oh.MajorLinkerVersion = 3
   972  	oh64.MinorLinkerVersion = 0
   973  	oh.MinorLinkerVersion = 0
   974  	oh64.SizeOfCode = f.textSect.sizeOfRawData
   975  	oh.SizeOfCode = f.textSect.sizeOfRawData
   976  	oh64.SizeOfInitializedData = f.dataSect.sizeOfRawData
   977  	oh.SizeOfInitializedData = f.dataSect.sizeOfRawData
   978  	oh64.SizeOfUninitializedData = 0
   979  	oh.SizeOfUninitializedData = 0
   980  	if ctxt.LinkMode != LinkExternal {
   981  		oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
   982  		oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
   983  	}
   984  	oh64.BaseOfCode = f.textSect.virtualAddress
   985  	oh.BaseOfCode = f.textSect.virtualAddress
   986  	oh64.ImageBase = uint64(PEBASE)
   987  	oh.ImageBase = uint32(PEBASE)
   988  	oh64.SectionAlignment = uint32(PESECTALIGN)
   989  	oh.SectionAlignment = uint32(PESECTALIGN)
   990  	oh64.FileAlignment = uint32(PEFILEALIGN)
   991  	oh.FileAlignment = uint32(PEFILEALIGN)
   992  	oh64.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
   993  	oh.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
   994  	oh64.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
   995  	oh.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
   996  	oh64.MajorImageVersion = 1
   997  	oh.MajorImageVersion = 1
   998  	oh64.MinorImageVersion = 0
   999  	oh.MinorImageVersion = 0
  1000  	oh64.MajorSubsystemVersion = PeMinimumTargetMajorVersion
  1001  	oh.MajorSubsystemVersion = PeMinimumTargetMajorVersion
  1002  	oh64.MinorSubsystemVersion = PeMinimumTargetMinorVersion
  1003  	oh.MinorSubsystemVersion = PeMinimumTargetMinorVersion
  1004  	oh64.SizeOfImage = f.nextSectOffset
  1005  	oh.SizeOfImage = f.nextSectOffset
  1006  	oh64.SizeOfHeaders = uint32(PEFILEHEADR)
  1007  	oh.SizeOfHeaders = uint32(PEFILEHEADR)
  1008  	if windowsgui {
  1009  		oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
  1010  		oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
  1011  	} else {
  1012  		oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
  1013  		oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
  1014  	}
  1015  
  1016  	// Mark as having awareness of terminal services, to avoid ancient compatibility hacks.
  1017  	oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
  1018  	oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
  1019  
  1020  	// Enable DEP
  1021  	oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
  1022  	oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
  1023  
  1024  	// The DLL can be relocated at load time.
  1025  	if needPEBaseReloc(ctxt) {
  1026  		oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
  1027  		oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
  1028  	}
  1029  
  1030  	// Image can handle a high entropy 64-bit virtual address space.
  1031  	if ctxt.BuildMode == BuildModePIE {
  1032  		oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
  1033  	}
  1034  
  1035  	// Disable stack growth as we don't want Windows to
  1036  	// fiddle with the thread stack limits, which we set
  1037  	// ourselves to circumvent the stack checks in the
  1038  	// Windows exception dispatcher.
  1039  	// Commit size must be strictly less than reserve
  1040  	// size otherwise reserve will be rounded up to a
  1041  	// larger size, as verified with VMMap.
  1042  
  1043  	// On 64-bit, we always reserve 2MB stacks. "Pure" Go code is
  1044  	// okay with much smaller stacks, but the syscall package
  1045  	// makes it easy to call into arbitrary C code without cgo,
  1046  	// and system calls even in "pure" Go code are actually C
  1047  	// calls that may need more stack than we think.
  1048  	//
  1049  	// The default stack reserve size directly affects only the main
  1050  	// thread.
  1051  	//
  1052  	// For other threads, the runtime explicitly asks the kernel
  1053  	// to use the default stack size so that all stacks are
  1054  	// consistent.
  1055  	//
  1056  	// At thread start, in minit, the runtime queries the OS for
  1057  	// the actual stack bounds so that the stack size doesn't need
  1058  	// to be hard-coded into the runtime.
  1059  	oh64.SizeOfStackReserve = 0x00200000
  1060  	if !iscgo {
  1061  		oh64.SizeOfStackCommit = 0x00001000
  1062  	} else {
  1063  		// TODO(brainman): Maybe remove optional header writing altogether for cgo.
  1064  		// For cgo it is the external linker that is building final executable.
  1065  		// And it probably does not use any information stored in optional header.
  1066  		oh64.SizeOfStackCommit = 0x00200000 - 0x2000 // account for 2 guard pages
  1067  	}
  1068  
  1069  	oh.SizeOfStackReserve = 0x00100000
  1070  	if !iscgo {
  1071  		oh.SizeOfStackCommit = 0x00001000
  1072  	} else {
  1073  		oh.SizeOfStackCommit = 0x00100000 - 0x2000 // account for 2 guard pages
  1074  	}
  1075  
  1076  	oh64.SizeOfHeapReserve = 0x00100000
  1077  	oh.SizeOfHeapReserve = 0x00100000
  1078  	oh64.SizeOfHeapCommit = 0x00001000
  1079  	oh.SizeOfHeapCommit = 0x00001000
  1080  	oh64.NumberOfRvaAndSizes = 16
  1081  	oh.NumberOfRvaAndSizes = 16
  1082  
  1083  	if pe64 != 0 {
  1084  		oh64.DataDirectory = f.dataDirectory
  1085  	} else {
  1086  		oh.DataDirectory = f.dataDirectory
  1087  	}
  1088  
  1089  	if pe64 != 0 {
  1090  		binary.Write(ctxt.Out, binary.LittleEndian, &oh64)
  1091  	} else {
  1092  		binary.Write(ctxt.Out, binary.LittleEndian, &oh)
  1093  	}
  1094  }
  1095  
  1096  var pefile peFile
  1097  
  1098  func Peinit(ctxt *Link) {
  1099  	var l int
  1100  
  1101  	if ctxt.Arch.PtrSize == 8 {
  1102  		// 64-bit architectures
  1103  		pe64 = 1
  1104  		PEBASE = 1 << 32
  1105  		if ctxt.Arch.Family == sys.AMD64 {
  1106  			// TODO(rsc): For cgo we currently use 32-bit relocations
  1107  			// that fail when PEBASE is too large.
  1108  			// We need to fix this, but for now, use a smaller PEBASE.
  1109  			PEBASE = 1 << 22
  1110  		}
  1111  		var oh64 pe.OptionalHeader64
  1112  		l = binary.Size(&oh64)
  1113  	} else {
  1114  		// 32-bit architectures
  1115  		PEBASE = 1 << 22
  1116  		var oh pe.OptionalHeader32
  1117  		l = binary.Size(&oh)
  1118  	}
  1119  
  1120  	if ctxt.LinkMode == LinkExternal {
  1121  		// .rdata section will contain "masks" and "shifts" symbols, and they
  1122  		// need to be aligned to 16-bytes. So make all sections aligned
  1123  		// to 32-byte and mark them all IMAGE_SCN_ALIGN_32BYTES so external
  1124  		// linker will honour that requirement.
  1125  		PESECTALIGN = 32
  1126  		PEFILEALIGN = 0
  1127  		// We are creating an object file. The absolute address is irrelevant.
  1128  		PEBASE = 0
  1129  	}
  1130  
  1131  	var sh [16]pe.SectionHeader32
  1132  	var fh pe.FileHeader
  1133  	PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
  1134  	if ctxt.LinkMode != LinkExternal {
  1135  		PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
  1136  	} else {
  1137  		PESECTHEADR = 0
  1138  	}
  1139  	pefile.nextSectOffset = uint32(PESECTHEADR)
  1140  	pefile.nextFileOffset = uint32(PEFILEHEADR)
  1141  
  1142  	if ctxt.LinkMode == LinkInternal {
  1143  		// some mingw libs depend on this symbol, for example, FindPESectionByName
  1144  		for _, name := range [2]string{"__image_base__", "_image_base__"} {
  1145  			sb := ctxt.loader.CreateSymForUpdate(name, 0)
  1146  			sb.SetType(sym.SDATA)
  1147  			sb.SetValue(PEBASE)
  1148  			ctxt.loader.SetAttrSpecial(sb.Sym(), true)
  1149  			ctxt.loader.SetAttrLocal(sb.Sym(), true)
  1150  		}
  1151  	}
  1152  
  1153  	HEADR = PEFILEHEADR
  1154  	if *FlagRound == -1 {
  1155  		*FlagRound = PESECTALIGN
  1156  	}
  1157  	if *FlagTextAddr == -1 {
  1158  		*FlagTextAddr = Rnd(PEBASE, *FlagRound) + int64(PESECTHEADR)
  1159  	}
  1160  }
  1161  
  1162  func pewrite(ctxt *Link) {
  1163  	ctxt.Out.SeekSet(0)
  1164  	if ctxt.LinkMode != LinkExternal {
  1165  		ctxt.Out.Write(dosstub)
  1166  		ctxt.Out.WriteStringN("PE", 4)
  1167  	}
  1168  
  1169  	pefile.writeFileHeader(ctxt)
  1170  
  1171  	pefile.writeOptionalHeader(ctxt)
  1172  
  1173  	for _, sect := range pefile.sections {
  1174  		sect.write(ctxt.Out, ctxt.LinkMode)
  1175  	}
  1176  }
  1177  
  1178  func strput(out *OutBuf, s string) {
  1179  	out.WriteString(s)
  1180  	out.Write8(0)
  1181  	// string must be padded to even size
  1182  	if (len(s)+1)%2 != 0 {
  1183  		out.Write8(0)
  1184  	}
  1185  }
  1186  
  1187  func initdynimport(ctxt *Link) *Dll {
  1188  	ldr := ctxt.loader
  1189  	var d *Dll
  1190  
  1191  	dr = nil
  1192  	var m *Imp
  1193  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
  1194  		if !ldr.AttrReachable(s) || ldr.SymType(s) != sym.SDYNIMPORT {
  1195  			continue
  1196  		}
  1197  		dynlib := ldr.SymDynimplib(s)
  1198  		for d = dr; d != nil; d = d.next {
  1199  			if d.name == dynlib {
  1200  				m = new(Imp)
  1201  				break
  1202  			}
  1203  		}
  1204  
  1205  		if d == nil {
  1206  			d = new(Dll)
  1207  			d.name = dynlib
  1208  			d.next = dr
  1209  			dr = d
  1210  			m = new(Imp)
  1211  		}
  1212  
  1213  		// Because external link requires properly stdcall decorated name,
  1214  		// all external symbols in runtime use %n to denote that the number
  1215  		// of uinptrs this function consumes. Store the argsize and discard
  1216  		// the %n suffix if any.
  1217  		m.argsize = -1
  1218  		extName := ldr.SymExtname(s)
  1219  		if i := strings.IndexByte(extName, '%'); i >= 0 {
  1220  			var err error
  1221  			m.argsize, err = strconv.Atoi(extName[i+1:])
  1222  			if err != nil {
  1223  				ctxt.Errorf(s, "failed to parse stdcall decoration: %v", err)
  1224  			}
  1225  			m.argsize *= ctxt.Arch.PtrSize
  1226  			ldr.SetSymExtname(s, extName[:i])
  1227  		}
  1228  
  1229  		m.s = s
  1230  		m.next = d.ms
  1231  		d.ms = m
  1232  	}
  1233  
  1234  	if ctxt.IsExternal() {
  1235  		// Add real symbol name
  1236  		for d := dr; d != nil; d = d.next {
  1237  			for m = d.ms; m != nil; m = m.next {
  1238  				sb := ldr.MakeSymbolUpdater(m.s)
  1239  				sb.SetType(sym.SDATA)
  1240  				sb.Grow(int64(ctxt.Arch.PtrSize))
  1241  				dynName := sb.Extname()
  1242  				// only windows/386 requires stdcall decoration
  1243  				if ctxt.Is386() && m.argsize >= 0 {
  1244  					dynName += fmt.Sprintf("@%d", m.argsize)
  1245  				}
  1246  				dynSym := ldr.CreateSymForUpdate(dynName, 0)
  1247  				dynSym.SetType(sym.SHOSTOBJ)
  1248  				r, _ := sb.AddRel(objabi.R_ADDR)
  1249  				r.SetSym(dynSym.Sym())
  1250  				r.SetSiz(uint8(ctxt.Arch.PtrSize))
  1251  			}
  1252  		}
  1253  	} else {
  1254  		dynamic := ldr.CreateSymForUpdate(".windynamic", 0)
  1255  		dynamic.SetType(sym.SWINDOWS)
  1256  		for d := dr; d != nil; d = d.next {
  1257  			for m = d.ms; m != nil; m = m.next {
  1258  				sb := ldr.MakeSymbolUpdater(m.s)
  1259  				sb.SetType(sym.SWINDOWS)
  1260  				sb.SetValue(dynamic.Size())
  1261  				dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
  1262  				dynamic.AddInteriorSym(m.s)
  1263  			}
  1264  
  1265  			dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
  1266  		}
  1267  	}
  1268  
  1269  	return dr
  1270  }
  1271  
  1272  // peimporteddlls returns the gcc command line argument to link all imported
  1273  // DLLs.
  1274  func peimporteddlls() []string {
  1275  	var dlls []string
  1276  
  1277  	for d := dr; d != nil; d = d.next {
  1278  		dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
  1279  	}
  1280  
  1281  	return dlls
  1282  }
  1283  
  1284  func addimports(ctxt *Link, datsect *peSection) {
  1285  	ldr := ctxt.loader
  1286  	startoff := ctxt.Out.Offset()
  1287  	dynamic := ldr.LookupOrCreateSym(".windynamic", 0)
  1288  
  1289  	// skip import descriptor table (will write it later)
  1290  	n := uint64(0)
  1291  
  1292  	for d := dr; d != nil; d = d.next {
  1293  		n++
  1294  	}
  1295  	ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
  1296  
  1297  	// write dll names
  1298  	for d := dr; d != nil; d = d.next {
  1299  		d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff)
  1300  		strput(ctxt.Out, d.name)
  1301  	}
  1302  
  1303  	// write function names
  1304  	for d := dr; d != nil; d = d.next {
  1305  		for m := d.ms; m != nil; m = m.next {
  1306  			m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
  1307  			ctxt.Out.Write16(0) // hint
  1308  			strput(ctxt.Out, ldr.SymExtname(m.s))
  1309  		}
  1310  	}
  1311  
  1312  	// write OriginalFirstThunks
  1313  	oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff)
  1314  
  1315  	n = uint64(ctxt.Out.Offset())
  1316  	for d := dr; d != nil; d = d.next {
  1317  		d.thunkoff = uint64(ctxt.Out.Offset()) - n
  1318  		for m := d.ms; m != nil; m = m.next {
  1319  			if pe64 != 0 {
  1320  				ctxt.Out.Write64(m.off)
  1321  			} else {
  1322  				ctxt.Out.Write32(uint32(m.off))
  1323  			}
  1324  		}
  1325  
  1326  		if pe64 != 0 {
  1327  			ctxt.Out.Write64(0)
  1328  		} else {
  1329  			ctxt.Out.Write32(0)
  1330  		}
  1331  	}
  1332  
  1333  	// add pe section and pad it at the end
  1334  	n = uint64(ctxt.Out.Offset()) - uint64(startoff)
  1335  
  1336  	isect := pefile.addSection(".idata", int(n), int(n))
  1337  	isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1338  	isect.checkOffset(startoff)
  1339  	isect.pad(ctxt.Out, uint32(n))
  1340  	endoff := ctxt.Out.Offset()
  1341  
  1342  	// write FirstThunks (allocated in .data section)
  1343  	ftbase := uint64(ldr.SymValue(dynamic)) - uint64(datsect.virtualAddress) - uint64(PEBASE)
  1344  
  1345  	ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase))
  1346  	for d := dr; d != nil; d = d.next {
  1347  		for m := d.ms; m != nil; m = m.next {
  1348  			if pe64 != 0 {
  1349  				ctxt.Out.Write64(m.off)
  1350  			} else {
  1351  				ctxt.Out.Write32(uint32(m.off))
  1352  			}
  1353  		}
  1354  
  1355  		if pe64 != 0 {
  1356  			ctxt.Out.Write64(0)
  1357  		} else {
  1358  			ctxt.Out.Write32(0)
  1359  		}
  1360  	}
  1361  
  1362  	// finally write import descriptor table
  1363  	out := ctxt.Out
  1364  	out.SeekSet(startoff)
  1365  
  1366  	for d := dr; d != nil; d = d.next {
  1367  		out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff))
  1368  		out.Write32(0)
  1369  		out.Write32(0)
  1370  		out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff))
  1371  		out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff))
  1372  	}
  1373  
  1374  	out.Write32(0) //end
  1375  	out.Write32(0)
  1376  	out.Write32(0)
  1377  	out.Write32(0)
  1378  	out.Write32(0)
  1379  
  1380  	// update data directory
  1381  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
  1382  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
  1383  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(ldr.SymValue(dynamic) - PEBASE)
  1384  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(ldr.SymSize(dynamic))
  1385  
  1386  	out.SeekSet(endoff)
  1387  }
  1388  
  1389  func initdynexport(ctxt *Link) {
  1390  	ldr := ctxt.loader
  1391  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
  1392  		if !ldr.AttrReachable(s) || !ldr.AttrCgoExportDynamic(s) {
  1393  			continue
  1394  		}
  1395  		if len(dexport) >= math.MaxUint16 {
  1396  			ctxt.Errorf(s, "pe dynexport table is full")
  1397  			errorexit()
  1398  		}
  1399  
  1400  		dexport = append(dexport, s)
  1401  	}
  1402  
  1403  	sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) })
  1404  }
  1405  
  1406  func addexports(ctxt *Link) {
  1407  	ldr := ctxt.loader
  1408  	var e IMAGE_EXPORT_DIRECTORY
  1409  
  1410  	nexport := len(dexport)
  1411  	size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
  1412  	for _, s := range dexport {
  1413  		size += len(ldr.SymExtname(s)) + 1
  1414  	}
  1415  
  1416  	if nexport == 0 {
  1417  		return
  1418  	}
  1419  
  1420  	sect := pefile.addSection(".edata", size, size)
  1421  	sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
  1422  	sect.checkOffset(ctxt.Out.Offset())
  1423  	va := int(sect.virtualAddress)
  1424  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
  1425  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
  1426  
  1427  	vaName := va + binary.Size(&e) + nexport*4
  1428  	vaAddr := va + binary.Size(&e)
  1429  	vaNa := va + binary.Size(&e) + nexport*8
  1430  
  1431  	e.Characteristics = 0
  1432  	e.MajorVersion = 0
  1433  	e.MinorVersion = 0
  1434  	e.NumberOfFunctions = uint32(nexport)
  1435  	e.NumberOfNames = uint32(nexport)
  1436  	e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
  1437  	e.Base = 1
  1438  	e.AddressOfFunctions = uint32(vaAddr)
  1439  	e.AddressOfNames = uint32(vaName)
  1440  	e.AddressOfNameOrdinals = uint32(vaNa)
  1441  
  1442  	out := ctxt.Out
  1443  
  1444  	// put IMAGE_EXPORT_DIRECTORY
  1445  	binary.Write(out, binary.LittleEndian, &e)
  1446  
  1447  	// put EXPORT Address Table
  1448  	for _, s := range dexport {
  1449  		out.Write32(uint32(ldr.SymValue(s) - PEBASE))
  1450  	}
  1451  
  1452  	// put EXPORT Name Pointer Table
  1453  	v := int(e.Name + uint32(len(*flagOutfile)) + 1)
  1454  
  1455  	for _, s := range dexport {
  1456  		out.Write32(uint32(v))
  1457  		v += len(ldr.SymExtname(s)) + 1
  1458  	}
  1459  
  1460  	// put EXPORT Ordinal Table
  1461  	for i := 0; i < nexport; i++ {
  1462  		out.Write16(uint16(i))
  1463  	}
  1464  
  1465  	// put Names
  1466  	out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
  1467  
  1468  	for _, s := range dexport {
  1469  		name := ldr.SymExtname(s)
  1470  		out.WriteStringN(name, len(name)+1)
  1471  	}
  1472  	sect.pad(out, uint32(size))
  1473  }
  1474  
  1475  // peBaseRelocEntry represents a single relocation entry.
  1476  type peBaseRelocEntry struct {
  1477  	typeOff uint16
  1478  }
  1479  
  1480  // peBaseRelocBlock represents a Base Relocation Block. A block
  1481  // is a collection of relocation entries in a page, where each
  1482  // entry describes a single relocation.
  1483  // The block page RVA (Relative Virtual Address) is the index
  1484  // into peBaseRelocTable.blocks.
  1485  type peBaseRelocBlock struct {
  1486  	entries []peBaseRelocEntry
  1487  }
  1488  
  1489  // pePages is a type used to store the list of pages for which there
  1490  // are base relocation blocks. This is defined as a type so that
  1491  // it can be sorted.
  1492  type pePages []uint32
  1493  
  1494  // A PE base relocation table is a list of blocks, where each block
  1495  // contains relocation information for a single page. The blocks
  1496  // must be emitted in order of page virtual address.
  1497  // See https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-reloc-section-image-only
  1498  type peBaseRelocTable struct {
  1499  	blocks map[uint32]peBaseRelocBlock
  1500  
  1501  	// pePages is a list of keys into blocks map.
  1502  	// It is stored separately for ease of sorting.
  1503  	pages pePages
  1504  }
  1505  
  1506  func (rt *peBaseRelocTable) init(ctxt *Link) {
  1507  	rt.blocks = make(map[uint32]peBaseRelocBlock)
  1508  }
  1509  
  1510  func (rt *peBaseRelocTable) addentry(ldr *loader.Loader, s loader.Sym, r *loader.Reloc) {
  1511  	// pageSize is the size in bytes of a page
  1512  	// described by a base relocation block.
  1513  	const pageSize = 0x1000
  1514  	const pageMask = pageSize - 1
  1515  
  1516  	addr := ldr.SymValue(s) + int64(r.Off()) - int64(PEBASE)
  1517  	page := uint32(addr &^ pageMask)
  1518  	off := uint32(addr & pageMask)
  1519  
  1520  	b, ok := rt.blocks[page]
  1521  	if !ok {
  1522  		rt.pages = append(rt.pages, page)
  1523  	}
  1524  
  1525  	e := peBaseRelocEntry{
  1526  		typeOff: uint16(off & 0xFFF),
  1527  	}
  1528  
  1529  	// Set entry type
  1530  	switch r.Siz() {
  1531  	default:
  1532  		Exitf("unsupported relocation size %d\n", r.Siz)
  1533  	case 4:
  1534  		e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12)
  1535  	case 8:
  1536  		e.typeOff |= uint16(IMAGE_REL_BASED_DIR64 << 12)
  1537  	}
  1538  
  1539  	b.entries = append(b.entries, e)
  1540  	rt.blocks[page] = b
  1541  }
  1542  
  1543  func (rt *peBaseRelocTable) write(ctxt *Link) {
  1544  	out := ctxt.Out
  1545  
  1546  	// sort the pages array
  1547  	slices.Sort(rt.pages)
  1548  
  1549  	// .reloc section must be 32-bit aligned
  1550  	if out.Offset()&3 != 0 {
  1551  		Errorf("internal error, start of .reloc not 32-bit aligned")
  1552  	}
  1553  
  1554  	for _, p := range rt.pages {
  1555  		b := rt.blocks[p]
  1556  
  1557  		// Add a dummy entry at the end of the list if we have an
  1558  		// odd number of entries, so as to ensure that the next
  1559  		// block starts on a 32-bit boundary (see issue 68260).
  1560  		if len(b.entries)&1 != 0 {
  1561  			b.entries = append(b.entries, peBaseRelocEntry{})
  1562  		}
  1563  
  1564  		const sizeOfPEbaseRelocBlock = 8 // 2 * sizeof(uint32)
  1565  		blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2)
  1566  		out.Write32(p)
  1567  		out.Write32(blockSize)
  1568  
  1569  		for _, e := range b.entries {
  1570  			out.Write16(e.typeOff)
  1571  		}
  1572  	}
  1573  }
  1574  
  1575  func addPEBaseRelocSym(ldr *loader.Loader, s loader.Sym, rt *peBaseRelocTable) {
  1576  	relocs := ldr.Relocs(s)
  1577  	for ri := 0; ri < relocs.Count(); ri++ {
  1578  		r := relocs.At(ri)
  1579  		if r.Type() >= objabi.ElfRelocOffset {
  1580  			continue
  1581  		}
  1582  		if r.Siz() == 0 { // informational relocation
  1583  			continue
  1584  		}
  1585  		if r.Type() == objabi.R_DWARFFILEREF {
  1586  			continue
  1587  		}
  1588  		rs := r.Sym()
  1589  		if rs == 0 {
  1590  			continue
  1591  		}
  1592  		if !ldr.AttrReachable(s) {
  1593  			continue
  1594  		}
  1595  
  1596  		switch r.Type() {
  1597  		default:
  1598  		case objabi.R_ADDR:
  1599  			rt.addentry(ldr, s, &r)
  1600  		}
  1601  	}
  1602  }
  1603  
  1604  func needPEBaseReloc(ctxt *Link) bool {
  1605  	// Non-PIE x86 binaries don't need the base relocation table.
  1606  	// Everyone else does.
  1607  	if (ctxt.Arch.Family == sys.I386 || ctxt.Arch.Family == sys.AMD64) && ctxt.BuildMode != BuildModePIE {
  1608  		return false
  1609  	}
  1610  	return true
  1611  }
  1612  
  1613  func addPEBaseReloc(ctxt *Link) {
  1614  	if !needPEBaseReloc(ctxt) {
  1615  		return
  1616  	}
  1617  
  1618  	var rt peBaseRelocTable
  1619  	rt.init(ctxt)
  1620  
  1621  	// Get relocation information
  1622  	ldr := ctxt.loader
  1623  	for _, s := range ctxt.Textp {
  1624  		addPEBaseRelocSym(ldr, s, &rt)
  1625  	}
  1626  	for _, s := range ctxt.datap {
  1627  		addPEBaseRelocSym(ldr, s, &rt)
  1628  	}
  1629  
  1630  	// Write relocation information
  1631  	startoff := ctxt.Out.Offset()
  1632  	rt.write(ctxt)
  1633  	size := ctxt.Out.Offset() - startoff
  1634  
  1635  	// Add a PE section and pad it at the end
  1636  	rsect := pefile.addSection(".reloc", int(size), int(size))
  1637  	rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
  1638  	rsect.checkOffset(startoff)
  1639  	rsect.pad(ctxt.Out, uint32(size))
  1640  
  1641  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
  1642  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
  1643  }
  1644  
  1645  func (ctxt *Link) dope() {
  1646  	initdynimport(ctxt)
  1647  	initdynexport(ctxt)
  1648  	writeSEH(ctxt)
  1649  }
  1650  
  1651  func setpersrc(ctxt *Link, syms []loader.Sym) {
  1652  	if len(rsrcsyms) != 0 {
  1653  		Errorf("too many .rsrc sections")
  1654  	}
  1655  	rsrcsyms = syms
  1656  }
  1657  
  1658  func addpersrc(ctxt *Link) {
  1659  	if len(rsrcsyms) == 0 {
  1660  		return
  1661  	}
  1662  
  1663  	var size int64
  1664  	for _, rsrcsym := range rsrcsyms {
  1665  		size += ctxt.loader.SymSize(rsrcsym)
  1666  	}
  1667  	h := pefile.addSection(".rsrc", int(size), int(size))
  1668  	h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA
  1669  	h.checkOffset(ctxt.Out.Offset())
  1670  
  1671  	for _, rsrcsym := range rsrcsyms {
  1672  		// A split resource happens when the actual resource data and its relocations are
  1673  		// split across multiple sections, denoted by a $01 or $02 at the end of the .rsrc
  1674  		// section name.
  1675  		splitResources := strings.Contains(ctxt.loader.SymName(rsrcsym), ".rsrc$")
  1676  		relocs := ctxt.loader.Relocs(rsrcsym)
  1677  		data := ctxt.loader.Data(rsrcsym)
  1678  		for ri := 0; ri < relocs.Count(); ri++ {
  1679  			r := relocs.At(ri)
  1680  			p := data[r.Off():]
  1681  			val := uint32(int64(h.virtualAddress) + r.Add())
  1682  			if splitResources {
  1683  				// If we're a split resource section, and that section has relocation
  1684  				// symbols, then the data that it points to doesn't actually begin at
  1685  				// the virtual address listed in this current section, but rather
  1686  				// begins at the section immediately after this one. So, in order to
  1687  				// calculate the proper virtual address of the data it's pointing to,
  1688  				// we have to add the length of this section to the virtual address.
  1689  				// This works because .rsrc sections are divided into two (but not more)
  1690  				// of these sections.
  1691  				val += uint32(len(data))
  1692  			}
  1693  			binary.LittleEndian.PutUint32(p, val)
  1694  		}
  1695  		ctxt.Out.Write(data)
  1696  	}
  1697  	h.pad(ctxt.Out, uint32(size))
  1698  
  1699  	// update data directory
  1700  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
  1701  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
  1702  }
  1703  
  1704  func asmbPe(ctxt *Link) {
  1705  	t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length))
  1706  	t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
  1707  	if ctxt.LinkMode == LinkExternal {
  1708  		// some data symbols (e.g. masks) end up in the .text section, and they normally
  1709  		// expect larger alignment requirement than the default text section alignment.
  1710  		t.characteristics |= IMAGE_SCN_ALIGN_32BYTES
  1711  	}
  1712  	t.checkSegment(&Segtext)
  1713  	pefile.textSect = t
  1714  
  1715  	ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length))
  1716  	ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
  1717  	if ctxt.LinkMode == LinkExternal {
  1718  		// some data symbols (e.g. masks) end up in the .rdata section, and they normally
  1719  		// expect larger alignment requirement than the default text section alignment.
  1720  		ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
  1721  	}
  1722  	ro.checkSegment(&Segrodata)
  1723  	pefile.rdataSect = ro
  1724  
  1725  	var d *peSection
  1726  	if ctxt.LinkMode != LinkExternal {
  1727  		d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
  1728  		d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1729  		d.checkSegment(&Segdata)
  1730  		pefile.dataSect = d
  1731  	} else {
  1732  		d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
  1733  		d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1734  		d.checkSegment(&Segdata)
  1735  		pefile.dataSect = d
  1736  
  1737  		b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
  1738  		b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1739  		b.pointerToRawData = 0
  1740  		pefile.bssSect = b
  1741  	}
  1742  
  1743  	pefile.addSEH(ctxt)
  1744  	pefile.addDWARF()
  1745  
  1746  	if ctxt.LinkMode == LinkExternal {
  1747  		pefile.ctorsSect = pefile.addInitArray(ctxt)
  1748  	}
  1749  
  1750  	ctxt.Out.SeekSet(int64(pefile.nextFileOffset))
  1751  	if ctxt.LinkMode != LinkExternal {
  1752  		addimports(ctxt, d)
  1753  		addexports(ctxt)
  1754  		addPEBaseReloc(ctxt)
  1755  	}
  1756  	pefile.writeSymbolTableAndStringTable(ctxt)
  1757  	addpersrc(ctxt)
  1758  	if ctxt.LinkMode == LinkExternal {
  1759  		pefile.emitRelocations(ctxt)
  1760  	}
  1761  
  1762  	pewrite(ctxt)
  1763  }
  1764  

View as plain text