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

View as plain text