github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/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 pescmp []*LSym
   688  
   689  func (x pescmp) Len() int {
   690  	return len(x)
   691  }
   692  
   693  func (x pescmp) Swap(i, j int) {
   694  	x[i], x[j] = x[j], x[i]
   695  }
   696  
   697  func (x pescmp) Less(i, j int) bool {
   698  	s1 := x[i]
   699  	s2 := x[j]
   700  	return stringsCompare(s1.Extname, s2.Extname) < 0
   701  }
   702  
   703  func initdynexport() {
   704  	nexport = 0
   705  	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
   706  		if !s.Reachable || s.Cgoexport&CgoExportDynamic == 0 {
   707  			continue
   708  		}
   709  		if nexport+1 > len(dexport) {
   710  			Diag("pe dynexport table is full")
   711  			errorexit()
   712  		}
   713  
   714  		dexport[nexport] = s
   715  		nexport++
   716  	}
   717  
   718  	sort.Sort(pescmp(dexport[:nexport]))
   719  }
   720  
   721  func addexports() {
   722  	var e IMAGE_EXPORT_DIRECTORY
   723  
   724  	size := binary.Size(&e) + 10*nexport + len(outfile) + 1
   725  	for i := 0; i < nexport; i++ {
   726  		size += len(dexport[i].Extname) + 1
   727  	}
   728  
   729  	if nexport == 0 {
   730  		return
   731  	}
   732  
   733  	sect := addpesection(".edata", size, size)
   734  	sect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
   735  	chksectoff(sect, Cpos())
   736  	va := int(sect.VirtualAddress)
   737  	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
   738  	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.VirtualSize
   739  
   740  	va_name := va + binary.Size(&e) + nexport*4
   741  	va_addr := va + binary.Size(&e)
   742  	va_na := va + binary.Size(&e) + nexport*8
   743  
   744  	e.Characteristics = 0
   745  	e.MajorVersion = 0
   746  	e.MinorVersion = 0
   747  	e.NumberOfFunctions = uint32(nexport)
   748  	e.NumberOfNames = uint32(nexport)
   749  	e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
   750  	e.Base = 1
   751  	e.AddressOfFunctions = uint32(va_addr)
   752  	e.AddressOfNames = uint32(va_name)
   753  	e.AddressOfNameOrdinals = uint32(va_na)
   754  
   755  	// put IMAGE_EXPORT_DIRECTORY
   756  	binary.Write(&coutbuf, binary.LittleEndian, &e)
   757  
   758  	// put EXPORT Address Table
   759  	for i := 0; i < nexport; i++ {
   760  		Lputl(uint32(dexport[i].Value - PEBASE))
   761  	}
   762  
   763  	// put EXPORT Name Pointer Table
   764  	v := int(e.Name + uint32(len(outfile)) + 1)
   765  
   766  	for i := 0; i < nexport; i++ {
   767  		Lputl(uint32(v))
   768  		v += len(dexport[i].Extname) + 1
   769  	}
   770  
   771  	// put EXPORT Ordinal Table
   772  	for i := 0; i < nexport; i++ {
   773  		Wputl(uint16(i))
   774  	}
   775  
   776  	// put Names
   777  	strnput(outfile, len(outfile)+1)
   778  
   779  	for i := 0; i < nexport; i++ {
   780  		strnput(dexport[i].Extname, len(dexport[i].Extname)+1)
   781  	}
   782  	strnput("", int(sect.SizeOfRawData-uint32(size)))
   783  }
   784  
   785  // perelocsect relocates symbols from first in section sect, and returns
   786  // the total number of relocations emitted.
   787  func perelocsect(sect *Section, first *LSym) int {
   788  	// If main section has no bits, nothing to relocate.
   789  	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
   790  		return 0
   791  	}
   792  
   793  	relocs := 0
   794  
   795  	sect.Reloff = uint64(Cpos())
   796  	var sym *LSym
   797  	for sym = first; sym != nil; sym = sym.Next {
   798  		if !sym.Reachable {
   799  			continue
   800  		}
   801  		if uint64(sym.Value) >= sect.Vaddr {
   802  			break
   803  		}
   804  	}
   805  
   806  	eaddr := int32(sect.Vaddr + sect.Length)
   807  	var r *Reloc
   808  	var ri int
   809  	for ; sym != nil; sym = sym.Next {
   810  		if !sym.Reachable {
   811  			continue
   812  		}
   813  		if sym.Value >= int64(eaddr) {
   814  			break
   815  		}
   816  		Ctxt.Cursym = sym
   817  
   818  		for ri = 0; ri < len(sym.R); ri++ {
   819  			r = &sym.R[ri]
   820  			if r.Done != 0 {
   821  				continue
   822  			}
   823  			if r.Xsym == nil {
   824  				Diag("missing xsym in relocation")
   825  				continue
   826  			}
   827  
   828  			if r.Xsym.Dynid < 0 {
   829  				Diag("reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
   830  			}
   831  			if !Thearch.PEreloc1(r, int64(uint64(sym.Value+int64(r.Off))-PEBASE)) {
   832  				Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
   833  			}
   834  
   835  			relocs++
   836  		}
   837  	}
   838  
   839  	sect.Rellen = uint64(Cpos()) - sect.Reloff
   840  
   841  	return relocs
   842  }
   843  
   844  // peemitreloc emits relocation entries for go.o in external linking.
   845  func peemitreloc(text, data *IMAGE_SECTION_HEADER) {
   846  	for Cpos()&7 != 0 {
   847  		Cput(0)
   848  	}
   849  
   850  	text.PointerToRelocations = uint32(Cpos())
   851  	// first entry: extended relocs
   852  	Lputl(0) // placeholder for number of relocation + 1
   853  	Lputl(0)
   854  	Wputl(0)
   855  
   856  	n := perelocsect(Segtext.Sect, Ctxt.Textp) + 1
   857  	for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
   858  		n += perelocsect(sect, datap)
   859  	}
   860  
   861  	cpos := Cpos()
   862  	Cseek(int64(text.PointerToRelocations))
   863  	Lputl(uint32(n))
   864  	Cseek(cpos)
   865  	if n > 0x10000 {
   866  		n = 0x10000
   867  		text.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
   868  	} else {
   869  		text.PointerToRelocations += 10 // skip the extend reloc entry
   870  	}
   871  	text.NumberOfRelocations = uint16(n - 1)
   872  
   873  	data.PointerToRelocations = uint32(cpos)
   874  	// first entry: extended relocs
   875  	Lputl(0) // placeholder for number of relocation + 1
   876  	Lputl(0)
   877  	Wputl(0)
   878  
   879  	n = 1
   880  	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
   881  		n += perelocsect(sect, datap)
   882  	}
   883  
   884  	cpos = Cpos()
   885  	Cseek(int64(data.PointerToRelocations))
   886  	Lputl(uint32(n))
   887  	Cseek(cpos)
   888  	if n > 0x10000 {
   889  		n = 0x10000
   890  		data.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
   891  	} else {
   892  		data.PointerToRelocations += 10 // skip the extend reloc entry
   893  	}
   894  	data.NumberOfRelocations = uint16(n - 1)
   895  }
   896  
   897  func dope() {
   898  	/* relocation table */
   899  	rel := Linklookup(Ctxt, ".rel", 0)
   900  
   901  	rel.Reachable = true
   902  	rel.Type = obj.SELFROSECT
   903  
   904  	initdynimport()
   905  	initdynexport()
   906  }
   907  
   908  func strtbladd(name string) int {
   909  	off := len(strtbl) + 4 // offset includes 4-byte length at beginning of table
   910  	strtbl = append(strtbl, name...)
   911  	strtbl = append(strtbl, 0)
   912  	return off
   913  }
   914  
   915  /*
   916   * For more than 8 characters section names, name contains a slash (/) that is
   917   * followed by an ASCII representation of a decimal number that is an offset into
   918   * the string table.
   919   * reference: pecoff_v8.docx Page 24.
   920   * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
   921   */
   922  func newPEDWARFSection(name string, size int64) *IMAGE_SECTION_HEADER {
   923  	if size == 0 {
   924  		return nil
   925  	}
   926  
   927  	off := strtbladd(name)
   928  	s := fmt.Sprintf("/%d", off)
   929  	h := addpesection(s, int(size), int(size))
   930  	h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
   931  
   932  	return h
   933  }
   934  
   935  func addpesym(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
   936  	if s == nil {
   937  		return
   938  	}
   939  
   940  	if s.Sect == nil && type_ != 'U' {
   941  		return
   942  	}
   943  
   944  	switch type_ {
   945  	default:
   946  		return
   947  
   948  	case 'D', 'B', 'T', 'U':
   949  		break
   950  	}
   951  
   952  	if coffsym != nil {
   953  		// only windows/386 requires underscore prefix on external symbols
   954  		if Thearch.Thechar == '8' && Linkmode == LinkExternal && (s.Type == obj.SHOSTOBJ || s.Cgoexport != 0) && s.Name == s.Extname {
   955  			s.Name = "_" + s.Name
   956  		}
   957  		cs := &coffsym[ncoffsym]
   958  		cs.sym = s
   959  		if len(s.Name) > 8 {
   960  			cs.strtbloff = strtbladd(s.Name)
   961  		}
   962  		// Note: although address of runtime.edata (type SDATA) is at the start of .bss section
   963  		// it still belongs to the .data section, not the .bss section.
   964  		if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != obj.SDATA && Linkmode == LinkExternal {
   965  			cs.value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen)
   966  			cs.sect = bsssect
   967  		} else if uint64(s.Value) >= Segdata.Vaddr {
   968  			cs.value = int64(uint64(s.Value) - Segdata.Vaddr)
   969  			cs.sect = datasect
   970  		} else if uint64(s.Value) >= Segtext.Vaddr {
   971  			cs.value = int64(uint64(s.Value) - Segtext.Vaddr)
   972  			cs.sect = textsect
   973  		} else if type_ == 'U' {
   974  			cs.value = 0
   975  			cs.typ = IMAGE_SYM_DTYPE_FUNCTION
   976  		} else {
   977  			cs.value = 0
   978  			cs.sect = 0
   979  			Diag("addpesym %#x", addr)
   980  		}
   981  	}
   982  
   983  	s.Dynid = int32(ncoffsym)
   984  	ncoffsym++
   985  }
   986  
   987  func pegenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
   988  	if Linkmode == LinkExternal {
   989  		for d := dr; d != nil; d = d.next {
   990  			for m := d.ms; m != nil; m = m.next {
   991  				s := m.s.R[0].Xsym
   992  				put(s, s.Name, 'U', 0, int64(Thearch.Ptrsize), 0, nil)
   993  			}
   994  		}
   995  	}
   996  	genasmsym(put)
   997  }
   998  
   999  func addpesymtable() {
  1000  	if Debug['s'] == 0 || Linkmode == LinkExternal {
  1001  		ncoffsym = 0
  1002  		pegenasmsym(addpesym)
  1003  		coffsym = make([]COFFSym, ncoffsym)
  1004  		ncoffsym = 0
  1005  		pegenasmsym(addpesym)
  1006  	}
  1007  	size := len(strtbl) + 4 + 18*ncoffsym
  1008  
  1009  	var h *IMAGE_SECTION_HEADER
  1010  	if Linkmode != LinkExternal {
  1011  		// We do not really need .symtab for go.o, and if we have one, ld
  1012  		// will also include it in the exe, and that will confuse windows.
  1013  		h = addpesection(".symtab", size, size)
  1014  		h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
  1015  		chksectoff(h, Cpos())
  1016  	}
  1017  	fh.PointerToSymbolTable = uint32(Cpos())
  1018  	fh.NumberOfSymbols = uint32(ncoffsym)
  1019  
  1020  	// put COFF symbol table
  1021  	var s *COFFSym
  1022  	for i := 0; i < ncoffsym; i++ {
  1023  		s = &coffsym[i]
  1024  		if s.strtbloff == 0 {
  1025  			strnput(s.sym.Name, 8)
  1026  		} else {
  1027  			Lputl(0)
  1028  			Lputl(uint32(s.strtbloff))
  1029  		}
  1030  
  1031  		Lputl(uint32(s.value))
  1032  		Wputl(uint16(s.sect))
  1033  		if s.typ != 0 {
  1034  			Wputl(s.typ)
  1035  		} else if Linkmode == LinkExternal {
  1036  			Wputl(0)
  1037  		} else {
  1038  			Wputl(0x0308) // "array of structs"
  1039  		}
  1040  		Cput(2) // storage class: external
  1041  		Cput(0) // no aux entries
  1042  	}
  1043  
  1044  	// put COFF string table
  1045  	Lputl(uint32(len(strtbl)) + 4)
  1046  
  1047  	for i := 0; i < len(strtbl); i++ {
  1048  		Cput(uint8(strtbl[i]))
  1049  	}
  1050  	if Linkmode != LinkExternal {
  1051  		strnput("", int(h.SizeOfRawData-uint32(size)))
  1052  	}
  1053  }
  1054  
  1055  func setpersrc(sym *LSym) {
  1056  	if rsrcsym != nil {
  1057  		Diag("too many .rsrc sections")
  1058  	}
  1059  
  1060  	rsrcsym = sym
  1061  }
  1062  
  1063  func addpersrc() {
  1064  	if rsrcsym == nil {
  1065  		return
  1066  	}
  1067  
  1068  	h := addpesection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
  1069  	h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
  1070  	chksectoff(h, Cpos())
  1071  
  1072  	// relocation
  1073  	var p []byte
  1074  	var r *Reloc
  1075  	var val uint32
  1076  	for ri := 0; ri < len(rsrcsym.R); ri++ {
  1077  		r = &rsrcsym.R[ri]
  1078  		p = rsrcsym.P[r.Off:]
  1079  		val = uint32(int64(h.VirtualAddress) + r.Add)
  1080  
  1081  		// 32-bit little-endian
  1082  		p[0] = byte(val)
  1083  
  1084  		p[1] = byte(val >> 8)
  1085  		p[2] = byte(val >> 16)
  1086  		p[3] = byte(val >> 24)
  1087  	}
  1088  
  1089  	Cwrite(rsrcsym.P)
  1090  	strnput("", int(int64(h.SizeOfRawData)-rsrcsym.Size))
  1091  
  1092  	// update data directory
  1093  	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.VirtualAddress
  1094  
  1095  	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.VirtualSize
  1096  }
  1097  
  1098  func Asmbpe() {
  1099  	switch Thearch.Thechar {
  1100  	default:
  1101  		Exitf("unknown PE architecture: %v", Thearch.Thechar)
  1102  	case '6':
  1103  		fh.Machine = IMAGE_FILE_MACHINE_AMD64
  1104  	case '8':
  1105  		fh.Machine = IMAGE_FILE_MACHINE_I386
  1106  	}
  1107  
  1108  	t := addpesection(".text", int(Segtext.Length), int(Segtext.Length))
  1109  	t.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
  1110  	if Linkmode == LinkExternal {
  1111  		// some data symbols (e.g. masks) end up in the .text section, and they normally
  1112  		// expect larger alignment requirement than the default text section alignment.
  1113  		t.Characteristics |= IMAGE_SCN_ALIGN_32BYTES
  1114  	}
  1115  	chksectseg(t, &Segtext)
  1116  	textsect = pensect
  1117  
  1118  	var d *IMAGE_SECTION_HEADER
  1119  	if Linkmode != LinkExternal {
  1120  		d = addpesection(".data", int(Segdata.Length), int(Segdata.Filelen))
  1121  		d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1122  		chksectseg(d, &Segdata)
  1123  		datasect = pensect
  1124  	} else {
  1125  		d = addpesection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
  1126  		d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1127  		chksectseg(d, &Segdata)
  1128  		datasect = pensect
  1129  
  1130  		b := addpesection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
  1131  		b.Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1132  		b.PointerToRawData = 0
  1133  		bsssect = pensect
  1134  	}
  1135  
  1136  	if Debug['s'] == 0 {
  1137  		dwarfaddpeheaders()
  1138  	}
  1139  
  1140  	Cseek(int64(nextfileoff))
  1141  	if Linkmode != LinkExternal {
  1142  		addimports(d)
  1143  		addexports()
  1144  	}
  1145  	addpesymtable()
  1146  	addpersrc()
  1147  	if Linkmode == LinkExternal {
  1148  		peemitreloc(t, d)
  1149  	}
  1150  
  1151  	fh.NumberOfSections = uint16(pensect)
  1152  
  1153  	// Being able to produce identical output for identical input is
  1154  	// much more beneficial than having build timestamp in the header.
  1155  	fh.TimeDateStamp = 0
  1156  
  1157  	if Linkmode == LinkExternal {
  1158  		fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED
  1159  	} else {
  1160  		fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED
  1161  	}
  1162  	if pe64 != 0 {
  1163  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
  1164  		fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE
  1165  		oh64.Magic = 0x20b // PE32+
  1166  	} else {
  1167  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
  1168  		fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE
  1169  		oh.Magic = 0x10b // PE32
  1170  		oh.BaseOfData = d.VirtualAddress
  1171  	}
  1172  
  1173  	// Fill out both oh64 and oh. We only use one. Oh well.
  1174  	oh64.MajorLinkerVersion = 3
  1175  
  1176  	oh.MajorLinkerVersion = 3
  1177  	oh64.MinorLinkerVersion = 0
  1178  	oh.MinorLinkerVersion = 0
  1179  	oh64.SizeOfCode = t.SizeOfRawData
  1180  	oh.SizeOfCode = t.SizeOfRawData
  1181  	oh64.SizeOfInitializedData = d.SizeOfRawData
  1182  	oh.SizeOfInitializedData = d.SizeOfRawData
  1183  	oh64.SizeOfUninitializedData = 0
  1184  	oh.SizeOfUninitializedData = 0
  1185  	if Linkmode != LinkExternal {
  1186  		oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
  1187  		oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
  1188  	}
  1189  	oh64.BaseOfCode = t.VirtualAddress
  1190  	oh.BaseOfCode = t.VirtualAddress
  1191  	oh64.ImageBase = PEBASE
  1192  	oh.ImageBase = PEBASE
  1193  	oh64.SectionAlignment = PESECTALIGN
  1194  	oh.SectionAlignment = PESECTALIGN
  1195  	oh64.FileAlignment = PEFILEALIGN
  1196  	oh.FileAlignment = PEFILEALIGN
  1197  	oh64.MajorOperatingSystemVersion = 4
  1198  	oh.MajorOperatingSystemVersion = 4
  1199  	oh64.MinorOperatingSystemVersion = 0
  1200  	oh.MinorOperatingSystemVersion = 0
  1201  	oh64.MajorImageVersion = 1
  1202  	oh.MajorImageVersion = 1
  1203  	oh64.MinorImageVersion = 0
  1204  	oh.MinorImageVersion = 0
  1205  	oh64.MajorSubsystemVersion = 4
  1206  	oh.MajorSubsystemVersion = 4
  1207  	oh64.MinorSubsystemVersion = 0
  1208  	oh.MinorSubsystemVersion = 0
  1209  	oh64.SizeOfImage = uint32(nextsectoff)
  1210  	oh.SizeOfImage = uint32(nextsectoff)
  1211  	oh64.SizeOfHeaders = uint32(PEFILEHEADR)
  1212  	oh.SizeOfHeaders = uint32(PEFILEHEADR)
  1213  	if headstring == "windowsgui" {
  1214  		oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
  1215  		oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
  1216  	} else {
  1217  		oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
  1218  		oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
  1219  	}
  1220  
  1221  	// Disable stack growth as we don't want Windows to
  1222  	// fiddle with the thread stack limits, which we set
  1223  	// ourselves to circumvent the stack checks in the
  1224  	// Windows exception dispatcher.
  1225  	// Commit size must be strictly less than reserve
  1226  	// size otherwise reserve will be rounded up to a
  1227  	// larger size, as verified with VMMap.
  1228  
  1229  	// Go code would be OK with 64k stacks, but we need larger stacks for cgo.
  1230  	// That default stack reserve size affects only the main thread,
  1231  	// for other threads we specify stack size in runtime explicitly
  1232  	// (runtime knows whether cgo is enabled or not).
  1233  	// If you change stack reserve sizes here,
  1234  	// change STACKSIZE in runtime/cgo/gcc_windows_{386,amd64}.c and correspondent
  1235  	// CreateThread parameter in runtime.newosproc as well.
  1236  	if !iscgo {
  1237  		oh64.SizeOfStackReserve = 0x00020000
  1238  		oh.SizeOfStackReserve = 0x00020000
  1239  		oh64.SizeOfStackCommit = 0x00001000
  1240  		oh.SizeOfStackCommit = 0x00001000
  1241  	} else {
  1242  		oh64.SizeOfStackReserve = 0x00200000
  1243  		oh.SizeOfStackReserve = 0x00100000
  1244  
  1245  		// account for 2 guard pages
  1246  		oh64.SizeOfStackCommit = 0x00200000 - 0x2000
  1247  
  1248  		oh.SizeOfStackCommit = 0x00100000 - 0x2000
  1249  	}
  1250  
  1251  	oh64.SizeOfHeapReserve = 0x00100000
  1252  	oh.SizeOfHeapReserve = 0x00100000
  1253  	oh64.SizeOfHeapCommit = 0x00001000
  1254  	oh.SizeOfHeapCommit = 0x00001000
  1255  	oh64.NumberOfRvaAndSizes = 16
  1256  	oh.NumberOfRvaAndSizes = 16
  1257  
  1258  	pewrite()
  1259  }