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