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