github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/src/cmd/link/internal/ld/pe.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ld
     6  
     7  import (
     8  	"cmd/internal/obj"
     9  	"cmd/internal/sys"
    10  	"encoding/binary"
    11  	"fmt"
    12  	"os"
    13  	"sort"
    14  	"strconv"
    15  	"strings"
    16  )
    17  
    18  type IMAGE_FILE_HEADER struct {
    19  	Machine              uint16
    20  	NumberOfSections     uint16
    21  	TimeDateStamp        uint32
    22  	PointerToSymbolTable uint32
    23  	NumberOfSymbols      uint32
    24  	SizeOfOptionalHeader uint16
    25  	Characteristics      uint16
    26  }
    27  
    28  type IMAGE_DATA_DIRECTORY struct {
    29  	VirtualAddress uint32
    30  	Size           uint32
    31  }
    32  
    33  type IMAGE_OPTIONAL_HEADER struct {
    34  	Magic                       uint16
    35  	MajorLinkerVersion          uint8
    36  	MinorLinkerVersion          uint8
    37  	SizeOfCode                  uint32
    38  	SizeOfInitializedData       uint32
    39  	SizeOfUninitializedData     uint32
    40  	AddressOfEntryPoint         uint32
    41  	BaseOfCode                  uint32
    42  	BaseOfData                  uint32
    43  	ImageBase                   uint32
    44  	SectionAlignment            uint32
    45  	FileAlignment               uint32
    46  	MajorOperatingSystemVersion uint16
    47  	MinorOperatingSystemVersion uint16
    48  	MajorImageVersion           uint16
    49  	MinorImageVersion           uint16
    50  	MajorSubsystemVersion       uint16
    51  	MinorSubsystemVersion       uint16
    52  	Win32VersionValue           uint32
    53  	SizeOfImage                 uint32
    54  	SizeOfHeaders               uint32
    55  	CheckSum                    uint32
    56  	Subsystem                   uint16
    57  	DllCharacteristics          uint16
    58  	SizeOfStackReserve          uint32
    59  	SizeOfStackCommit           uint32
    60  	SizeOfHeapReserve           uint32
    61  	SizeOfHeapCommit            uint32
    62  	LoaderFlags                 uint32
    63  	NumberOfRvaAndSizes         uint32
    64  	DataDirectory               [16]IMAGE_DATA_DIRECTORY
    65  }
    66  
    67  type IMAGE_SECTION_HEADER struct {
    68  	Name                 [8]uint8
    69  	VirtualSize          uint32
    70  	VirtualAddress       uint32
    71  	SizeOfRawData        uint32
    72  	PointerToRawData     uint32
    73  	PointerToRelocations uint32
    74  	PointerToLineNumbers uint32
    75  	NumberOfRelocations  uint16
    76  	NumberOfLineNumbers  uint16
    77  	Characteristics      uint32
    78  }
    79  
    80  type IMAGE_IMPORT_DESCRIPTOR struct {
    81  	OriginalFirstThunk uint32
    82  	TimeDateStamp      uint32
    83  	ForwarderChain     uint32
    84  	Name               uint32
    85  	FirstThunk         uint32
    86  }
    87  
    88  type IMAGE_EXPORT_DIRECTORY struct {
    89  	Characteristics       uint32
    90  	TimeDateStamp         uint32
    91  	MajorVersion          uint16
    92  	MinorVersion          uint16
    93  	Name                  uint32
    94  	Base                  uint32
    95  	NumberOfFunctions     uint32
    96  	NumberOfNames         uint32
    97  	AddressOfFunctions    uint32
    98  	AddressOfNames        uint32
    99  	AddressOfNameOrdinals uint32
   100  }
   101  
   102  const (
   103  	PEBASE = 0x00400000
   104  
   105  	// SectionAlignment must be greater than or equal to FileAlignment.
   106  	// The default is the page size for the architecture.
   107  	PESECTALIGN = 0x1000
   108  
   109  	// FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
   110  	// The default is 512. If the SectionAlignment is less than
   111  	// the architecture's page size, then FileAlignment must match SectionAlignment.
   112  	PEFILEALIGN = 2 << 8
   113  )
   114  
   115  const (
   116  	IMAGE_FILE_MACHINE_I386              = 0x14c
   117  	IMAGE_FILE_MACHINE_AMD64             = 0x8664
   118  	IMAGE_FILE_RELOCS_STRIPPED           = 0x0001
   119  	IMAGE_FILE_EXECUTABLE_IMAGE          = 0x0002
   120  	IMAGE_FILE_LINE_NUMS_STRIPPED        = 0x0004
   121  	IMAGE_FILE_LARGE_ADDRESS_AWARE       = 0x0020
   122  	IMAGE_FILE_32BIT_MACHINE             = 0x0100
   123  	IMAGE_FILE_DEBUG_STRIPPED            = 0x0200
   124  	IMAGE_SCN_CNT_CODE                   = 0x00000020
   125  	IMAGE_SCN_CNT_INITIALIZED_DATA       = 0x00000040
   126  	IMAGE_SCN_CNT_UNINITIALIZED_DATA     = 0x00000080
   127  	IMAGE_SCN_MEM_EXECUTE                = 0x20000000
   128  	IMAGE_SCN_MEM_READ                   = 0x40000000
   129  	IMAGE_SCN_MEM_WRITE                  = 0x80000000
   130  	IMAGE_SCN_MEM_DISCARDABLE            = 0x2000000
   131  	IMAGE_SCN_LNK_NRELOC_OVFL            = 0x1000000
   132  	IMAGE_SCN_ALIGN_32BYTES              = 0x600000
   133  	IMAGE_DIRECTORY_ENTRY_EXPORT         = 0
   134  	IMAGE_DIRECTORY_ENTRY_IMPORT         = 1
   135  	IMAGE_DIRECTORY_ENTRY_RESOURCE       = 2
   136  	IMAGE_DIRECTORY_ENTRY_EXCEPTION      = 3
   137  	IMAGE_DIRECTORY_ENTRY_SECURITY       = 4
   138  	IMAGE_DIRECTORY_ENTRY_BASERELOC      = 5
   139  	IMAGE_DIRECTORY_ENTRY_DEBUG          = 6
   140  	IMAGE_DIRECTORY_ENTRY_COPYRIGHT      = 7
   141  	IMAGE_DIRECTORY_ENTRY_ARCHITECTURE   = 7
   142  	IMAGE_DIRECTORY_ENTRY_GLOBALPTR      = 8
   143  	IMAGE_DIRECTORY_ENTRY_TLS            = 9
   144  	IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    = 10
   145  	IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   = 11
   146  	IMAGE_DIRECTORY_ENTRY_IAT            = 12
   147  	IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   = 13
   148  	IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14
   149  	IMAGE_SUBSYSTEM_WINDOWS_GUI          = 2
   150  	IMAGE_SUBSYSTEM_WINDOWS_CUI          = 3
   151  )
   152  
   153  // X64
   154  type PE64_IMAGE_OPTIONAL_HEADER struct {
   155  	Magic                       uint16
   156  	MajorLinkerVersion          uint8
   157  	MinorLinkerVersion          uint8
   158  	SizeOfCode                  uint32
   159  	SizeOfInitializedData       uint32
   160  	SizeOfUninitializedData     uint32
   161  	AddressOfEntryPoint         uint32
   162  	BaseOfCode                  uint32
   163  	ImageBase                   uint64
   164  	SectionAlignment            uint32
   165  	FileAlignment               uint32
   166  	MajorOperatingSystemVersion uint16
   167  	MinorOperatingSystemVersion uint16
   168  	MajorImageVersion           uint16
   169  	MinorImageVersion           uint16
   170  	MajorSubsystemVersion       uint16
   171  	MinorSubsystemVersion       uint16
   172  	Win32VersionValue           uint32
   173  	SizeOfImage                 uint32
   174  	SizeOfHeaders               uint32
   175  	CheckSum                    uint32
   176  	Subsystem                   uint16
   177  	DllCharacteristics          uint16
   178  	SizeOfStackReserve          uint64
   179  	SizeOfStackCommit           uint64
   180  	SizeOfHeapReserve           uint64
   181  	SizeOfHeapCommit            uint64
   182  	LoaderFlags                 uint32
   183  	NumberOfRvaAndSizes         uint32
   184  	DataDirectory               [16]IMAGE_DATA_DIRECTORY
   185  }
   186  
   187  // Copyright 2009 The Go Authors. All rights reserved.
   188  // Use of this source code is governed by a BSD-style
   189  // license that can be found in the LICENSE file.
   190  
   191  // PE (Portable Executable) file writing
   192  // http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
   193  
   194  // DOS stub that prints out
   195  // "This program cannot be run in DOS mode."
   196  var dosstub = []uint8{
   197  	0x4d,
   198  	0x5a,
   199  	0x90,
   200  	0x00,
   201  	0x03,
   202  	0x00,
   203  	0x04,
   204  	0x00,
   205  	0x00,
   206  	0x00,
   207  	0x00,
   208  	0x00,
   209  	0xff,
   210  	0xff,
   211  	0x00,
   212  	0x00,
   213  	0x8b,
   214  	0x00,
   215  	0x00,
   216  	0x00,
   217  	0x00,
   218  	0x00,
   219  	0x00,
   220  	0x00,
   221  	0x40,
   222  	0x00,
   223  	0x00,
   224  	0x00,
   225  	0x00,
   226  	0x00,
   227  	0x00,
   228  	0x00,
   229  	0x00,
   230  	0x00,
   231  	0x00,
   232  	0x00,
   233  	0x00,
   234  	0x00,
   235  	0x00,
   236  	0x00,
   237  	0x00,
   238  	0x00,
   239  	0x00,
   240  	0x00,
   241  	0x00,
   242  	0x00,
   243  	0x00,
   244  	0x00,
   245  	0x00,
   246  	0x00,
   247  	0x00,
   248  	0x00,
   249  	0x00,
   250  	0x00,
   251  	0x00,
   252  	0x00,
   253  	0x00,
   254  	0x00,
   255  	0x00,
   256  	0x00,
   257  	0x80,
   258  	0x00,
   259  	0x00,
   260  	0x00,
   261  	0x0e,
   262  	0x1f,
   263  	0xba,
   264  	0x0e,
   265  	0x00,
   266  	0xb4,
   267  	0x09,
   268  	0xcd,
   269  	0x21,
   270  	0xb8,
   271  	0x01,
   272  	0x4c,
   273  	0xcd,
   274  	0x21,
   275  	0x54,
   276  	0x68,
   277  	0x69,
   278  	0x73,
   279  	0x20,
   280  	0x70,
   281  	0x72,
   282  	0x6f,
   283  	0x67,
   284  	0x72,
   285  	0x61,
   286  	0x6d,
   287  	0x20,
   288  	0x63,
   289  	0x61,
   290  	0x6e,
   291  	0x6e,
   292  	0x6f,
   293  	0x74,
   294  	0x20,
   295  	0x62,
   296  	0x65,
   297  	0x20,
   298  	0x72,
   299  	0x75,
   300  	0x6e,
   301  	0x20,
   302  	0x69,
   303  	0x6e,
   304  	0x20,
   305  	0x44,
   306  	0x4f,
   307  	0x53,
   308  	0x20,
   309  	0x6d,
   310  	0x6f,
   311  	0x64,
   312  	0x65,
   313  	0x2e,
   314  	0x0d,
   315  	0x0d,
   316  	0x0a,
   317  	0x24,
   318  	0x00,
   319  	0x00,
   320  	0x00,
   321  	0x00,
   322  	0x00,
   323  	0x00,
   324  	0x00,
   325  }
   326  
   327  var rsrcsym *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  		ctxt.Diag("too many sections")
   383  		errorexit()
   384  	}
   385  
   386  	h := &sh[pensect]
   387  	pensect++
   388  	copy(h.Name[:], name)
   389  	h.VirtualSize = uint32(sectsize)
   390  	h.VirtualAddress = uint32(nextsectoff)
   391  	nextsectoff = int(Rnd(int64(nextsectoff)+int64(sectsize), PESECTALIGN))
   392  	h.PointerToRawData = uint32(nextfileoff)
   393  	if filesize > 0 {
   394  		h.SizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN))
   395  		nextfileoff += int(h.SizeOfRawData)
   396  	}
   397  
   398  	return h
   399  }
   400  
   401  func chksectoff(ctxt *Link, h *IMAGE_SECTION_HEADER, off int64) {
   402  	if off != int64(h.PointerToRawData) {
   403  		ctxt.Diag("%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  		ctxt.Diag("%s.VirtualAddress = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.VirtualAddress)), uint64(int64(s.Vaddr-PEBASE)))
   411  		errorexit()
   412  	}
   413  
   414  	if s.Fileoff != uint64(h.PointerToRawData) {
   415  		ctxt.Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(int64(s.Fileoff)))
   416  		errorexit()
   417  	}
   418  }
   419  
   420  func Peinit(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.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  				ctxt.Diag("failed to parse stdcall decoration: %v", err)
   509  			}
   510  			m.argsize *= SysArch.PtrSize
   511  			s.Extname = s.Extname[:i]
   512  		}
   513  
   514  		m.s = s
   515  		m.next = d.ms
   516  		d.ms = m
   517  	}
   518  
   519  	if Linkmode == LinkExternal {
   520  		// Add real symbol name
   521  		for d := dr; d != nil; d = d.next {
   522  			for m = d.ms; m != nil; m = m.next {
   523  				m.s.Type = obj.SDATA
   524  				Symgrow(ctxt, m.s, int64(SysArch.PtrSize))
   525  				dynName := m.s.Extname
   526  				// only windows/386 requires stdcall decoration
   527  				if SysArch.Family == sys.I386 && m.argsize >= 0 {
   528  					dynName += fmt.Sprintf("@%d", m.argsize)
   529  				}
   530  				dynSym := Linklookup(ctxt, dynName, 0)
   531  				dynSym.Attr |= AttrReachable
   532  				dynSym.Type = obj.SHOSTOBJ
   533  				r := Addrel(m.s)
   534  				r.Sym = dynSym
   535  				r.Off = 0
   536  				r.Siz = uint8(SysArch.PtrSize)
   537  				r.Type = obj.R_ADDR
   538  			}
   539  		}
   540  	} else {
   541  		dynamic := Linklookup(ctxt, ".windynamic", 0)
   542  		dynamic.Attr |= AttrReachable
   543  		dynamic.Type = obj.SWINDOWS
   544  		for d := dr; d != nil; d = d.next {
   545  			for m = d.ms; m != nil; m = m.next {
   546  				m.s.Type = obj.SWINDOWS | obj.SSUB
   547  				m.s.Sub = dynamic.Sub
   548  				dynamic.Sub = m.s
   549  				m.s.Value = dynamic.Size
   550  				dynamic.Size += int64(SysArch.PtrSize)
   551  			}
   552  
   553  			dynamic.Size += int64(SysArch.PtrSize)
   554  		}
   555  	}
   556  
   557  	return dr
   558  }
   559  
   560  // peimporteddlls returns the gcc command line argument to link all imported
   561  // DLLs.
   562  func peimporteddlls() []string {
   563  	var dlls []string
   564  
   565  	for d := dr; d != nil; d = d.next {
   566  		dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
   567  	}
   568  
   569  	return dlls
   570  }
   571  
   572  func addimports(ctxt *Link, datsect *IMAGE_SECTION_HEADER) {
   573  	startoff := coutbuf.Offset()
   574  	dynamic := Linklookup(ctxt, ".windynamic", 0)
   575  
   576  	// skip import descriptor table (will write it later)
   577  	n := uint64(0)
   578  
   579  	for d := dr; d != nil; d = d.next {
   580  		n++
   581  	}
   582  	Cseek(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
   583  
   584  	// write dll names
   585  	for d := dr; d != nil; d = d.next {
   586  		d.nameoff = uint64(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.Allsym {
   685  		if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() {
   686  			continue
   687  		}
   688  		if nexport+1 > len(dexport) {
   689  			ctxt.Diag("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  		ctxt.Cursym = sym
   794  
   795  		for ri := 0; ri < len(sym.R); ri++ {
   796  			r := &sym.R[ri]
   797  			if r.Done != 0 {
   798  				continue
   799  			}
   800  			if r.Xsym == nil {
   801  				ctxt.Diag("missing xsym in relocation")
   802  				continue
   803  			}
   804  
   805  			if r.Xsym.Dynid < 0 {
   806  				ctxt.Diag("reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
   807  			}
   808  			if !Thearch.PEreloc1(ctxt, r, int64(uint64(sym.Value+int64(r.Off))-PEBASE)) {
   809  				ctxt.Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
   810  			}
   811  
   812  			relocs++
   813  		}
   814  	}
   815  
   816  	sect.Rellen = uint64(coutbuf.Offset()) - sect.Reloff
   817  
   818  	return relocs
   819  }
   820  
   821  // peemitreloc emits relocation entries for go.o in external linking.
   822  func peemitreloc(ctxt *Link, text, data, ctors *IMAGE_SECTION_HEADER) {
   823  	for coutbuf.Offset()&7 != 0 {
   824  		Cput(0)
   825  	}
   826  
   827  	text.PointerToRelocations = uint32(coutbuf.Offset())
   828  	// first entry: extended relocs
   829  	Lputl(0) // placeholder for number of relocation + 1
   830  	Lputl(0)
   831  	Wputl(0)
   832  
   833  	n := perelocsect(ctxt, Segtext.Sect, ctxt.Textp) + 1
   834  	for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
   835  		n += perelocsect(ctxt, sect, datap)
   836  	}
   837  
   838  	cpos := coutbuf.Offset()
   839  	Cseek(int64(text.PointerToRelocations))
   840  	Lputl(uint32(n))
   841  	Cseek(cpos)
   842  	if n > 0x10000 {
   843  		n = 0x10000
   844  		text.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
   845  	} else {
   846  		text.PointerToRelocations += 10 // skip the extend reloc entry
   847  	}
   848  	text.NumberOfRelocations = uint16(n - 1)
   849  
   850  	data.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 = 1
   857  	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
   858  		n += perelocsect(ctxt, sect, datap)
   859  	}
   860  
   861  	cpos = coutbuf.Offset()
   862  	Cseek(int64(data.PointerToRelocations))
   863  	Lputl(uint32(n))
   864  	Cseek(cpos)
   865  	if n > 0x10000 {
   866  		n = 0x10000
   867  		data.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
   868  	} else {
   869  		data.PointerToRelocations += 10 // skip the extend reloc entry
   870  	}
   871  	data.NumberOfRelocations = uint16(n - 1)
   872  
   873  	dottext := Linklookup(ctxt, ".text", 0)
   874  	ctors.NumberOfRelocations = 1
   875  	ctors.PointerToRelocations = uint32(coutbuf.Offset())
   876  	sectoff := ctors.VirtualAddress
   877  	Lputl(sectoff)
   878  	Lputl(uint32(dottext.Dynid))
   879  	switch obj.Getgoarch() {
   880  	default:
   881  		fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch())
   882  		os.Exit(2)
   883  	case "386":
   884  		Wputl(IMAGE_REL_I386_DIR32)
   885  	case "amd64":
   886  		Wputl(IMAGE_REL_AMD64_ADDR64)
   887  	}
   888  }
   889  
   890  func (ctxt *Link) dope() {
   891  	/* relocation table */
   892  	rel := Linklookup(ctxt, ".rel", 0)
   893  
   894  	rel.Attr |= AttrReachable
   895  	rel.Type = obj.SELFROSECT
   896  
   897  	initdynimport(ctxt)
   898  	initdynexport(ctxt)
   899  }
   900  
   901  func strtbladd(name string) int {
   902  	off := len(strtbl) + 4 // offset includes 4-byte length at beginning of table
   903  	strtbl = append(strtbl, name...)
   904  	strtbl = append(strtbl, 0)
   905  	return off
   906  }
   907  
   908  /*
   909   * For more than 8 characters section names, name contains a slash (/) that is
   910   * followed by an ASCII representation of a decimal number that is an offset into
   911   * the string table.
   912   * reference: pecoff_v8.docx Page 24.
   913   * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
   914   */
   915  func newPEDWARFSection(ctxt *Link, name string, size int64) *IMAGE_SECTION_HEADER {
   916  	if size == 0 {
   917  		return nil
   918  	}
   919  
   920  	off := strtbladd(name)
   921  	s := fmt.Sprintf("/%d", off)
   922  	h := addpesection(ctxt, s, int(size), int(size))
   923  	h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
   924  
   925  	return h
   926  }
   927  
   928  // writePESymTableRecords writes all COFF symbol table records.
   929  // It returns number of records written.
   930  func writePESymTableRecords(ctxt *Link) int {
   931  	var symcnt int
   932  
   933  	put := func(ctxt *Link, s *Symbol, name string, type_ int, addr int64, size int64, ver int, gotype *Symbol) {
   934  		if s == nil {
   935  			return
   936  		}
   937  		if s.Sect == nil && type_ != 'U' {
   938  			return
   939  		}
   940  		switch type_ {
   941  		default:
   942  			return
   943  		case 'D', 'B', 'T', 'U':
   944  		}
   945  
   946  		// only windows/386 requires underscore prefix on external symbols
   947  		if SysArch.Family == sys.I386 &&
   948  			Linkmode == LinkExternal &&
   949  			(s.Type != obj.SDYNIMPORT || s.Attr.CgoExport()) &&
   950  			s.Name == s.Extname &&
   951  			s.Name != "_main" {
   952  			s.Name = "_" + s.Name
   953  		}
   954  
   955  		var typ uint16
   956  		var sect int
   957  		var value int64
   958  		// Note: although address of runtime.edata (type SDATA) is at the start of .bss section
   959  		// it still belongs to the .data section, not the .bss section.
   960  		if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != obj.SDATA && Linkmode == LinkExternal {
   961  			value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen)
   962  			sect = bsssect
   963  		} else if uint64(s.Value) >= Segdata.Vaddr {
   964  			value = int64(uint64(s.Value) - Segdata.Vaddr)
   965  			sect = datasect
   966  		} else if uint64(s.Value) >= Segtext.Vaddr {
   967  			value = int64(uint64(s.Value) - Segtext.Vaddr)
   968  			sect = textsect
   969  		} else if type_ == 'U' {
   970  			typ = IMAGE_SYM_DTYPE_FUNCTION
   971  		} else {
   972  			ctxt.Diag("addpesym %#x", addr)
   973  		}
   974  
   975  		// write COFF symbol table record
   976  		if len(s.Name) > 8 {
   977  			Lputl(0)
   978  			Lputl(uint32(strtbladd(s.Name)))
   979  		} else {
   980  			strnput(s.Name, 8)
   981  		}
   982  		Lputl(uint32(value))
   983  		Wputl(uint16(sect))
   984  		if typ != 0 {
   985  			Wputl(typ)
   986  		} else if Linkmode == LinkExternal {
   987  			Wputl(0)
   988  		} else {
   989  			Wputl(0x0308) // "array of structs"
   990  		}
   991  		Cput(2) // storage class: external
   992  		Cput(0) // no aux entries
   993  
   994  		s.Dynid = int32(symcnt)
   995  
   996  		symcnt++
   997  	}
   998  
   999  	if Linkmode == LinkExternal {
  1000  		for d := dr; d != nil; d = d.next {
  1001  			for m := d.ms; m != nil; m = m.next {
  1002  				s := m.s.R[0].Xsym
  1003  				put(ctxt, s, s.Name, 'U', 0, int64(SysArch.PtrSize), 0, nil)
  1004  			}
  1005  		}
  1006  
  1007  		s := Linklookup(ctxt, ".text", 0)
  1008  		if s.Type == obj.STEXT {
  1009  			put(ctxt, s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
  1010  		}
  1011  	}
  1012  
  1013  	genasmsym(ctxt, put)
  1014  
  1015  	return symcnt
  1016  }
  1017  
  1018  func addpesymtable(ctxt *Link) {
  1019  	symtabStartPos := coutbuf.Offset()
  1020  
  1021  	// write COFF symbol table
  1022  	var symcnt int
  1023  	if !*FlagS || Linkmode == LinkExternal {
  1024  		symcnt = writePESymTableRecords(ctxt)
  1025  	}
  1026  
  1027  	// update COFF file header and section table
  1028  	size := len(strtbl) + 4 + 18*symcnt
  1029  	var h *IMAGE_SECTION_HEADER
  1030  	if Linkmode != LinkExternal {
  1031  		// We do not really need .symtab for go.o, and if we have one, ld
  1032  		// will also include it in the exe, and that will confuse windows.
  1033  		h = addpesection(ctxt, ".symtab", size, size)
  1034  		h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
  1035  		chksectoff(ctxt, h, symtabStartPos)
  1036  	}
  1037  	fh.PointerToSymbolTable = uint32(symtabStartPos)
  1038  	fh.NumberOfSymbols = uint32(symcnt)
  1039  
  1040  	// write COFF string table
  1041  	Lputl(uint32(len(strtbl)) + 4)
  1042  	for i := 0; i < len(strtbl); i++ {
  1043  		Cput(strtbl[i])
  1044  	}
  1045  	if Linkmode != LinkExternal {
  1046  		strnput("", int(h.SizeOfRawData-uint32(size)))
  1047  	}
  1048  }
  1049  
  1050  func setpersrc(ctxt *Link, sym *Symbol) {
  1051  	if rsrcsym != nil {
  1052  		ctxt.Diag("too many .rsrc sections")
  1053  	}
  1054  
  1055  	rsrcsym = sym
  1056  }
  1057  
  1058  func addpersrc(ctxt *Link) {
  1059  	if rsrcsym == nil {
  1060  		return
  1061  	}
  1062  
  1063  	h := addpesection(ctxt, ".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
  1064  	h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
  1065  	chksectoff(ctxt, h, coutbuf.Offset())
  1066  
  1067  	// relocation
  1068  	var p []byte
  1069  	var r *Reloc
  1070  	var val uint32
  1071  	for ri := 0; ri < len(rsrcsym.R); ri++ {
  1072  		r = &rsrcsym.R[ri]
  1073  		p = rsrcsym.P[r.Off:]
  1074  		val = uint32(int64(h.VirtualAddress) + r.Add)
  1075  
  1076  		// 32-bit little-endian
  1077  		p[0] = byte(val)
  1078  
  1079  		p[1] = byte(val >> 8)
  1080  		p[2] = byte(val >> 16)
  1081  		p[3] = byte(val >> 24)
  1082  	}
  1083  
  1084  	Cwrite(rsrcsym.P)
  1085  	strnput("", int(int64(h.SizeOfRawData)-rsrcsym.Size))
  1086  
  1087  	// update data directory
  1088  	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.VirtualAddress
  1089  
  1090  	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.VirtualSize
  1091  }
  1092  
  1093  func addinitarray(ctxt *Link) (c *IMAGE_SECTION_HEADER) {
  1094  	// The size below was determined by the specification for array relocations,
  1095  	// and by observing what GCC writes here. If the initarray section grows to
  1096  	// contain more than one constructor entry, the size will need to be 8 * constructor_count.
  1097  	// However, the entire Go runtime is initialized from just one function, so it is unlikely
  1098  	// that this will need to grow in the future.
  1099  	var size int
  1100  	switch obj.Getgoarch() {
  1101  	default:
  1102  		fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch())
  1103  		os.Exit(2)
  1104  	case "386":
  1105  		size = 4
  1106  	case "amd64":
  1107  		size = 8
  1108  	}
  1109  
  1110  	c = addpesection(ctxt, ".ctors", size, size)
  1111  	c.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
  1112  	c.SizeOfRawData = uint32(size)
  1113  
  1114  	Cseek(int64(c.PointerToRawData))
  1115  	chksectoff(ctxt, c, coutbuf.Offset())
  1116  	init_entry := Linklookup(ctxt, *flagEntrySymbol, 0)
  1117  	addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr
  1118  
  1119  	switch obj.Getgoarch() {
  1120  	case "386":
  1121  		Lputl(uint32(addr))
  1122  	case "amd64":
  1123  		Vputl(addr)
  1124  	}
  1125  
  1126  	return c
  1127  }
  1128  
  1129  func Asmbpe(ctxt *Link) {
  1130  	switch SysArch.Family {
  1131  	default:
  1132  		Exitf("unknown PE architecture: %v", SysArch.Family)
  1133  	case sys.AMD64:
  1134  		fh.Machine = IMAGE_FILE_MACHINE_AMD64
  1135  	case sys.I386:
  1136  		fh.Machine = IMAGE_FILE_MACHINE_I386
  1137  	}
  1138  
  1139  	t := addpesection(ctxt, ".text", int(Segtext.Length), int(Segtext.Length))
  1140  	t.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
  1141  	if Linkmode == LinkExternal {
  1142  		// some data symbols (e.g. masks) end up in the .text section, and they normally
  1143  		// expect larger alignment requirement than the default text section alignment.
  1144  		t.Characteristics |= IMAGE_SCN_ALIGN_32BYTES
  1145  	}
  1146  	chksectseg(ctxt, t, &Segtext)
  1147  	textsect = pensect
  1148  
  1149  	var d *IMAGE_SECTION_HEADER
  1150  	var c *IMAGE_SECTION_HEADER
  1151  	if Linkmode != LinkExternal {
  1152  		d = addpesection(ctxt, ".data", int(Segdata.Length), int(Segdata.Filelen))
  1153  		d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1154  		chksectseg(ctxt, d, &Segdata)
  1155  		datasect = pensect
  1156  	} else {
  1157  		d = addpesection(ctxt, ".data", int(Segdata.Filelen), int(Segdata.Filelen))
  1158  		d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1159  		chksectseg(ctxt, d, &Segdata)
  1160  		datasect = pensect
  1161  
  1162  		b := addpesection(ctxt, ".bss", int(Segdata.Length-Segdata.Filelen), 0)
  1163  		b.Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1164  		b.PointerToRawData = 0
  1165  		bsssect = pensect
  1166  
  1167  		c = addinitarray(ctxt)
  1168  	}
  1169  
  1170  	if !*FlagS {
  1171  		dwarfaddpeheaders(ctxt)
  1172  	}
  1173  
  1174  	Cseek(int64(nextfileoff))
  1175  	if Linkmode != LinkExternal {
  1176  		addimports(ctxt, d)
  1177  		addexports(ctxt)
  1178  	}
  1179  	addpesymtable(ctxt)
  1180  	addpersrc(ctxt)
  1181  	if Linkmode == LinkExternal {
  1182  		peemitreloc(ctxt, t, d, c)
  1183  	}
  1184  
  1185  	fh.NumberOfSections = uint16(pensect)
  1186  
  1187  	// Being able to produce identical output for identical input is
  1188  	// much more beneficial than having build timestamp in the header.
  1189  	fh.TimeDateStamp = 0
  1190  
  1191  	if Linkmode == LinkExternal {
  1192  		fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED
  1193  	} else {
  1194  		fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED
  1195  	}
  1196  	if pe64 != 0 {
  1197  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
  1198  		fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE
  1199  		oh64.Magic = 0x20b // PE32+
  1200  	} else {
  1201  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
  1202  		fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE
  1203  		oh.Magic = 0x10b // PE32
  1204  		oh.BaseOfData = d.VirtualAddress
  1205  	}
  1206  
  1207  	// Fill out both oh64 and oh. We only use one. Oh well.
  1208  	oh64.MajorLinkerVersion = 3
  1209  
  1210  	oh.MajorLinkerVersion = 3
  1211  	oh64.MinorLinkerVersion = 0
  1212  	oh.MinorLinkerVersion = 0
  1213  	oh64.SizeOfCode = t.SizeOfRawData
  1214  	oh.SizeOfCode = t.SizeOfRawData
  1215  	oh64.SizeOfInitializedData = d.SizeOfRawData
  1216  	oh.SizeOfInitializedData = d.SizeOfRawData
  1217  	oh64.SizeOfUninitializedData = 0
  1218  	oh.SizeOfUninitializedData = 0
  1219  	if Linkmode != LinkExternal {
  1220  		oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
  1221  		oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
  1222  	}
  1223  	oh64.BaseOfCode = t.VirtualAddress
  1224  	oh.BaseOfCode = t.VirtualAddress
  1225  	oh64.ImageBase = PEBASE
  1226  	oh.ImageBase = PEBASE
  1227  	oh64.SectionAlignment = PESECTALIGN
  1228  	oh.SectionAlignment = PESECTALIGN
  1229  	oh64.FileAlignment = PEFILEALIGN
  1230  	oh.FileAlignment = PEFILEALIGN
  1231  	oh64.MajorOperatingSystemVersion = 4
  1232  	oh.MajorOperatingSystemVersion = 4
  1233  	oh64.MinorOperatingSystemVersion = 0
  1234  	oh.MinorOperatingSystemVersion = 0
  1235  	oh64.MajorImageVersion = 1
  1236  	oh.MajorImageVersion = 1
  1237  	oh64.MinorImageVersion = 0
  1238  	oh.MinorImageVersion = 0
  1239  	oh64.MajorSubsystemVersion = 4
  1240  	oh.MajorSubsystemVersion = 4
  1241  	oh64.MinorSubsystemVersion = 0
  1242  	oh.MinorSubsystemVersion = 0
  1243  	oh64.SizeOfImage = uint32(nextsectoff)
  1244  	oh.SizeOfImage = uint32(nextsectoff)
  1245  	oh64.SizeOfHeaders = uint32(PEFILEHEADR)
  1246  	oh.SizeOfHeaders = uint32(PEFILEHEADR)
  1247  	if headstring == "windowsgui" {
  1248  		oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
  1249  		oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
  1250  	} else {
  1251  		oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
  1252  		oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
  1253  	}
  1254  
  1255  	// Disable stack growth as we don't want Windows to
  1256  	// fiddle with the thread stack limits, which we set
  1257  	// ourselves to circumvent the stack checks in the
  1258  	// Windows exception dispatcher.
  1259  	// Commit size must be strictly less than reserve
  1260  	// size otherwise reserve will be rounded up to a
  1261  	// larger size, as verified with VMMap.
  1262  
  1263  	// Go code would be OK with 64k stacks, but we need larger stacks for cgo.
  1264  	//
  1265  	// The default stack reserve size affects only the main
  1266  	// thread, ctrlhandler thread, and profileloop thread. For
  1267  	// these, it must be greater than the stack size assumed by
  1268  	// externalthreadhandler.
  1269  	//
  1270  	// For other threads we specify stack size in runtime explicitly
  1271  	// (runtime knows whether cgo is enabled or not).
  1272  	// For these, the reserve must match STACKSIZE in
  1273  	// runtime/cgo/gcc_windows_{386,amd64}.c and the correspondent
  1274  	// CreateThread parameter in runtime.newosproc.
  1275  	if !iscgo {
  1276  		oh64.SizeOfStackReserve = 0x00020000
  1277  		oh.SizeOfStackReserve = 0x00020000
  1278  		oh64.SizeOfStackCommit = 0x00001000
  1279  		oh.SizeOfStackCommit = 0x00001000
  1280  	} else {
  1281  		oh64.SizeOfStackReserve = 0x00200000
  1282  		oh.SizeOfStackReserve = 0x00100000
  1283  
  1284  		// account for 2 guard pages
  1285  		oh64.SizeOfStackCommit = 0x00200000 - 0x2000
  1286  
  1287  		oh.SizeOfStackCommit = 0x00100000 - 0x2000
  1288  	}
  1289  
  1290  	oh64.SizeOfHeapReserve = 0x00100000
  1291  	oh.SizeOfHeapReserve = 0x00100000
  1292  	oh64.SizeOfHeapCommit = 0x00001000
  1293  	oh.SizeOfHeapCommit = 0x00001000
  1294  	oh64.NumberOfRvaAndSizes = 16
  1295  	oh.NumberOfRvaAndSizes = 16
  1296  
  1297  	pewrite()
  1298  }