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