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