github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/cmd/link/internal/ld/pe.go (about)

     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  package ld
     6  
     7  import (
     8  	"cmd/internal/obj"
     9  	"cmd/internal/sys"
    10  	"encoding/binary"
    11  	"fmt"
    12  	"os"
    13  	"sort"
    14  	"strconv"
    15  	"strings"
    16  )
    17  
    18  type IMAGE_FILE_HEADER struct {
    19  	Machine              uint16
    20  	NumberOfSections     uint16
    21  	TimeDateStamp        uint32
    22  	PointerToSymbolTable uint32
    23  	NumberOfSymbols      uint32
    24  	SizeOfOptionalHeader uint16
    25  	Characteristics      uint16
    26  }
    27  
    28  type IMAGE_DATA_DIRECTORY struct {
    29  	VirtualAddress uint32
    30  	Size           uint32
    31  }
    32  
    33  type IMAGE_OPTIONAL_HEADER struct {
    34  	Magic                       uint16
    35  	MajorLinkerVersion          uint8
    36  	MinorLinkerVersion          uint8
    37  	SizeOfCode                  uint32
    38  	SizeOfInitializedData       uint32
    39  	SizeOfUninitializedData     uint32
    40  	AddressOfEntryPoint         uint32
    41  	BaseOfCode                  uint32
    42  	BaseOfData                  uint32
    43  	ImageBase                   uint32
    44  	SectionAlignment            uint32
    45  	FileAlignment               uint32
    46  	MajorOperatingSystemVersion uint16
    47  	MinorOperatingSystemVersion uint16
    48  	MajorImageVersion           uint16
    49  	MinorImageVersion           uint16
    50  	MajorSubsystemVersion       uint16
    51  	MinorSubsystemVersion       uint16
    52  	Win32VersionValue           uint32
    53  	SizeOfImage                 uint32
    54  	SizeOfHeaders               uint32
    55  	CheckSum                    uint32
    56  	Subsystem                   uint16
    57  	DllCharacteristics          uint16
    58  	SizeOfStackReserve          uint32
    59  	SizeOfStackCommit           uint32
    60  	SizeOfHeapReserve           uint32
    61  	SizeOfHeapCommit            uint32
    62  	LoaderFlags                 uint32
    63  	NumberOfRvaAndSizes         uint32
    64  	DataDirectory               [16]IMAGE_DATA_DIRECTORY
    65  }
    66  
    67  type IMAGE_SECTION_HEADER struct {
    68  	Name                 [8]uint8
    69  	VirtualSize          uint32
    70  	VirtualAddress       uint32
    71  	SizeOfRawData        uint32
    72  	PointerToRawData     uint32
    73  	PointerToRelocations uint32
    74  	PointerToLineNumbers uint32
    75  	NumberOfRelocations  uint16
    76  	NumberOfLineNumbers  uint16
    77  	Characteristics      uint32
    78  }
    79  
    80  type IMAGE_IMPORT_DESCRIPTOR struct {
    81  	OriginalFirstThunk uint32
    82  	TimeDateStamp      uint32
    83  	ForwarderChain     uint32
    84  	Name               uint32
    85  	FirstThunk         uint32
    86  }
    87  
    88  type IMAGE_EXPORT_DIRECTORY struct {
    89  	Characteristics       uint32
    90  	TimeDateStamp         uint32
    91  	MajorVersion          uint16
    92  	MinorVersion          uint16
    93  	Name                  uint32
    94  	Base                  uint32
    95  	NumberOfFunctions     uint32
    96  	NumberOfNames         uint32
    97  	AddressOfFunctions    uint32
    98  	AddressOfNames        uint32
    99  	AddressOfNameOrdinals uint32
   100  }
   101  
   102  const (
   103  	PEBASE = 0x00400000
   104  
   105  	// SectionAlignment must be greater than or equal to FileAlignment.
   106  	// The default is the page size for the architecture.
   107  	PESECTALIGN = 0x1000
   108  
   109  	// FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
   110  	// The default is 512. If the SectionAlignment is less than
   111  	// the architecture's page size, then FileAlignment must match SectionAlignment.
   112  	PEFILEALIGN = 2 << 8
   113  )
   114  
   115  const (
   116  	IMAGE_FILE_MACHINE_I386              = 0x14c
   117  	IMAGE_FILE_MACHINE_AMD64             = 0x8664
   118  	IMAGE_FILE_RELOCS_STRIPPED           = 0x0001
   119  	IMAGE_FILE_EXECUTABLE_IMAGE          = 0x0002
   120  	IMAGE_FILE_LINE_NUMS_STRIPPED        = 0x0004
   121  	IMAGE_FILE_LARGE_ADDRESS_AWARE       = 0x0020
   122  	IMAGE_FILE_32BIT_MACHINE             = 0x0100
   123  	IMAGE_FILE_DEBUG_STRIPPED            = 0x0200
   124  	IMAGE_SCN_CNT_CODE                   = 0x00000020
   125  	IMAGE_SCN_CNT_INITIALIZED_DATA       = 0x00000040
   126  	IMAGE_SCN_CNT_UNINITIALIZED_DATA     = 0x00000080
   127  	IMAGE_SCN_MEM_EXECUTE                = 0x20000000
   128  	IMAGE_SCN_MEM_READ                   = 0x40000000
   129  	IMAGE_SCN_MEM_WRITE                  = 0x80000000
   130  	IMAGE_SCN_MEM_DISCARDABLE            = 0x2000000
   131  	IMAGE_SCN_LNK_NRELOC_OVFL            = 0x1000000
   132  	IMAGE_SCN_ALIGN_32BYTES              = 0x600000
   133  	IMAGE_DIRECTORY_ENTRY_EXPORT         = 0
   134  	IMAGE_DIRECTORY_ENTRY_IMPORT         = 1
   135  	IMAGE_DIRECTORY_ENTRY_RESOURCE       = 2
   136  	IMAGE_DIRECTORY_ENTRY_EXCEPTION      = 3
   137  	IMAGE_DIRECTORY_ENTRY_SECURITY       = 4
   138  	IMAGE_DIRECTORY_ENTRY_BASERELOC      = 5
   139  	IMAGE_DIRECTORY_ENTRY_DEBUG          = 6
   140  	IMAGE_DIRECTORY_ENTRY_COPYRIGHT      = 7
   141  	IMAGE_DIRECTORY_ENTRY_ARCHITECTURE   = 7
   142  	IMAGE_DIRECTORY_ENTRY_GLOBALPTR      = 8
   143  	IMAGE_DIRECTORY_ENTRY_TLS            = 9
   144  	IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    = 10
   145  	IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   = 11
   146  	IMAGE_DIRECTORY_ENTRY_IAT            = 12
   147  	IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   = 13
   148  	IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14
   149  	IMAGE_SUBSYSTEM_WINDOWS_GUI          = 2
   150  	IMAGE_SUBSYSTEM_WINDOWS_CUI          = 3
   151  )
   152  
   153  // X64
   154  type PE64_IMAGE_OPTIONAL_HEADER struct {
   155  	Magic                       uint16
   156  	MajorLinkerVersion          uint8
   157  	MinorLinkerVersion          uint8
   158  	SizeOfCode                  uint32
   159  	SizeOfInitializedData       uint32
   160  	SizeOfUninitializedData     uint32
   161  	AddressOfEntryPoint         uint32
   162  	BaseOfCode                  uint32
   163  	ImageBase                   uint64
   164  	SectionAlignment            uint32
   165  	FileAlignment               uint32
   166  	MajorOperatingSystemVersion uint16
   167  	MinorOperatingSystemVersion uint16
   168  	MajorImageVersion           uint16
   169  	MinorImageVersion           uint16
   170  	MajorSubsystemVersion       uint16
   171  	MinorSubsystemVersion       uint16
   172  	Win32VersionValue           uint32
   173  	SizeOfImage                 uint32
   174  	SizeOfHeaders               uint32
   175  	CheckSum                    uint32
   176  	Subsystem                   uint16
   177  	DllCharacteristics          uint16
   178  	SizeOfStackReserve          uint64
   179  	SizeOfStackCommit           uint64
   180  	SizeOfHeapReserve           uint64
   181  	SizeOfHeapCommit            uint64
   182  	LoaderFlags                 uint32
   183  	NumberOfRvaAndSizes         uint32
   184  	DataDirectory               [16]IMAGE_DATA_DIRECTORY
   185  }
   186  
   187  // Copyright 2009 The Go Authors. All rights reserved.
   188  // Use of this source code is governed by a BSD-style
   189  // license that can be found in the LICENSE file.
   190  
   191  // PE (Portable Executable) file writing
   192  // http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
   193  
   194  // DOS stub that prints out
   195  // "This program cannot be run in DOS mode."
   196  var dosstub = []uint8{
   197  	0x4d,
   198  	0x5a,
   199  	0x90,
   200  	0x00,
   201  	0x03,
   202  	0x00,
   203  	0x04,
   204  	0x00,
   205  	0x00,
   206  	0x00,
   207  	0x00,
   208  	0x00,
   209  	0xff,
   210  	0xff,
   211  	0x00,
   212  	0x00,
   213  	0x8b,
   214  	0x00,
   215  	0x00,
   216  	0x00,
   217  	0x00,
   218  	0x00,
   219  	0x00,
   220  	0x00,
   221  	0x40,
   222  	0x00,
   223  	0x00,
   224  	0x00,
   225  	0x00,
   226  	0x00,
   227  	0x00,
   228  	0x00,
   229  	0x00,
   230  	0x00,
   231  	0x00,
   232  	0x00,
   233  	0x00,
   234  	0x00,
   235  	0x00,
   236  	0x00,
   237  	0x00,
   238  	0x00,
   239  	0x00,
   240  	0x00,
   241  	0x00,
   242  	0x00,
   243  	0x00,
   244  	0x00,
   245  	0x00,
   246  	0x00,
   247  	0x00,
   248  	0x00,
   249  	0x00,
   250  	0x00,
   251  	0x00,
   252  	0x00,
   253  	0x00,
   254  	0x00,
   255  	0x00,
   256  	0x00,
   257  	0x80,
   258  	0x00,
   259  	0x00,
   260  	0x00,
   261  	0x0e,
   262  	0x1f,
   263  	0xba,
   264  	0x0e,
   265  	0x00,
   266  	0xb4,
   267  	0x09,
   268  	0xcd,
   269  	0x21,
   270  	0xb8,
   271  	0x01,
   272  	0x4c,
   273  	0xcd,
   274  	0x21,
   275  	0x54,
   276  	0x68,
   277  	0x69,
   278  	0x73,
   279  	0x20,
   280  	0x70,
   281  	0x72,
   282  	0x6f,
   283  	0x67,
   284  	0x72,
   285  	0x61,
   286  	0x6d,
   287  	0x20,
   288  	0x63,
   289  	0x61,
   290  	0x6e,
   291  	0x6e,
   292  	0x6f,
   293  	0x74,
   294  	0x20,
   295  	0x62,
   296  	0x65,
   297  	0x20,
   298  	0x72,
   299  	0x75,
   300  	0x6e,
   301  	0x20,
   302  	0x69,
   303  	0x6e,
   304  	0x20,
   305  	0x44,
   306  	0x4f,
   307  	0x53,
   308  	0x20,
   309  	0x6d,
   310  	0x6f,
   311  	0x64,
   312  	0x65,
   313  	0x2e,
   314  	0x0d,
   315  	0x0d,
   316  	0x0a,
   317  	0x24,
   318  	0x00,
   319  	0x00,
   320  	0x00,
   321  	0x00,
   322  	0x00,
   323  	0x00,
   324  	0x00,
   325  }
   326  
   327  var rsrcsym *LSym
   328  
   329  var strtbl []byte
   330  
   331  var PESECTHEADR int32
   332  
   333  var PEFILEHEADR int32
   334  
   335  var pe64 int
   336  
   337  var pensect int
   338  
   339  var nextsectoff int
   340  
   341  var nextfileoff int
   342  
   343  var textsect int
   344  
   345  var datasect int
   346  
   347  var bsssect int
   348  
   349  var fh IMAGE_FILE_HEADER
   350  
   351  var oh IMAGE_OPTIONAL_HEADER
   352  
   353  var oh64 PE64_IMAGE_OPTIONAL_HEADER
   354  
   355  var sh [16]IMAGE_SECTION_HEADER
   356  
   357  var dd []IMAGE_DATA_DIRECTORY
   358  
   359  type Imp struct {
   360  	s       *LSym
   361  	off     uint64
   362  	next    *Imp
   363  	argsize int
   364  }
   365  
   366  type Dll struct {
   367  	name     string
   368  	nameoff  uint64
   369  	thunkoff uint64
   370  	ms       *Imp
   371  	next     *Dll
   372  }
   373  
   374  var dr *Dll
   375  
   376  var dexport [1024]*LSym
   377  
   378  var nexport int
   379  
   380  func addpesection(name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
   381  	if pensect == 16 {
   382  		Diag("too many sections")
   383  		errorexit()
   384  	}
   385  
   386  	h := &sh[pensect]
   387  	pensect++
   388  	copy(h.Name[:], name)
   389  	h.VirtualSize = uint32(sectsize)
   390  	h.VirtualAddress = uint32(nextsectoff)
   391  	nextsectoff = int(Rnd(int64(nextsectoff)+int64(sectsize), PESECTALIGN))
   392  	h.PointerToRawData = uint32(nextfileoff)
   393  	if filesize > 0 {
   394  		h.SizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN))
   395  		nextfileoff += int(h.SizeOfRawData)
   396  	}
   397  
   398  	return h
   399  }
   400  
   401  func chksectoff(h *IMAGE_SECTION_HEADER, off int64) {
   402  	if off != int64(h.PointerToRawData) {
   403  		Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(off))
   404  		errorexit()
   405  	}
   406  }
   407  
   408  func chksectseg(h *IMAGE_SECTION_HEADER, s *Segment) {
   409  	if s.Vaddr-PEBASE != uint64(h.VirtualAddress) {
   410  		Diag("%s.VirtualAddress = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.VirtualAddress)), uint64(int64(s.Vaddr-PEBASE)))
   411  		errorexit()
   412  	}
   413  
   414  	if s.Fileoff != uint64(h.PointerToRawData) {
   415  		Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(int64(s.Fileoff)))
   416  		errorexit()
   417  	}
   418  }
   419  
   420  func Peinit() {
   421  	var l int
   422  
   423  	switch SysArch.Family {
   424  	// 64-bit architectures
   425  	case sys.AMD64:
   426  		pe64 = 1
   427  
   428  		l = binary.Size(&oh64)
   429  		dd = oh64.DataDirectory[:]
   430  
   431  	// 32-bit architectures
   432  	default:
   433  		l = binary.Size(&oh)
   434  
   435  		dd = oh.DataDirectory[:]
   436  	}
   437  
   438  	PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
   439  	PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
   440  	nextsectoff = int(PESECTHEADR)
   441  	nextfileoff = int(PEFILEHEADR)
   442  
   443  	// some mingw libs depend on this symbol, for example, FindPESectionByName
   444  	xdefine("__image_base__", obj.SDATA, PEBASE)
   445  
   446  	xdefine("_image_base__", obj.SDATA, PEBASE)
   447  }
   448  
   449  func pewrite() {
   450  	Cseek(0)
   451  	if Linkmode != LinkExternal {
   452  		Cwrite(dosstub)
   453  		strnput("PE", 4)
   454  	}
   455  
   456  	binary.Write(&coutbuf, binary.LittleEndian, &fh)
   457  
   458  	if pe64 != 0 {
   459  		binary.Write(&coutbuf, binary.LittleEndian, &oh64)
   460  	} else {
   461  		binary.Write(&coutbuf, binary.LittleEndian, &oh)
   462  	}
   463  	binary.Write(&coutbuf, binary.LittleEndian, sh[:pensect])
   464  }
   465  
   466  func strput(s string) {
   467  	coutbuf.WriteString(s)
   468  	Cput(0)
   469  	// string must be padded to even size
   470  	if (len(s)+1)%2 != 0 {
   471  		Cput(0)
   472  	}
   473  }
   474  
   475  func initdynimport() *Dll {
   476  	var d *Dll
   477  
   478  	dr = nil
   479  	var m *Imp
   480  	for _, s := range Ctxt.Allsym {
   481  		if !s.Attr.Reachable() || s.Type != obj.SDYNIMPORT {
   482  			continue
   483  		}
   484  		for d = dr; d != nil; d = d.next {
   485  			if d.name == s.Dynimplib {
   486  				m = new(Imp)
   487  				break
   488  			}
   489  		}
   490  
   491  		if d == nil {
   492  			d = new(Dll)
   493  			d.name = s.Dynimplib
   494  			d.next = dr
   495  			dr = d
   496  			m = new(Imp)
   497  		}
   498  
   499  		// Because external link requires properly stdcall decorated name,
   500  		// all external symbols in runtime use %n to denote that the number
   501  		// of uinptrs this function consumes. Store the argsize and discard
   502  		// the %n suffix if any.
   503  		m.argsize = -1
   504  		if i := strings.IndexByte(s.Extname, '%'); i >= 0 {
   505  			var err error
   506  			m.argsize, err = strconv.Atoi(s.Extname[i+1:])
   507  			if err != nil {
   508  				Diag("failed to parse stdcall decoration: %v", err)
   509  			}
   510  			m.argsize *= SysArch.PtrSize
   511  			s.Extname = s.Extname[:i]
   512  		}
   513  
   514  		m.s = s
   515  		m.next = d.ms
   516  		d.ms = m
   517  	}
   518  
   519  	if Linkmode == LinkExternal {
   520  		// Add real symbol name
   521  		for d := dr; d != nil; d = d.next {
   522  			for m = d.ms; m != nil; m = m.next {
   523  				m.s.Type = obj.SDATA
   524  				Symgrow(Ctxt, m.s, int64(SysArch.PtrSize))
   525  				dynName := m.s.Extname
   526  				// only windows/386 requires stdcall decoration
   527  				if SysArch.Family == sys.I386 && m.argsize >= 0 {
   528  					dynName += fmt.Sprintf("@%d", m.argsize)
   529  				}
   530  				dynSym := Linklookup(Ctxt, dynName, 0)
   531  				dynSym.Attr |= AttrReachable
   532  				dynSym.Type = obj.SHOSTOBJ
   533  				r := Addrel(m.s)
   534  				r.Sym = dynSym
   535  				r.Off = 0
   536  				r.Siz = uint8(SysArch.PtrSize)
   537  				r.Type = obj.R_ADDR
   538  			}
   539  		}
   540  	} else {
   541  		dynamic := Linklookup(Ctxt, ".windynamic", 0)
   542  		dynamic.Attr |= AttrReachable
   543  		dynamic.Type = obj.SWINDOWS
   544  		for d := dr; d != nil; d = d.next {
   545  			for m = d.ms; m != nil; m = m.next {
   546  				m.s.Type = obj.SWINDOWS | obj.SSUB
   547  				m.s.Sub = dynamic.Sub
   548  				dynamic.Sub = m.s
   549  				m.s.Value = dynamic.Size
   550  				dynamic.Size += int64(SysArch.PtrSize)
   551  			}
   552  
   553  			dynamic.Size += int64(SysArch.PtrSize)
   554  		}
   555  	}
   556  
   557  	return dr
   558  }
   559  
   560  // peimporteddlls returns the gcc command line argument to link all imported
   561  // DLLs.
   562  func peimporteddlls() []string {
   563  	var dlls []string
   564  
   565  	for d := dr; d != nil; d = d.next {
   566  		dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
   567  	}
   568  
   569  	return dlls
   570  }
   571  
   572  func addimports(datsect *IMAGE_SECTION_HEADER) {
   573  	startoff := Cpos()
   574  	dynamic := Linklookup(Ctxt, ".windynamic", 0)
   575  
   576  	// skip import descriptor table (will write it later)
   577  	n := uint64(0)
   578  
   579  	for d := dr; d != nil; d = d.next {
   580  		n++
   581  	}
   582  	Cseek(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
   583  
   584  	// write dll names
   585  	for d := dr; d != nil; d = d.next {
   586  		d.nameoff = uint64(Cpos()) - uint64(startoff)
   587  		strput(d.name)
   588  	}
   589  
   590  	// write function names
   591  	var m *Imp
   592  	for d := dr; d != nil; d = d.next {
   593  		for m = d.ms; m != nil; m = m.next {
   594  			m.off = uint64(nextsectoff) + uint64(Cpos()) - uint64(startoff)
   595  			Wputl(0) // hint
   596  			strput(m.s.Extname)
   597  		}
   598  	}
   599  
   600  	// write OriginalFirstThunks
   601  	oftbase := uint64(Cpos()) - uint64(startoff)
   602  
   603  	n = uint64(Cpos())
   604  	for d := dr; d != nil; d = d.next {
   605  		d.thunkoff = uint64(Cpos()) - n
   606  		for m = d.ms; m != nil; m = m.next {
   607  			if pe64 != 0 {
   608  				Vputl(m.off)
   609  			} else {
   610  				Lputl(uint32(m.off))
   611  			}
   612  		}
   613  
   614  		if pe64 != 0 {
   615  			Vputl(0)
   616  		} else {
   617  			Lputl(0)
   618  		}
   619  	}
   620  
   621  	// add pe section and pad it at the end
   622  	n = uint64(Cpos()) - uint64(startoff)
   623  
   624  	isect := addpesection(".idata", int(n), int(n))
   625  	isect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
   626  	chksectoff(isect, startoff)
   627  	strnput("", int(uint64(isect.SizeOfRawData)-n))
   628  	endoff := Cpos()
   629  
   630  	// write FirstThunks (allocated in .data section)
   631  	ftbase := uint64(dynamic.Value) - uint64(datsect.VirtualAddress) - PEBASE
   632  
   633  	Cseek(int64(uint64(datsect.PointerToRawData) + ftbase))
   634  	for d := dr; d != nil; d = d.next {
   635  		for m = d.ms; m != nil; m = m.next {
   636  			if pe64 != 0 {
   637  				Vputl(m.off)
   638  			} else {
   639  				Lputl(uint32(m.off))
   640  			}
   641  		}
   642  
   643  		if pe64 != 0 {
   644  			Vputl(0)
   645  		} else {
   646  			Lputl(0)
   647  		}
   648  	}
   649  
   650  	// finally write import descriptor table
   651  	Cseek(startoff)
   652  
   653  	for d := dr; d != nil; d = d.next {
   654  		Lputl(uint32(uint64(isect.VirtualAddress) + oftbase + d.thunkoff))
   655  		Lputl(0)
   656  		Lputl(0)
   657  		Lputl(uint32(uint64(isect.VirtualAddress) + d.nameoff))
   658  		Lputl(uint32(uint64(datsect.VirtualAddress) + ftbase + d.thunkoff))
   659  	}
   660  
   661  	Lputl(0) //end
   662  	Lputl(0)
   663  	Lputl(0)
   664  	Lputl(0)
   665  	Lputl(0)
   666  
   667  	// update data directory
   668  	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.VirtualAddress
   669  
   670  	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.VirtualSize
   671  	dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE)
   672  	dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size)
   673  
   674  	Cseek(endoff)
   675  }
   676  
   677  type byExtname []*LSym
   678  
   679  func (s byExtname) Len() int           { return len(s) }
   680  func (s byExtname) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   681  func (s byExtname) Less(i, j int) bool { return s[i].Extname < s[j].Extname }
   682  
   683  func initdynexport() {
   684  	nexport = 0
   685  	for _, s := range Ctxt.Allsym {
   686  		if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() {
   687  			continue
   688  		}
   689  		if nexport+1 > len(dexport) {
   690  			Diag("pe dynexport table is full")
   691  			errorexit()
   692  		}
   693  
   694  		dexport[nexport] = s
   695  		nexport++
   696  	}
   697  
   698  	sort.Sort(byExtname(dexport[:nexport]))
   699  }
   700  
   701  func addexports() {
   702  	var e IMAGE_EXPORT_DIRECTORY
   703  
   704  	size := binary.Size(&e) + 10*nexport + len(outfile) + 1
   705  	for i := 0; i < nexport; i++ {
   706  		size += len(dexport[i].Extname) + 1
   707  	}
   708  
   709  	if nexport == 0 {
   710  		return
   711  	}
   712  
   713  	sect := addpesection(".edata", size, size)
   714  	sect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
   715  	chksectoff(sect, Cpos())
   716  	va := int(sect.VirtualAddress)
   717  	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
   718  	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.VirtualSize
   719  
   720  	va_name := va + binary.Size(&e) + nexport*4
   721  	va_addr := va + binary.Size(&e)
   722  	va_na := va + binary.Size(&e) + nexport*8
   723  
   724  	e.Characteristics = 0
   725  	e.MajorVersion = 0
   726  	e.MinorVersion = 0
   727  	e.NumberOfFunctions = uint32(nexport)
   728  	e.NumberOfNames = uint32(nexport)
   729  	e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
   730  	e.Base = 1
   731  	e.AddressOfFunctions = uint32(va_addr)
   732  	e.AddressOfNames = uint32(va_name)
   733  	e.AddressOfNameOrdinals = uint32(va_na)
   734  
   735  	// put IMAGE_EXPORT_DIRECTORY
   736  	binary.Write(&coutbuf, binary.LittleEndian, &e)
   737  
   738  	// put EXPORT Address Table
   739  	for i := 0; i < nexport; i++ {
   740  		Lputl(uint32(dexport[i].Value - PEBASE))
   741  	}
   742  
   743  	// put EXPORT Name Pointer Table
   744  	v := int(e.Name + uint32(len(outfile)) + 1)
   745  
   746  	for i := 0; i < nexport; i++ {
   747  		Lputl(uint32(v))
   748  		v += len(dexport[i].Extname) + 1
   749  	}
   750  
   751  	// put EXPORT Ordinal Table
   752  	for i := 0; i < nexport; i++ {
   753  		Wputl(uint16(i))
   754  	}
   755  
   756  	// put Names
   757  	strnput(outfile, len(outfile)+1)
   758  
   759  	for i := 0; i < nexport; i++ {
   760  		strnput(dexport[i].Extname, len(dexport[i].Extname)+1)
   761  	}
   762  	strnput("", int(sect.SizeOfRawData-uint32(size)))
   763  }
   764  
   765  // perelocsect relocates symbols from first in section sect, and returns
   766  // the total number of relocations emitted.
   767  func perelocsect(sect *Section, syms []*LSym) int {
   768  	// If main section has no bits, nothing to relocate.
   769  	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
   770  		return 0
   771  	}
   772  
   773  	relocs := 0
   774  
   775  	sect.Reloff = uint64(Cpos())
   776  	for i, s := range syms {
   777  		if !s.Attr.Reachable() {
   778  			continue
   779  		}
   780  		if uint64(s.Value) >= sect.Vaddr {
   781  			syms = syms[i:]
   782  			break
   783  		}
   784  	}
   785  
   786  	eaddr := int32(sect.Vaddr + sect.Length)
   787  	for _, sym := range syms {
   788  		if !sym.Attr.Reachable() {
   789  			continue
   790  		}
   791  		if sym.Value >= int64(eaddr) {
   792  			break
   793  		}
   794  		Ctxt.Cursym = sym
   795  
   796  		for ri := 0; ri < len(sym.R); ri++ {
   797  			r := &sym.R[ri]
   798  			if r.Done != 0 {
   799  				continue
   800  			}
   801  			if r.Xsym == nil {
   802  				Diag("missing xsym in relocation")
   803  				continue
   804  			}
   805  
   806  			if r.Xsym.Dynid < 0 {
   807  				Diag("reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
   808  			}
   809  			if !Thearch.PEreloc1(r, int64(uint64(sym.Value+int64(r.Off))-PEBASE)) {
   810  				Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
   811  			}
   812  
   813  			relocs++
   814  		}
   815  	}
   816  
   817  	sect.Rellen = uint64(Cpos()) - sect.Reloff
   818  
   819  	return relocs
   820  }
   821  
   822  // peemitreloc emits relocation entries for go.o in external linking.
   823  func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) {
   824  	for Cpos()&7 != 0 {
   825  		Cput(0)
   826  	}
   827  
   828  	text.PointerToRelocations = uint32(Cpos())
   829  	// first entry: extended relocs
   830  	Lputl(0) // placeholder for number of relocation + 1
   831  	Lputl(0)
   832  	Wputl(0)
   833  
   834  	n := perelocsect(Segtext.Sect, Ctxt.Textp) + 1
   835  	for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
   836  		n += perelocsect(sect, datap)
   837  	}
   838  
   839  	cpos := Cpos()
   840  	Cseek(int64(text.PointerToRelocations))
   841  	Lputl(uint32(n))
   842  	Cseek(cpos)
   843  	if n > 0x10000 {
   844  		n = 0x10000
   845  		text.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
   846  	} else {
   847  		text.PointerToRelocations += 10 // skip the extend reloc entry
   848  	}
   849  	text.NumberOfRelocations = uint16(n - 1)
   850  
   851  	data.PointerToRelocations = uint32(cpos)
   852  	// first entry: extended relocs
   853  	Lputl(0) // placeholder for number of relocation + 1
   854  	Lputl(0)
   855  	Wputl(0)
   856  
   857  	n = 1
   858  	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
   859  		n += perelocsect(sect, datap)
   860  	}
   861  
   862  	cpos = Cpos()
   863  	Cseek(int64(data.PointerToRelocations))
   864  	Lputl(uint32(n))
   865  	Cseek(cpos)
   866  	if n > 0x10000 {
   867  		n = 0x10000
   868  		data.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
   869  	} else {
   870  		data.PointerToRelocations += 10 // skip the extend reloc entry
   871  	}
   872  	data.NumberOfRelocations = uint16(n - 1)
   873  
   874  	dottext := Linklookup(Ctxt, ".text", 0)
   875  	ctors.NumberOfRelocations = 1
   876  	ctors.PointerToRelocations = uint32(Cpos())
   877  	sectoff := ctors.VirtualAddress
   878  	Lputl(sectoff)
   879  	Lputl(uint32(dottext.Dynid))
   880  	switch obj.Getgoarch() {
   881  	default:
   882  		fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch())
   883  		os.Exit(2)
   884  	case "386":
   885  		Wputl(IMAGE_REL_I386_DIR32)
   886  	case "amd64":
   887  		Wputl(IMAGE_REL_AMD64_ADDR64)
   888  	}
   889  }
   890  
   891  func dope() {
   892  	/* relocation table */
   893  	rel := Linklookup(Ctxt, ".rel", 0)
   894  
   895  	rel.Attr |= AttrReachable
   896  	rel.Type = obj.SELFROSECT
   897  
   898  	initdynimport()
   899  	initdynexport()
   900  }
   901  
   902  func strtbladd(name string) int {
   903  	off := len(strtbl) + 4 // offset includes 4-byte length at beginning of table
   904  	strtbl = append(strtbl, name...)
   905  	strtbl = append(strtbl, 0)
   906  	return off
   907  }
   908  
   909  /*
   910   * For more than 8 characters section names, name contains a slash (/) that is
   911   * followed by an ASCII representation of a decimal number that is an offset into
   912   * the string table.
   913   * reference: pecoff_v8.docx Page 24.
   914   * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
   915   */
   916  func newPEDWARFSection(name string, size int64) *IMAGE_SECTION_HEADER {
   917  	if size == 0 {
   918  		return nil
   919  	}
   920  
   921  	off := strtbladd(name)
   922  	s := fmt.Sprintf("/%d", off)
   923  	h := addpesection(s, int(size), int(size))
   924  	h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
   925  
   926  	return h
   927  }
   928  
   929  // writePESymTableRecords writes all COFF symbol table records.
   930  // It returns number of records written.
   931  func writePESymTableRecords() int {
   932  	var symcnt int
   933  
   934  	put := func(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
   935  		if s == nil {
   936  			return
   937  		}
   938  		if s.Sect == nil && type_ != 'U' {
   939  			return
   940  		}
   941  		switch type_ {
   942  		default:
   943  			return
   944  		case 'D', 'B', 'T', 'U':
   945  		}
   946  
   947  		// only windows/386 requires underscore prefix on external symbols
   948  		if SysArch.Family == sys.I386 &&
   949  			Linkmode == LinkExternal &&
   950  			(s.Type != obj.SDYNIMPORT || s.Attr.CgoExport()) &&
   951  			s.Name == s.Extname &&
   952  			s.Name != "_main" {
   953  			s.Name = "_" + s.Name
   954  		}
   955  
   956  		var typ uint16
   957  		var sect int
   958  		var value int64
   959  		// Note: although address of runtime.edata (type SDATA) is at the start of .bss section
   960  		// it still belongs to the .data section, not the .bss section.
   961  		if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != obj.SDATA && Linkmode == LinkExternal {
   962  			value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen)
   963  			sect = bsssect
   964  		} else if uint64(s.Value) >= Segdata.Vaddr {
   965  			value = int64(uint64(s.Value) - Segdata.Vaddr)
   966  			sect = datasect
   967  		} else if uint64(s.Value) >= Segtext.Vaddr {
   968  			value = int64(uint64(s.Value) - Segtext.Vaddr)
   969  			sect = textsect
   970  		} else if type_ == 'U' {
   971  			typ = IMAGE_SYM_DTYPE_FUNCTION
   972  		} else {
   973  			Diag("addpesym %#x", addr)
   974  		}
   975  
   976  		// write COFF symbol table record
   977  		if len(s.Name) > 8 {
   978  			Lputl(0)
   979  			Lputl(uint32(strtbladd(s.Name)))
   980  		} else {
   981  			strnput(s.Name, 8)
   982  		}
   983  		Lputl(uint32(value))
   984  		Wputl(uint16(sect))
   985  		if typ != 0 {
   986  			Wputl(typ)
   987  		} else if Linkmode == LinkExternal {
   988  			Wputl(0)
   989  		} else {
   990  			Wputl(0x0308) // "array of structs"
   991  		}
   992  		Cput(2) // storage class: external
   993  		Cput(0) // no aux entries
   994  
   995  		s.Dynid = int32(symcnt)
   996  
   997  		symcnt++
   998  	}
   999  
  1000  	if Linkmode == LinkExternal {
  1001  		for d := dr; d != nil; d = d.next {
  1002  			for m := d.ms; m != nil; m = m.next {
  1003  				s := m.s.R[0].Xsym
  1004  				put(s, s.Name, 'U', 0, int64(SysArch.PtrSize), 0, nil)
  1005  			}
  1006  		}
  1007  
  1008  		s := Linklookup(Ctxt, ".text", 0)
  1009  		if s.Type == obj.STEXT {
  1010  			put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
  1011  		}
  1012  	}
  1013  
  1014  	genasmsym(put)
  1015  
  1016  	return symcnt
  1017  }
  1018  
  1019  func addpesymtable() {
  1020  	symtabStartPos := Cpos()
  1021  
  1022  	// write COFF symbol table
  1023  	var symcnt int
  1024  	if Debug['s'] == 0 || Linkmode == LinkExternal {
  1025  		symcnt = writePESymTableRecords()
  1026  	}
  1027  
  1028  	// update COFF file header and section table
  1029  	size := len(strtbl) + 4 + 18*symcnt
  1030  	var h *IMAGE_SECTION_HEADER
  1031  	if Linkmode != LinkExternal {
  1032  		// We do not really need .symtab for go.o, and if we have one, ld
  1033  		// will also include it in the exe, and that will confuse windows.
  1034  		h = addpesection(".symtab", size, size)
  1035  		h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
  1036  		chksectoff(h, symtabStartPos)
  1037  	}
  1038  	fh.PointerToSymbolTable = uint32(symtabStartPos)
  1039  	fh.NumberOfSymbols = uint32(symcnt)
  1040  
  1041  	// write COFF string table
  1042  	Lputl(uint32(len(strtbl)) + 4)
  1043  	for i := 0; i < len(strtbl); i++ {
  1044  		Cput(strtbl[i])
  1045  	}
  1046  	if Linkmode != LinkExternal {
  1047  		strnput("", int(h.SizeOfRawData-uint32(size)))
  1048  	}
  1049  }
  1050  
  1051  func setpersrc(sym *LSym) {
  1052  	if rsrcsym != nil {
  1053  		Diag("too many .rsrc sections")
  1054  	}
  1055  
  1056  	rsrcsym = sym
  1057  }
  1058  
  1059  func addpersrc() {
  1060  	if rsrcsym == nil {
  1061  		return
  1062  	}
  1063  
  1064  	h := addpesection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
  1065  	h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
  1066  	chksectoff(h, Cpos())
  1067  
  1068  	// relocation
  1069  	var p []byte
  1070  	var r *Reloc
  1071  	var val uint32
  1072  	for ri := 0; ri < len(rsrcsym.R); ri++ {
  1073  		r = &rsrcsym.R[ri]
  1074  		p = rsrcsym.P[r.Off:]
  1075  		val = uint32(int64(h.VirtualAddress) + r.Add)
  1076  
  1077  		// 32-bit little-endian
  1078  		p[0] = byte(val)
  1079  
  1080  		p[1] = byte(val >> 8)
  1081  		p[2] = byte(val >> 16)
  1082  		p[3] = byte(val >> 24)
  1083  	}
  1084  
  1085  	Cwrite(rsrcsym.P)
  1086  	strnput("", int(int64(h.SizeOfRawData)-rsrcsym.Size))
  1087  
  1088  	// update data directory
  1089  	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.VirtualAddress
  1090  
  1091  	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.VirtualSize
  1092  }
  1093  
  1094  func addinitarray() (c *IMAGE_SECTION_HEADER) {
  1095  	// The size below was determined by the specification for array relocations,
  1096  	// and by observing what GCC writes here. If the initarray section grows to
  1097  	// contain more than one constructor entry, the size will need to be 8 * constructor_count.
  1098  	// However, the entire Go runtime is initialized from just one function, so it is unlikely
  1099  	// that this will need to grow in the future.
  1100  	var size int
  1101  	switch obj.Getgoarch() {
  1102  	default:
  1103  		fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch())
  1104  		os.Exit(2)
  1105  	case "386":
  1106  		size = 4
  1107  	case "amd64":
  1108  		size = 8
  1109  	}
  1110  
  1111  	c = addpesection(".ctors", size, size)
  1112  	c.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
  1113  	c.SizeOfRawData = uint32(size)
  1114  
  1115  	Cseek(int64(c.PointerToRawData))
  1116  	chksectoff(c, Cpos())
  1117  	init_entry := Linklookup(Ctxt, INITENTRY, 0)
  1118  	addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr
  1119  
  1120  	switch obj.Getgoarch() {
  1121  	case "386":
  1122  		Lputl(uint32(addr))
  1123  	case "amd64":
  1124  		Vputl(addr)
  1125  	}
  1126  
  1127  	return c
  1128  }
  1129  
  1130  func Asmbpe() {
  1131  	switch SysArch.Family {
  1132  	default:
  1133  		Exitf("unknown PE architecture: %v", SysArch.Family)
  1134  	case sys.AMD64:
  1135  		fh.Machine = IMAGE_FILE_MACHINE_AMD64
  1136  	case sys.I386:
  1137  		fh.Machine = IMAGE_FILE_MACHINE_I386
  1138  	}
  1139  
  1140  	t := addpesection(".text", int(Segtext.Length), int(Segtext.Length))
  1141  	t.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
  1142  	if Linkmode == LinkExternal {
  1143  		// some data symbols (e.g. masks) end up in the .text section, and they normally
  1144  		// expect larger alignment requirement than the default text section alignment.
  1145  		t.Characteristics |= IMAGE_SCN_ALIGN_32BYTES
  1146  	}
  1147  	chksectseg(t, &Segtext)
  1148  	textsect = pensect
  1149  
  1150  	var d *IMAGE_SECTION_HEADER
  1151  	var c *IMAGE_SECTION_HEADER
  1152  	if Linkmode != LinkExternal {
  1153  		d = addpesection(".data", int(Segdata.Length), int(Segdata.Filelen))
  1154  		d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1155  		chksectseg(d, &Segdata)
  1156  		datasect = pensect
  1157  	} else {
  1158  		d = addpesection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
  1159  		d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1160  		chksectseg(d, &Segdata)
  1161  		datasect = pensect
  1162  
  1163  		b := addpesection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
  1164  		b.Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1165  		b.PointerToRawData = 0
  1166  		bsssect = pensect
  1167  
  1168  		c = addinitarray()
  1169  	}
  1170  
  1171  	if Debug['s'] == 0 {
  1172  		dwarfaddpeheaders()
  1173  	}
  1174  
  1175  	Cseek(int64(nextfileoff))
  1176  	if Linkmode != LinkExternal {
  1177  		addimports(d)
  1178  		addexports()
  1179  	}
  1180  	addpesymtable()
  1181  	addpersrc()
  1182  	if Linkmode == LinkExternal {
  1183  		peemitreloc(t, d, c)
  1184  	}
  1185  
  1186  	fh.NumberOfSections = uint16(pensect)
  1187  
  1188  	// Being able to produce identical output for identical input is
  1189  	// much more beneficial than having build timestamp in the header.
  1190  	fh.TimeDateStamp = 0
  1191  
  1192  	if Linkmode == LinkExternal {
  1193  		fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED
  1194  	} else {
  1195  		fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED
  1196  	}
  1197  	if pe64 != 0 {
  1198  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
  1199  		fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE
  1200  		oh64.Magic = 0x20b // PE32+
  1201  	} else {
  1202  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
  1203  		fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE
  1204  		oh.Magic = 0x10b // PE32
  1205  		oh.BaseOfData = d.VirtualAddress
  1206  	}
  1207  
  1208  	// Fill out both oh64 and oh. We only use one. Oh well.
  1209  	oh64.MajorLinkerVersion = 3
  1210  
  1211  	oh.MajorLinkerVersion = 3
  1212  	oh64.MinorLinkerVersion = 0
  1213  	oh.MinorLinkerVersion = 0
  1214  	oh64.SizeOfCode = t.SizeOfRawData
  1215  	oh.SizeOfCode = t.SizeOfRawData
  1216  	oh64.SizeOfInitializedData = d.SizeOfRawData
  1217  	oh.SizeOfInitializedData = d.SizeOfRawData
  1218  	oh64.SizeOfUninitializedData = 0
  1219  	oh.SizeOfUninitializedData = 0
  1220  	if Linkmode != LinkExternal {
  1221  		oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
  1222  		oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
  1223  	}
  1224  	oh64.BaseOfCode = t.VirtualAddress
  1225  	oh.BaseOfCode = t.VirtualAddress
  1226  	oh64.ImageBase = PEBASE
  1227  	oh.ImageBase = PEBASE
  1228  	oh64.SectionAlignment = PESECTALIGN
  1229  	oh.SectionAlignment = PESECTALIGN
  1230  	oh64.FileAlignment = PEFILEALIGN
  1231  	oh.FileAlignment = PEFILEALIGN
  1232  	oh64.MajorOperatingSystemVersion = 4
  1233  	oh.MajorOperatingSystemVersion = 4
  1234  	oh64.MinorOperatingSystemVersion = 0
  1235  	oh.MinorOperatingSystemVersion = 0
  1236  	oh64.MajorImageVersion = 1
  1237  	oh.MajorImageVersion = 1
  1238  	oh64.MinorImageVersion = 0
  1239  	oh.MinorImageVersion = 0
  1240  	oh64.MajorSubsystemVersion = 4
  1241  	oh.MajorSubsystemVersion = 4
  1242  	oh64.MinorSubsystemVersion = 0
  1243  	oh.MinorSubsystemVersion = 0
  1244  	oh64.SizeOfImage = uint32(nextsectoff)
  1245  	oh.SizeOfImage = uint32(nextsectoff)
  1246  	oh64.SizeOfHeaders = uint32(PEFILEHEADR)
  1247  	oh.SizeOfHeaders = uint32(PEFILEHEADR)
  1248  	if headstring == "windowsgui" {
  1249  		oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
  1250  		oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
  1251  	} else {
  1252  		oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
  1253  		oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
  1254  	}
  1255  
  1256  	// Disable stack growth as we don't want Windows to
  1257  	// fiddle with the thread stack limits, which we set
  1258  	// ourselves to circumvent the stack checks in the
  1259  	// Windows exception dispatcher.
  1260  	// Commit size must be strictly less than reserve
  1261  	// size otherwise reserve will be rounded up to a
  1262  	// larger size, as verified with VMMap.
  1263  
  1264  	// Go code would be OK with 64k stacks, but we need larger stacks for cgo.
  1265  	//
  1266  	// The default stack reserve size affects only the main
  1267  	// thread, ctrlhandler thread, and profileloop thread. For
  1268  	// these, it must be greater than the stack size assumed by
  1269  	// externalthreadhandler.
  1270  	//
  1271  	// For other threads we specify stack size in runtime explicitly
  1272  	// (runtime knows whether cgo is enabled or not).
  1273  	// For these, the reserve must match STACKSIZE in
  1274  	// runtime/cgo/gcc_windows_{386,amd64}.c and the correspondent
  1275  	// CreateThread parameter in runtime.newosproc.
  1276  	if !iscgo {
  1277  		oh64.SizeOfStackReserve = 0x00020000
  1278  		oh.SizeOfStackReserve = 0x00020000
  1279  		oh64.SizeOfStackCommit = 0x00001000
  1280  		oh.SizeOfStackCommit = 0x00001000
  1281  	} else {
  1282  		oh64.SizeOfStackReserve = 0x00200000
  1283  		oh.SizeOfStackReserve = 0x00100000
  1284  
  1285  		// account for 2 guard pages
  1286  		oh64.SizeOfStackCommit = 0x00200000 - 0x2000
  1287  
  1288  		oh.SizeOfStackCommit = 0x00100000 - 0x2000
  1289  	}
  1290  
  1291  	oh64.SizeOfHeapReserve = 0x00100000
  1292  	oh.SizeOfHeapReserve = 0x00100000
  1293  	oh64.SizeOfHeapCommit = 0x00001000
  1294  	oh.SizeOfHeapCommit = 0x00001000
  1295  	oh64.NumberOfRvaAndSizes = 16
  1296  	oh.NumberOfRvaAndSizes = 16
  1297  
  1298  	pewrite()
  1299  }