...
Run Format

Source file src/cmd/link/internal/ld/pe.go

Documentation: cmd/link/internal/ld

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ld
     6  
     7  import (
     8  	"cmd/internal/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  	oh.SizeOfStackReserve = 0x00100000
   861  	if !iscgo {
   862  		oh.SizeOfStackCommit = 0x00001000
   863  	} else {
   864  		oh.SizeOfStackCommit = 0x00100000 - 0x2000 // account for 2 guard pages
   865  	}
   866  
   867  	oh64.SizeOfHeapReserve = 0x00100000
   868  	oh.SizeOfHeapReserve = 0x00100000
   869  	oh64.SizeOfHeapCommit = 0x00001000
   870  	oh.SizeOfHeapCommit = 0x00001000
   871  	oh64.NumberOfRvaAndSizes = 16
   872  	oh.NumberOfRvaAndSizes = 16
   873  
   874  	if pe64 != 0 {
   875  		oh64.DataDirectory = f.dataDirectory
   876  	} else {
   877  		oh.DataDirectory = f.dataDirectory
   878  	}
   879  
   880  	if pe64 != 0 {
   881  		binary.Write(ctxt.Out, binary.LittleEndian, &oh64)
   882  	} else {
   883  		binary.Write(ctxt.Out, binary.LittleEndian, &oh)
   884  	}
   885  }
   886  
   887  var pefile peFile
   888  
   889  func Peinit(ctxt *Link) {
   890  	var l int
   891  
   892  	switch ctxt.Arch.Family {
   893  	// 64-bit architectures
   894  	case sys.AMD64:
   895  		pe64 = 1
   896  		var oh64 pe.OptionalHeader64
   897  		l = binary.Size(&oh64)
   898  
   899  	// 32-bit architectures
   900  	default:
   901  		var oh pe.OptionalHeader32
   902  		l = binary.Size(&oh)
   903  
   904  	}
   905  
   906  	if ctxt.LinkMode == LinkExternal {
   907  		PESECTALIGN = 0
   908  		PEFILEALIGN = 0
   909  	}
   910  
   911  	var sh [16]pe.SectionHeader32
   912  	var fh pe.FileHeader
   913  	PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
   914  	if ctxt.LinkMode != LinkExternal {
   915  		PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
   916  	} else {
   917  		PESECTHEADR = 0
   918  	}
   919  	pefile.nextSectOffset = uint32(PESECTHEADR)
   920  	pefile.nextFileOffset = uint32(PEFILEHEADR)
   921  
   922  	if ctxt.LinkMode == LinkInternal {
   923  		// some mingw libs depend on this symbol, for example, FindPESectionByName
   924  		ctxt.xdefine("__image_base__", sym.SDATA, PEBASE)
   925  		ctxt.xdefine("_image_base__", sym.SDATA, PEBASE)
   926  	}
   927  
   928  	HEADR = PEFILEHEADR
   929  	if *FlagTextAddr == -1 {
   930  		*FlagTextAddr = PEBASE + int64(PESECTHEADR)
   931  	}
   932  	if *FlagDataAddr == -1 {
   933  		*FlagDataAddr = 0
   934  	}
   935  	if *FlagRound == -1 {
   936  		*FlagRound = int(PESECTALIGN)
   937  	}
   938  	if *FlagDataAddr != 0 && *FlagRound != 0 {
   939  		fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*FlagDataAddr), uint32(*FlagRound))
   940  	}
   941  }
   942  
   943  func pewrite(ctxt *Link) {
   944  	ctxt.Out.SeekSet(0)
   945  	if ctxt.LinkMode != LinkExternal {
   946  		ctxt.Out.Write(dosstub)
   947  		ctxt.Out.WriteStringN("PE", 4)
   948  	}
   949  
   950  	pefile.writeFileHeader(ctxt.Arch, ctxt.Out, ctxt.LinkMode)
   951  
   952  	pefile.writeOptionalHeader(ctxt)
   953  
   954  	for _, sect := range pefile.sections {
   955  		sect.write(ctxt.Out, ctxt.LinkMode)
   956  	}
   957  }
   958  
   959  func strput(out *OutBuf, s string) {
   960  	out.WriteString(s)
   961  	out.Write8(0)
   962  	// string must be padded to even size
   963  	if (len(s)+1)%2 != 0 {
   964  		out.Write8(0)
   965  	}
   966  }
   967  
   968  func initdynimport(ctxt *Link) *Dll {
   969  	var d *Dll
   970  
   971  	dr = nil
   972  	var m *Imp
   973  	for _, s := range ctxt.Syms.Allsym {
   974  		if !s.Attr.Reachable() || s.Type != sym.SDYNIMPORT {
   975  			continue
   976  		}
   977  		for d = dr; d != nil; d = d.next {
   978  			if d.name == s.Dynimplib {
   979  				m = new(Imp)
   980  				break
   981  			}
   982  		}
   983  
   984  		if d == nil {
   985  			d = new(Dll)
   986  			d.name = s.Dynimplib
   987  			d.next = dr
   988  			dr = d
   989  			m = new(Imp)
   990  		}
   991  
   992  		// Because external link requires properly stdcall decorated name,
   993  		// all external symbols in runtime use %n to denote that the number
   994  		// of uinptrs this function consumes. Store the argsize and discard
   995  		// the %n suffix if any.
   996  		m.argsize = -1
   997  		if i := strings.IndexByte(s.Extname, '%'); i >= 0 {
   998  			var err error
   999  			m.argsize, err = strconv.Atoi(s.Extname[i+1:])
  1000  			if err != nil {
  1001  				Errorf(s, "failed to parse stdcall decoration: %v", err)
  1002  			}
  1003  			m.argsize *= ctxt.Arch.PtrSize
  1004  			s.Extname = s.Extname[:i]
  1005  		}
  1006  
  1007  		m.s = s
  1008  		m.next = d.ms
  1009  		d.ms = m
  1010  	}
  1011  
  1012  	if ctxt.LinkMode == LinkExternal {
  1013  		// Add real symbol name
  1014  		for d := dr; d != nil; d = d.next {
  1015  			for m = d.ms; m != nil; m = m.next {
  1016  				m.s.Type = sym.SDATA
  1017  				m.s.Grow(int64(ctxt.Arch.PtrSize))
  1018  				dynName := m.s.Extname
  1019  				// only windows/386 requires stdcall decoration
  1020  				if ctxt.Arch.Family == sys.I386 && m.argsize >= 0 {
  1021  					dynName += fmt.Sprintf("@%d", m.argsize)
  1022  				}
  1023  				dynSym := ctxt.Syms.Lookup(dynName, 0)
  1024  				dynSym.Attr |= sym.AttrReachable
  1025  				dynSym.Type = sym.SHOSTOBJ
  1026  				r := m.s.AddRel()
  1027  				r.Sym = dynSym
  1028  				r.Off = 0
  1029  				r.Siz = uint8(ctxt.Arch.PtrSize)
  1030  				r.Type = objabi.R_ADDR
  1031  			}
  1032  		}
  1033  	} else {
  1034  		dynamic := ctxt.Syms.Lookup(".windynamic", 0)
  1035  		dynamic.Attr |= sym.AttrReachable
  1036  		dynamic.Type = sym.SWINDOWS
  1037  		for d := dr; d != nil; d = d.next {
  1038  			for m = d.ms; m != nil; m = m.next {
  1039  				m.s.Type = sym.SWINDOWS
  1040  				m.s.Attr |= sym.AttrSubSymbol
  1041  				m.s.Sub = dynamic.Sub
  1042  				dynamic.Sub = m.s
  1043  				m.s.Value = dynamic.Size
  1044  				dynamic.Size += int64(ctxt.Arch.PtrSize)
  1045  			}
  1046  
  1047  			dynamic.Size += int64(ctxt.Arch.PtrSize)
  1048  		}
  1049  	}
  1050  
  1051  	return dr
  1052  }
  1053  
  1054  // peimporteddlls returns the gcc command line argument to link all imported
  1055  // DLLs.
  1056  func peimporteddlls() []string {
  1057  	var dlls []string
  1058  
  1059  	for d := dr; d != nil; d = d.next {
  1060  		dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
  1061  	}
  1062  
  1063  	return dlls
  1064  }
  1065  
  1066  func addimports(ctxt *Link, datsect *peSection) {
  1067  	startoff := ctxt.Out.Offset()
  1068  	dynamic := ctxt.Syms.Lookup(".windynamic", 0)
  1069  
  1070  	// skip import descriptor table (will write it later)
  1071  	n := uint64(0)
  1072  
  1073  	for d := dr; d != nil; d = d.next {
  1074  		n++
  1075  	}
  1076  	ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
  1077  
  1078  	// write dll names
  1079  	for d := dr; d != nil; d = d.next {
  1080  		d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff)
  1081  		strput(ctxt.Out, d.name)
  1082  	}
  1083  
  1084  	// write function names
  1085  	var m *Imp
  1086  	for d := dr; d != nil; d = d.next {
  1087  		for m = d.ms; m != nil; m = m.next {
  1088  			m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
  1089  			ctxt.Out.Write16(0) // hint
  1090  			strput(ctxt.Out, m.s.Extname)
  1091  		}
  1092  	}
  1093  
  1094  	// write OriginalFirstThunks
  1095  	oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff)
  1096  
  1097  	n = uint64(ctxt.Out.Offset())
  1098  	for d := dr; d != nil; d = d.next {
  1099  		d.thunkoff = uint64(ctxt.Out.Offset()) - n
  1100  		for m = d.ms; m != nil; m = m.next {
  1101  			if pe64 != 0 {
  1102  				ctxt.Out.Write64(m.off)
  1103  			} else {
  1104  				ctxt.Out.Write32(uint32(m.off))
  1105  			}
  1106  		}
  1107  
  1108  		if pe64 != 0 {
  1109  			ctxt.Out.Write64(0)
  1110  		} else {
  1111  			ctxt.Out.Write32(0)
  1112  		}
  1113  	}
  1114  
  1115  	// add pe section and pad it at the end
  1116  	n = uint64(ctxt.Out.Offset()) - uint64(startoff)
  1117  
  1118  	isect := pefile.addSection(".idata", int(n), int(n))
  1119  	isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1120  	isect.checkOffset(startoff)
  1121  	isect.pad(ctxt.Out, uint32(n))
  1122  	endoff := ctxt.Out.Offset()
  1123  
  1124  	// write FirstThunks (allocated in .data section)
  1125  	ftbase := uint64(dynamic.Value) - uint64(datsect.virtualAddress) - PEBASE
  1126  
  1127  	ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase))
  1128  	for d := dr; d != nil; d = d.next {
  1129  		for m = d.ms; m != nil; m = m.next {
  1130  			if pe64 != 0 {
  1131  				ctxt.Out.Write64(m.off)
  1132  			} else {
  1133  				ctxt.Out.Write32(uint32(m.off))
  1134  			}
  1135  		}
  1136  
  1137  		if pe64 != 0 {
  1138  			ctxt.Out.Write64(0)
  1139  		} else {
  1140  			ctxt.Out.Write32(0)
  1141  		}
  1142  	}
  1143  
  1144  	// finally write import descriptor table
  1145  	out := ctxt.Out
  1146  	out.SeekSet(startoff)
  1147  
  1148  	for d := dr; d != nil; d = d.next {
  1149  		out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff))
  1150  		out.Write32(0)
  1151  		out.Write32(0)
  1152  		out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff))
  1153  		out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff))
  1154  	}
  1155  
  1156  	out.Write32(0) //end
  1157  	out.Write32(0)
  1158  	out.Write32(0)
  1159  	out.Write32(0)
  1160  	out.Write32(0)
  1161  
  1162  	// update data directory
  1163  	pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
  1164  	pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
  1165  	pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE)
  1166  	pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size)
  1167  
  1168  	out.SeekSet(endoff)
  1169  }
  1170  
  1171  type byExtname []*sym.Symbol
  1172  
  1173  func (s byExtname) Len() int           { return len(s) }
  1174  func (s byExtname) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
  1175  func (s byExtname) Less(i, j int) bool { return s[i].Extname < s[j].Extname }
  1176  
  1177  func initdynexport(ctxt *Link) {
  1178  	nexport = 0
  1179  	for _, s := range ctxt.Syms.Allsym {
  1180  		if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() {
  1181  			continue
  1182  		}
  1183  		if nexport+1 > len(dexport) {
  1184  			Errorf(s, "pe dynexport table is full")
  1185  			errorexit()
  1186  		}
  1187  
  1188  		dexport[nexport] = s
  1189  		nexport++
  1190  	}
  1191  
  1192  	sort.Sort(byExtname(dexport[:nexport]))
  1193  }
  1194  
  1195  func addexports(ctxt *Link) {
  1196  	var e IMAGE_EXPORT_DIRECTORY
  1197  
  1198  	size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
  1199  	for i := 0; i < nexport; i++ {
  1200  		size += len(dexport[i].Extname) + 1
  1201  	}
  1202  
  1203  	if nexport == 0 {
  1204  		return
  1205  	}
  1206  
  1207  	sect := pefile.addSection(".edata", size, size)
  1208  	sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
  1209  	sect.checkOffset(ctxt.Out.Offset())
  1210  	va := int(sect.virtualAddress)
  1211  	pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
  1212  	pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
  1213  
  1214  	vaName := va + binary.Size(&e) + nexport*4
  1215  	vaAddr := va + binary.Size(&e)
  1216  	vaNa := va + binary.Size(&e) + nexport*8
  1217  
  1218  	e.Characteristics = 0
  1219  	e.MajorVersion = 0
  1220  	e.MinorVersion = 0
  1221  	e.NumberOfFunctions = uint32(nexport)
  1222  	e.NumberOfNames = uint32(nexport)
  1223  	e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
  1224  	e.Base = 1
  1225  	e.AddressOfFunctions = uint32(vaAddr)
  1226  	e.AddressOfNames = uint32(vaName)
  1227  	e.AddressOfNameOrdinals = uint32(vaNa)
  1228  
  1229  	out := ctxt.Out
  1230  
  1231  	// put IMAGE_EXPORT_DIRECTORY
  1232  	binary.Write(out, binary.LittleEndian, &e)
  1233  
  1234  	// put EXPORT Address Table
  1235  	for i := 0; i < nexport; i++ {
  1236  		out.Write32(uint32(dexport[i].Value - PEBASE))
  1237  	}
  1238  
  1239  	// put EXPORT Name Pointer Table
  1240  	v := int(e.Name + uint32(len(*flagOutfile)) + 1)
  1241  
  1242  	for i := 0; i < nexport; i++ {
  1243  		out.Write32(uint32(v))
  1244  		v += len(dexport[i].Extname) + 1
  1245  	}
  1246  
  1247  	// put EXPORT Ordinal Table
  1248  	for i := 0; i < nexport; i++ {
  1249  		out.Write16(uint16(i))
  1250  	}
  1251  
  1252  	// put Names
  1253  	out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
  1254  
  1255  	for i := 0; i < nexport; i++ {
  1256  		out.WriteStringN(dexport[i].Extname, len(dexport[i].Extname)+1)
  1257  	}
  1258  	sect.pad(out, uint32(size))
  1259  }
  1260  
  1261  func (ctxt *Link) dope() {
  1262  	/* relocation table */
  1263  	rel := ctxt.Syms.Lookup(".rel", 0)
  1264  
  1265  	rel.Attr |= sym.AttrReachable
  1266  	rel.Type = sym.SELFROSECT
  1267  
  1268  	initdynimport(ctxt)
  1269  	initdynexport(ctxt)
  1270  }
  1271  
  1272  func setpersrc(ctxt *Link, sym *sym.Symbol) {
  1273  	if rsrcsym != nil {
  1274  		Errorf(sym, "too many .rsrc sections")
  1275  	}
  1276  
  1277  	rsrcsym = sym
  1278  }
  1279  
  1280  func addpersrc(ctxt *Link) {
  1281  	if rsrcsym == nil {
  1282  		return
  1283  	}
  1284  
  1285  	h := pefile.addSection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
  1286  	h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
  1287  	h.checkOffset(ctxt.Out.Offset())
  1288  
  1289  	// relocation
  1290  	var p []byte
  1291  	var r *sym.Reloc
  1292  	var val uint32
  1293  	for ri := 0; ri < len(rsrcsym.R); ri++ {
  1294  		r = &rsrcsym.R[ri]
  1295  		p = rsrcsym.P[r.Off:]
  1296  		val = uint32(int64(h.virtualAddress) + r.Add)
  1297  
  1298  		// 32-bit little-endian
  1299  		p[0] = byte(val)
  1300  
  1301  		p[1] = byte(val >> 8)
  1302  		p[2] = byte(val >> 16)
  1303  		p[3] = byte(val >> 24)
  1304  	}
  1305  
  1306  	ctxt.Out.Write(rsrcsym.P)
  1307  	h.pad(ctxt.Out, uint32(rsrcsym.Size))
  1308  
  1309  	// update data directory
  1310  	pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
  1311  
  1312  	pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
  1313  }
  1314  
  1315  func Asmbpe(ctxt *Link) {
  1316  	switch ctxt.Arch.Family {
  1317  	default:
  1318  		Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
  1319  	case sys.AMD64, sys.I386:
  1320  	}
  1321  
  1322  	t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length))
  1323  	t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
  1324  	if ctxt.LinkMode == LinkExternal {
  1325  		// some data symbols (e.g. masks) end up in the .text section, and they normally
  1326  		// expect larger alignment requirement than the default text section alignment.
  1327  		t.characteristics |= IMAGE_SCN_ALIGN_32BYTES
  1328  	}
  1329  	t.checkSegment(&Segtext)
  1330  	pefile.textSect = t
  1331  
  1332  	var d *peSection
  1333  	if ctxt.LinkMode != LinkExternal {
  1334  		d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
  1335  		d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1336  		d.checkSegment(&Segdata)
  1337  		pefile.dataSect = d
  1338  	} else {
  1339  		d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
  1340  		d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1341  		d.checkSegment(&Segdata)
  1342  		pefile.dataSect = d
  1343  
  1344  		b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
  1345  		b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1346  		b.pointerToRawData = 0
  1347  		pefile.bssSect = b
  1348  	}
  1349  
  1350  	pefile.addDWARF()
  1351  
  1352  	if ctxt.LinkMode == LinkExternal {
  1353  		pefile.ctorsSect = pefile.addInitArray(ctxt)
  1354  	}
  1355  
  1356  	ctxt.Out.SeekSet(int64(pefile.nextFileOffset))
  1357  	if ctxt.LinkMode != LinkExternal {
  1358  		addimports(ctxt, d)
  1359  		addexports(ctxt)
  1360  	}
  1361  	pefile.writeSymbolTableAndStringTable(ctxt)
  1362  	addpersrc(ctxt)
  1363  	if ctxt.LinkMode == LinkExternal {
  1364  		pefile.emitRelocations(ctxt)
  1365  	}
  1366  
  1367  	pewrite(ctxt)
  1368  }
  1369  

View as plain text