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