Home | History | Annotate | Download | only in ld
      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 }
   1260