Black Lives Matter. Support the Equal Justice Initiative.

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  // PE (Portable Executable) file writing
     6  // https://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
     7  
     8  package ld
     9  
    10  import (
    11  	"cmd/internal/objabi"
    12  	"cmd/internal/sys"
    13  	"cmd/link/internal/loader"
    14  	"cmd/link/internal/sym"
    15  	"debug/pe"
    16  	"encoding/binary"
    17  	"fmt"
    18  	"sort"
    19  	"strconv"
    20  	"strings"
    21  )
    22  
    23  type IMAGE_IMPORT_DESCRIPTOR struct {
    24  	OriginalFirstThunk uint32
    25  	TimeDateStamp      uint32
    26  	ForwarderChain     uint32
    27  	Name               uint32
    28  	FirstThunk         uint32
    29  }
    30  
    31  type IMAGE_EXPORT_DIRECTORY struct {
    32  	Characteristics       uint32
    33  	TimeDateStamp         uint32
    34  	MajorVersion          uint16
    35  	MinorVersion          uint16
    36  	Name                  uint32
    37  	Base                  uint32
    38  	NumberOfFunctions     uint32
    39  	NumberOfNames         uint32
    40  	AddressOfFunctions    uint32
    41  	AddressOfNames        uint32
    42  	AddressOfNameOrdinals uint32
    43  }
    44  
    45  const (
    46  	PEBASE = 0x00400000
    47  )
    48  
    49  var (
    50  	// SectionAlignment must be greater than or equal to FileAlignment.
    51  	// The default is the page size for the architecture.
    52  	PESECTALIGN int64 = 0x1000
    53  
    54  	// FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
    55  	// The default is 512. If the SectionAlignment is less than
    56  	// the architecture's page size, then FileAlignment must match SectionAlignment.
    57  	PEFILEALIGN int64 = 2 << 8
    58  )
    59  
    60  const (
    61  	IMAGE_SCN_CNT_CODE               = 0x00000020
    62  	IMAGE_SCN_CNT_INITIALIZED_DATA   = 0x00000040
    63  	IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080
    64  	IMAGE_SCN_MEM_EXECUTE            = 0x20000000
    65  	IMAGE_SCN_MEM_READ               = 0x40000000
    66  	IMAGE_SCN_MEM_WRITE              = 0x80000000
    67  	IMAGE_SCN_MEM_DISCARDABLE        = 0x2000000
    68  	IMAGE_SCN_LNK_NRELOC_OVFL        = 0x1000000
    69  	IMAGE_SCN_ALIGN_32BYTES          = 0x600000
    70  )
    71  
    72  // TODO(crawshaw): add these constants to debug/pe.
    73  const (
    74  	// TODO: the Microsoft doco says IMAGE_SYM_DTYPE_ARRAY is 3 and IMAGE_SYM_DTYPE_FUNCTION is 2
    75  	IMAGE_SYM_TYPE_NULL      = 0
    76  	IMAGE_SYM_TYPE_STRUCT    = 8
    77  	IMAGE_SYM_DTYPE_FUNCTION = 0x20
    78  	IMAGE_SYM_DTYPE_ARRAY    = 0x30
    79  	IMAGE_SYM_CLASS_EXTERNAL = 2
    80  	IMAGE_SYM_CLASS_STATIC   = 3
    81  
    82  	IMAGE_REL_I386_DIR32  = 0x0006
    83  	IMAGE_REL_I386_SECREL = 0x000B
    84  	IMAGE_REL_I386_REL32  = 0x0014
    85  
    86  	IMAGE_REL_AMD64_ADDR64 = 0x0001
    87  	IMAGE_REL_AMD64_ADDR32 = 0x0002
    88  	IMAGE_REL_AMD64_REL32  = 0x0004
    89  	IMAGE_REL_AMD64_SECREL = 0x000B
    90  
    91  	IMAGE_REL_ARM_ABSOLUTE = 0x0000
    92  	IMAGE_REL_ARM_ADDR32   = 0x0001
    93  	IMAGE_REL_ARM_ADDR32NB = 0x0002
    94  	IMAGE_REL_ARM_BRANCH24 = 0x0003
    95  	IMAGE_REL_ARM_BRANCH11 = 0x0004
    96  	IMAGE_REL_ARM_SECREL   = 0x000F
    97  
    98  	IMAGE_REL_BASED_HIGHLOW = 3
    99  	IMAGE_REL_BASED_DIR64   = 10
   100  )
   101  
   102  const (
   103  	PeMinimumTargetMajorVersion = 6
   104  	PeMinimumTargetMinorVersion = 1
   105  )
   106  
   107  // DOS stub that prints out
   108  // "This program cannot be run in DOS mode."
   109  var dosstub = []uint8{
   110  	0x4d,
   111  	0x5a,
   112  	0x90,
   113  	0x00,
   114  	0x03,
   115  	0x00,
   116  	0x04,
   117  	0x00,
   118  	0x00,
   119  	0x00,
   120  	0x00,
   121  	0x00,
   122  	0xff,
   123  	0xff,
   124  	0x00,
   125  	0x00,
   126  	0x8b,
   127  	0x00,
   128  	0x00,
   129  	0x00,
   130  	0x00,
   131  	0x00,
   132  	0x00,
   133  	0x00,
   134  	0x40,
   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  	0x00,
   165  	0x00,
   166  	0x00,
   167  	0x00,
   168  	0x00,
   169  	0x00,
   170  	0x80,
   171  	0x00,
   172  	0x00,
   173  	0x00,
   174  	0x0e,
   175  	0x1f,
   176  	0xba,
   177  	0x0e,
   178  	0x00,
   179  	0xb4,
   180  	0x09,
   181  	0xcd,
   182  	0x21,
   183  	0xb8,
   184  	0x01,
   185  	0x4c,
   186  	0xcd,
   187  	0x21,
   188  	0x54,
   189  	0x68,
   190  	0x69,
   191  	0x73,
   192  	0x20,
   193  	0x70,
   194  	0x72,
   195  	0x6f,
   196  	0x67,
   197  	0x72,
   198  	0x61,
   199  	0x6d,
   200  	0x20,
   201  	0x63,
   202  	0x61,
   203  	0x6e,
   204  	0x6e,
   205  	0x6f,
   206  	0x74,
   207  	0x20,
   208  	0x62,
   209  	0x65,
   210  	0x20,
   211  	0x72,
   212  	0x75,
   213  	0x6e,
   214  	0x20,
   215  	0x69,
   216  	0x6e,
   217  	0x20,
   218  	0x44,
   219  	0x4f,
   220  	0x53,
   221  	0x20,
   222  	0x6d,
   223  	0x6f,
   224  	0x64,
   225  	0x65,
   226  	0x2e,
   227  	0x0d,
   228  	0x0d,
   229  	0x0a,
   230  	0x24,
   231  	0x00,
   232  	0x00,
   233  	0x00,
   234  	0x00,
   235  	0x00,
   236  	0x00,
   237  	0x00,
   238  }
   239  
   240  type Imp struct {
   241  	s       loader.Sym
   242  	off     uint64
   243  	next    *Imp
   244  	argsize int
   245  }
   246  
   247  type Dll struct {
   248  	name     string
   249  	nameoff  uint64
   250  	thunkoff uint64
   251  	ms       *Imp
   252  	next     *Dll
   253  }
   254  
   255  var (
   256  	rsrcsyms    []loader.Sym
   257  	PESECTHEADR int32
   258  	PEFILEHEADR int32
   259  	pe64        int
   260  	dr          *Dll
   261  
   262  	dexport = make([]loader.Sym, 0, 1024)
   263  )
   264  
   265  // peStringTable is a COFF string table.
   266  type peStringTable struct {
   267  	strings    []string
   268  	stringsLen int
   269  }
   270  
   271  // size returns size of string table t.
   272  func (t *peStringTable) size() int {
   273  	// string table starts with 4-byte length at the beginning
   274  	return t.stringsLen + 4
   275  }
   276  
   277  // add adds string str to string table t.
   278  func (t *peStringTable) add(str string) int {
   279  	off := t.size()
   280  	t.strings = append(t.strings, str)
   281  	t.stringsLen += len(str) + 1 // each string will have 0 appended to it
   282  	return off
   283  }
   284  
   285  // write writes string table t into the output file.
   286  func (t *peStringTable) write(out *OutBuf) {
   287  	out.Write32(uint32(t.size()))
   288  	for _, s := range t.strings {
   289  		out.WriteString(s)
   290  		out.Write8(0)
   291  	}
   292  }
   293  
   294  // peSection represents section from COFF section table.
   295  type peSection struct {
   296  	name                 string
   297  	shortName            string
   298  	index                int // one-based index into the Section Table
   299  	virtualSize          uint32
   300  	virtualAddress       uint32
   301  	sizeOfRawData        uint32
   302  	pointerToRawData     uint32
   303  	pointerToRelocations uint32
   304  	numberOfRelocations  uint16
   305  	characteristics      uint32
   306  }
   307  
   308  // checkOffset verifies COFF section sect offset in the file.
   309  func (sect *peSection) checkOffset(off int64) {
   310  	if off != int64(sect.pointerToRawData) {
   311  		Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(off))
   312  		errorexit()
   313  	}
   314  }
   315  
   316  // checkSegment verifies COFF section sect matches address
   317  // and file offset provided in segment seg.
   318  func (sect *peSection) checkSegment(seg *sym.Segment) {
   319  	if seg.Vaddr-PEBASE != uint64(sect.virtualAddress) {
   320  		Errorf(nil, "%s.VirtualAddress = %#x, want %#x", sect.name, uint64(int64(sect.virtualAddress)), uint64(int64(seg.Vaddr-PEBASE)))
   321  		errorexit()
   322  	}
   323  	if seg.Fileoff != uint64(sect.pointerToRawData) {
   324  		Errorf(nil, "%s.PointerToRawData = %#x, want %#x", sect.name, uint64(int64(sect.pointerToRawData)), uint64(int64(seg.Fileoff)))
   325  		errorexit()
   326  	}
   327  }
   328  
   329  // pad adds zeros to the section sect. It writes as many bytes
   330  // as necessary to make section sect.SizeOfRawData bytes long.
   331  // It assumes that n bytes are already written to the file.
   332  func (sect *peSection) pad(out *OutBuf, n uint32) {
   333  	out.WriteStringN("", int(sect.sizeOfRawData-n))
   334  }
   335  
   336  // write writes COFF section sect into the output file.
   337  func (sect *peSection) write(out *OutBuf, linkmode LinkMode) error {
   338  	h := pe.SectionHeader32{
   339  		VirtualSize:          sect.virtualSize,
   340  		SizeOfRawData:        sect.sizeOfRawData,
   341  		PointerToRawData:     sect.pointerToRawData,
   342  		PointerToRelocations: sect.pointerToRelocations,
   343  		NumberOfRelocations:  sect.numberOfRelocations,
   344  		Characteristics:      sect.characteristics,
   345  	}
   346  	if linkmode != LinkExternal {
   347  		h.VirtualAddress = sect.virtualAddress
   348  	}
   349  	copy(h.Name[:], sect.shortName)
   350  	return binary.Write(out, binary.LittleEndian, h)
   351  }
   352  
   353  // emitRelocations emits the relocation entries for the sect.
   354  // The actual relocations are emitted by relocfn.
   355  // This updates the corresponding PE section table entry
   356  // with the relocation offset and count.
   357  func (sect *peSection) emitRelocations(out *OutBuf, relocfn func() int) {
   358  	sect.pointerToRelocations = uint32(out.Offset())
   359  	// first entry: extended relocs
   360  	out.Write32(0) // placeholder for number of relocation + 1
   361  	out.Write32(0)
   362  	out.Write16(0)
   363  
   364  	n := relocfn() + 1
   365  
   366  	cpos := out.Offset()
   367  	out.SeekSet(int64(sect.pointerToRelocations))
   368  	out.Write32(uint32(n))
   369  	out.SeekSet(cpos)
   370  	if n > 0x10000 {
   371  		n = 0x10000
   372  		sect.characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
   373  	} else {
   374  		sect.pointerToRelocations += 10 // skip the extend reloc entry
   375  	}
   376  	sect.numberOfRelocations = uint16(n - 1)
   377  }
   378  
   379  // peFile is used to build COFF file.
   380  type peFile struct {
   381  	sections       []*peSection
   382  	stringTable    peStringTable
   383  	textSect       *peSection
   384  	rdataSect      *peSection
   385  	dataSect       *peSection
   386  	bssSect        *peSection
   387  	ctorsSect      *peSection
   388  	nextSectOffset uint32
   389  	nextFileOffset uint32
   390  	symtabOffset   int64 // offset to the start of symbol table
   391  	symbolCount    int   // number of symbol table records written
   392  	dataDirectory  [16]pe.DataDirectory
   393  }
   394  
   395  // addSection adds section to the COFF file f.
   396  func (f *peFile) addSection(name string, sectsize int, filesize int) *peSection {
   397  	sect := &peSection{
   398  		name:             name,
   399  		shortName:        name,
   400  		index:            len(f.sections) + 1,
   401  		virtualSize:      uint32(sectsize),
   402  		virtualAddress:   f.nextSectOffset,
   403  		pointerToRawData: f.nextFileOffset,
   404  	}
   405  	f.nextSectOffset = uint32(Rnd(int64(f.nextSectOffset)+int64(sectsize), PESECTALIGN))
   406  	if filesize > 0 {
   407  		sect.sizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN))
   408  		f.nextFileOffset += sect.sizeOfRawData
   409  	}
   410  	f.sections = append(f.sections, sect)
   411  	return sect
   412  }
   413  
   414  // addDWARFSection adds DWARF section to the COFF file f.
   415  // This function is similar to addSection, but DWARF section names are
   416  // longer than 8 characters, so they need to be stored in the string table.
   417  func (f *peFile) addDWARFSection(name string, size int) *peSection {
   418  	if size == 0 {
   419  		Exitf("DWARF section %q is empty", name)
   420  	}
   421  	// DWARF section names are longer than 8 characters.
   422  	// PE format requires such names to be stored in string table,
   423  	// and section names replaced with slash (/) followed by
   424  	// correspondent string table index.
   425  	// see http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx
   426  	// for details
   427  	off := f.stringTable.add(name)
   428  	h := f.addSection(name, size, size)
   429  	h.shortName = fmt.Sprintf("/%d", off)
   430  	h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
   431  	return h
   432  }
   433  
   434  // addDWARF adds DWARF information to the COFF file f.
   435  func (f *peFile) addDWARF() {
   436  	if *FlagS { // disable symbol table
   437  		return
   438  	}
   439  	if *FlagW { // disable dwarf
   440  		return
   441  	}
   442  	for _, sect := range Segdwarf.Sections {
   443  		h := f.addDWARFSection(sect.Name, int(sect.Length))
   444  		fileoff := sect.Vaddr - Segdwarf.Vaddr + Segdwarf.Fileoff
   445  		if uint64(h.pointerToRawData) != fileoff {
   446  			Exitf("%s.PointerToRawData = %#x, want %#x", sect.Name, h.pointerToRawData, fileoff)
   447  		}
   448  	}
   449  }
   450  
   451  // addInitArray adds .ctors COFF section to the file f.
   452  func (f *peFile) addInitArray(ctxt *Link) *peSection {
   453  	// The size below was determined by the specification for array relocations,
   454  	// and by observing what GCC writes here. If the initarray section grows to
   455  	// contain more than one constructor entry, the size will need to be 8 * constructor_count.
   456  	// However, the entire Go runtime is initialized from just one function, so it is unlikely
   457  	// that this will need to grow in the future.
   458  	var size int
   459  	switch objabi.GOARCH {
   460  	default:
   461  		Exitf("peFile.addInitArray: unsupported GOARCH=%q\n", objabi.GOARCH)
   462  	case "386":
   463  		size = 4
   464  	case "amd64":
   465  		size = 8
   466  	case "arm":
   467  		size = 4
   468  	}
   469  	sect := f.addSection(".ctors", size, size)
   470  	sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
   471  	sect.sizeOfRawData = uint32(size)
   472  	ctxt.Out.SeekSet(int64(sect.pointerToRawData))
   473  	sect.checkOffset(ctxt.Out.Offset())
   474  
   475  	init_entry := ctxt.loader.Lookup(*flagEntrySymbol, 0)
   476  	addr := uint64(ctxt.loader.SymValue(init_entry)) - ctxt.loader.SymSect(init_entry).Vaddr
   477  	switch objabi.GOARCH {
   478  	case "386", "arm":
   479  		ctxt.Out.Write32(uint32(addr))
   480  	case "amd64":
   481  		ctxt.Out.Write64(addr)
   482  	}
   483  	return sect
   484  }
   485  
   486  // emitRelocations emits relocation entries for go.o in external linking.
   487  func (f *peFile) emitRelocations(ctxt *Link) {
   488  	for ctxt.Out.Offset()&7 != 0 {
   489  		ctxt.Out.Write8(0)
   490  	}
   491  
   492  	ldr := ctxt.loader
   493  
   494  	// relocsect relocates symbols from first in section sect, and returns
   495  	// the total number of relocations emitted.
   496  	relocsect := func(sect *sym.Section, syms []loader.Sym, base uint64) int {
   497  		// If main section has no bits, nothing to relocate.
   498  		if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
   499  			return 0
   500  		}
   501  		nrelocs := 0
   502  		sect.Reloff = uint64(ctxt.Out.Offset())
   503  		for i, s := range syms {
   504  			if !ldr.AttrReachable(s) {
   505  				continue
   506  			}
   507  			if uint64(ldr.SymValue(s)) >= sect.Vaddr {
   508  				syms = syms[i:]
   509  				break
   510  			}
   511  		}
   512  		eaddr := int32(sect.Vaddr + sect.Length)
   513  		for _, s := range syms {
   514  			if !ldr.AttrReachable(s) {
   515  				continue
   516  			}
   517  			if ldr.SymValue(s) >= int64(eaddr) {
   518  				break
   519  			}
   520  			// Compute external relocations on the go, and pass to PEreloc1
   521  			// to stream out.
   522  			relocs := ldr.Relocs(s)
   523  			for ri := 0; ri < relocs.Count(); ri++ {
   524  				r := relocs.At(ri)
   525  				rr, ok := extreloc(ctxt, ldr, s, r)
   526  				if !ok {
   527  					continue
   528  				}
   529  				if rr.Xsym == 0 {
   530  					ctxt.Errorf(s, "missing xsym in relocation")
   531  					continue
   532  				}
   533  				if ldr.SymDynid(rr.Xsym) < 0 {
   534  					ctxt.Errorf(s, "reloc %d to non-coff symbol %s (outer=%s) %d", r.Type(), ldr.SymName(r.Sym()), ldr.SymName(rr.Xsym), ldr.SymType(r.Sym()))
   535  				}
   536  				if !thearch.PEreloc1(ctxt.Arch, ctxt.Out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-base)) {
   537  					ctxt.Errorf(s, "unsupported obj reloc %d/%d to %s", r.Type(), r.Siz(), ldr.SymName(r.Sym()))
   538  				}
   539  				nrelocs++
   540  			}
   541  		}
   542  		sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
   543  		return nrelocs
   544  	}
   545  
   546  	sects := []struct {
   547  		peSect *peSection
   548  		seg    *sym.Segment
   549  		syms   []loader.Sym
   550  	}{
   551  		{f.textSect, &Segtext, ctxt.Textp},
   552  		{f.rdataSect, &Segrodata, ctxt.datap},
   553  		{f.dataSect, &Segdata, ctxt.datap},
   554  	}
   555  	for _, s := range sects {
   556  		s.peSect.emitRelocations(ctxt.Out, func() int {
   557  			var n int
   558  			for _, sect := range s.seg.Sections {
   559  				n += relocsect(sect, s.syms, s.seg.Vaddr)
   560  			}
   561  			return n
   562  		})
   563  	}
   564  
   565  dwarfLoop:
   566  	for i := 0; i < len(Segdwarf.Sections); i++ {
   567  		sect := Segdwarf.Sections[i]
   568  		si := dwarfp[i]
   569  		if si.secSym() != loader.Sym(sect.Sym) ||
   570  			ldr.SymSect(si.secSym()) != sect {
   571  			panic("inconsistency between dwarfp and Segdwarf")
   572  		}
   573  		for _, pesect := range f.sections {
   574  			if sect.Name == pesect.name {
   575  				pesect.emitRelocations(ctxt.Out, func() int {
   576  					return relocsect(sect, si.syms, sect.Vaddr)
   577  				})
   578  				continue dwarfLoop
   579  			}
   580  		}
   581  		Errorf(nil, "emitRelocations: could not find %q section", sect.Name)
   582  	}
   583  
   584  	f.ctorsSect.emitRelocations(ctxt.Out, func() int {
   585  		dottext := ldr.Lookup(".text", 0)
   586  		ctxt.Out.Write32(0)
   587  		ctxt.Out.Write32(uint32(ldr.SymDynid(dottext)))
   588  		switch objabi.GOARCH {
   589  		default:
   590  			ctxt.Errorf(dottext, "unknown architecture for PE: %q\n", objabi.GOARCH)
   591  		case "386":
   592  			ctxt.Out.Write16(IMAGE_REL_I386_DIR32)
   593  		case "amd64":
   594  			ctxt.Out.Write16(IMAGE_REL_AMD64_ADDR64)
   595  		case "arm":
   596  			ctxt.Out.Write16(IMAGE_REL_ARM_ADDR32)
   597  		}
   598  		return 1
   599  	})
   600  }
   601  
   602  // writeSymbol appends symbol s to file f symbol table.
   603  // It also sets s.Dynid to written symbol number.
   604  func (f *peFile) writeSymbol(out *OutBuf, ldr *loader.Loader, s loader.Sym, name string, value int64, sectidx int, typ uint16, class uint8) {
   605  	if len(name) > 8 {
   606  		out.Write32(0)
   607  		out.Write32(uint32(f.stringTable.add(name)))
   608  	} else {
   609  		out.WriteStringN(name, 8)
   610  	}
   611  	out.Write32(uint32(value))
   612  	out.Write16(uint16(sectidx))
   613  	out.Write16(typ)
   614  	out.Write8(class)
   615  	out.Write8(0) // no aux entries
   616  
   617  	ldr.SetSymDynid(s, int32(f.symbolCount))
   618  
   619  	f.symbolCount++
   620  }
   621  
   622  // mapToPESection searches peFile f for s symbol's location.
   623  // It returns PE section index, and offset within that section.
   624  func (f *peFile) mapToPESection(ldr *loader.Loader, s loader.Sym, linkmode LinkMode) (pesectidx int, offset int64, err error) {
   625  	sect := ldr.SymSect(s)
   626  	if sect == nil {
   627  		return 0, 0, fmt.Errorf("could not map %s symbol with no section", ldr.SymName(s))
   628  	}
   629  	if sect.Seg == &Segtext {
   630  		return f.textSect.index, int64(uint64(ldr.SymValue(s)) - Segtext.Vaddr), nil
   631  	}
   632  	if sect.Seg == &Segrodata {
   633  		return f.rdataSect.index, int64(uint64(ldr.SymValue(s)) - Segrodata.Vaddr), nil
   634  	}
   635  	if sect.Seg != &Segdata {
   636  		return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .rdata or .data section", ldr.SymName(s))
   637  	}
   638  	v := uint64(ldr.SymValue(s)) - Segdata.Vaddr
   639  	if linkmode != LinkExternal {
   640  		return f.dataSect.index, int64(v), nil
   641  	}
   642  	if ldr.SymType(s) == sym.SDATA {
   643  		return f.dataSect.index, int64(v), nil
   644  	}
   645  	// Note: although address of runtime.edata (type sym.SDATA) is at the start of .bss section
   646  	// it still belongs to the .data section, not the .bss section.
   647  	if v < Segdata.Filelen {
   648  		return f.dataSect.index, int64(v), nil
   649  	}
   650  	return f.bssSect.index, int64(v - Segdata.Filelen), nil
   651  }
   652  
   653  // writeSymbols writes all COFF symbol table records.
   654  func (f *peFile) writeSymbols(ctxt *Link) {
   655  	ldr := ctxt.loader
   656  	addsym := func(s loader.Sym) {
   657  		t := ldr.SymType(s)
   658  		if ldr.SymSect(s) == nil && t != sym.SDYNIMPORT && t != sym.SHOSTOBJ && t != sym.SUNDEFEXT {
   659  			return
   660  		}
   661  
   662  		name := ldr.SymName(s)
   663  
   664  		// Only windows/386 requires underscore prefix on external symbols.
   665  		if ctxt.Is386() && ctxt.IsExternal() &&
   666  			(t == sym.SHOSTOBJ || t == sym.SUNDEFEXT || ldr.AttrCgoExport(s)) {
   667  			name = "_" + name
   668  		}
   669  
   670  		var peSymType uint16
   671  		if ctxt.IsExternal() {
   672  			peSymType = IMAGE_SYM_TYPE_NULL
   673  		} else {
   674  			// TODO: fix IMAGE_SYM_DTYPE_ARRAY value and use following expression, instead of 0x0308
   675  			// peSymType = IMAGE_SYM_DTYPE_ARRAY<<8 + IMAGE_SYM_TYPE_STRUCT
   676  			peSymType = 0x0308 // "array of structs"
   677  		}
   678  		sect, value, err := f.mapToPESection(ldr, s, ctxt.LinkMode)
   679  		if err != nil {
   680  			if t == sym.SDYNIMPORT || t == sym.SHOSTOBJ || t == sym.SUNDEFEXT {
   681  				peSymType = IMAGE_SYM_DTYPE_FUNCTION
   682  			} else {
   683  				ctxt.Errorf(s, "addpesym: %v", err)
   684  			}
   685  		}
   686  		class := IMAGE_SYM_CLASS_EXTERNAL
   687  		if ldr.IsFileLocal(s) || ldr.AttrVisibilityHidden(s) || ldr.AttrLocal(s) {
   688  			class = IMAGE_SYM_CLASS_STATIC
   689  		}
   690  		f.writeSymbol(ctxt.Out, ldr, s, name, value, sect, peSymType, uint8(class))
   691  	}
   692  
   693  	if ctxt.LinkMode == LinkExternal {
   694  		// Include section symbols as external, because
   695  		// .ctors and .debug_* section relocations refer to it.
   696  		for _, pesect := range f.sections {
   697  			s := ldr.LookupOrCreateSym(pesect.name, 0)
   698  			f.writeSymbol(ctxt.Out, ldr, s, pesect.name, 0, pesect.index, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC)
   699  		}
   700  	}
   701  
   702  	// Add special runtime.text and runtime.etext symbols.
   703  	s := ldr.Lookup("runtime.text", 0)
   704  	if ldr.SymType(s) == sym.STEXT {
   705  		addsym(s)
   706  	}
   707  	s = ldr.Lookup("runtime.etext", 0)
   708  	if ldr.SymType(s) == sym.STEXT {
   709  		addsym(s)
   710  	}
   711  
   712  	// Add text symbols.
   713  	for _, s := range ctxt.Textp {
   714  		addsym(s)
   715  	}
   716  
   717  	shouldBeInSymbolTable := func(s loader.Sym) bool {
   718  		if ldr.AttrNotInSymbolTable(s) {
   719  			return false
   720  		}
   721  		name := ldr.RawSymName(s) // TODO: try not to read the name
   722  		if name == "" || name[0] == '.' {
   723  			return false
   724  		}
   725  		return true
   726  	}
   727  
   728  	// Add data symbols and external references.
   729  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
   730  		if !ldr.AttrReachable(s) {
   731  			continue
   732  		}
   733  		t := ldr.SymType(s)
   734  		if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
   735  			if t == sym.STLSBSS {
   736  				continue
   737  			}
   738  			if !shouldBeInSymbolTable(s) {
   739  				continue
   740  			}
   741  			addsym(s)
   742  		}
   743  
   744  		switch t {
   745  		case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
   746  			addsym(s)
   747  		}
   748  	}
   749  }
   750  
   751  // writeSymbolTableAndStringTable writes out symbol and string tables for peFile f.
   752  func (f *peFile) writeSymbolTableAndStringTable(ctxt *Link) {
   753  	f.symtabOffset = ctxt.Out.Offset()
   754  
   755  	// write COFF symbol table
   756  	if !*FlagS || ctxt.LinkMode == LinkExternal {
   757  		f.writeSymbols(ctxt)
   758  	}
   759  
   760  	// update COFF file header and section table
   761  	size := f.stringTable.size() + 18*f.symbolCount
   762  	var h *peSection
   763  	if ctxt.LinkMode != LinkExternal {
   764  		// We do not really need .symtab for go.o, and if we have one, ld
   765  		// will also include it in the exe, and that will confuse windows.
   766  		h = f.addSection(".symtab", size, size)
   767  		h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
   768  		h.checkOffset(f.symtabOffset)
   769  	}
   770  
   771  	// write COFF string table
   772  	f.stringTable.write(ctxt.Out)
   773  	if ctxt.LinkMode != LinkExternal {
   774  		h.pad(ctxt.Out, uint32(size))
   775  	}
   776  }
   777  
   778  // writeFileHeader writes COFF file header for peFile f.
   779  func (f *peFile) writeFileHeader(ctxt *Link) {
   780  	var fh pe.FileHeader
   781  
   782  	switch ctxt.Arch.Family {
   783  	default:
   784  		Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
   785  	case sys.AMD64:
   786  		fh.Machine = pe.IMAGE_FILE_MACHINE_AMD64
   787  	case sys.I386:
   788  		fh.Machine = pe.IMAGE_FILE_MACHINE_I386
   789  	case sys.ARM:
   790  		fh.Machine = pe.IMAGE_FILE_MACHINE_ARMNT
   791  	}
   792  
   793  	fh.NumberOfSections = uint16(len(f.sections))
   794  
   795  	// Being able to produce identical output for identical input is
   796  	// much more beneficial than having build timestamp in the header.
   797  	fh.TimeDateStamp = 0
   798  
   799  	if ctxt.LinkMode == LinkExternal {
   800  		fh.Characteristics = pe.IMAGE_FILE_LINE_NUMS_STRIPPED
   801  	} else {
   802  		fh.Characteristics = pe.IMAGE_FILE_EXECUTABLE_IMAGE | pe.IMAGE_FILE_DEBUG_STRIPPED
   803  		switch ctxt.Arch.Family {
   804  		case sys.AMD64, sys.I386:
   805  			if ctxt.BuildMode != BuildModePIE {
   806  				fh.Characteristics |= pe.IMAGE_FILE_RELOCS_STRIPPED
   807  			}
   808  		}
   809  	}
   810  	if pe64 != 0 {
   811  		var oh64 pe.OptionalHeader64
   812  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
   813  		fh.Characteristics |= pe.IMAGE_FILE_LARGE_ADDRESS_AWARE
   814  	} else {
   815  		var oh pe.OptionalHeader32
   816  		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
   817  		fh.Characteristics |= pe.IMAGE_FILE_32BIT_MACHINE
   818  	}
   819  
   820  	fh.PointerToSymbolTable = uint32(f.symtabOffset)
   821  	fh.NumberOfSymbols = uint32(f.symbolCount)
   822  
   823  	binary.Write(ctxt.Out, binary.LittleEndian, &fh)
   824  }
   825  
   826  // writeOptionalHeader writes COFF optional header for peFile f.
   827  func (f *peFile) writeOptionalHeader(ctxt *Link) {
   828  	var oh pe.OptionalHeader32
   829  	var oh64 pe.OptionalHeader64
   830  
   831  	if pe64 != 0 {
   832  		oh64.Magic = 0x20b // PE32+
   833  	} else {
   834  		oh.Magic = 0x10b // PE32
   835  		oh.BaseOfData = f.dataSect.virtualAddress
   836  	}
   837  
   838  	// Fill out both oh64 and oh. We only use one. Oh well.
   839  	oh64.MajorLinkerVersion = 3
   840  	oh.MajorLinkerVersion = 3
   841  	oh64.MinorLinkerVersion = 0
   842  	oh.MinorLinkerVersion = 0
   843  	oh64.SizeOfCode = f.textSect.sizeOfRawData
   844  	oh.SizeOfCode = f.textSect.sizeOfRawData
   845  	oh64.SizeOfInitializedData = f.dataSect.sizeOfRawData
   846  	oh.SizeOfInitializedData = f.dataSect.sizeOfRawData
   847  	oh64.SizeOfUninitializedData = 0
   848  	oh.SizeOfUninitializedData = 0
   849  	if ctxt.LinkMode != LinkExternal {
   850  		oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
   851  		oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
   852  	}
   853  	oh64.BaseOfCode = f.textSect.virtualAddress
   854  	oh.BaseOfCode = f.textSect.virtualAddress
   855  	oh64.ImageBase = PEBASE
   856  	oh.ImageBase = PEBASE
   857  	oh64.SectionAlignment = uint32(PESECTALIGN)
   858  	oh.SectionAlignment = uint32(PESECTALIGN)
   859  	oh64.FileAlignment = uint32(PEFILEALIGN)
   860  	oh.FileAlignment = uint32(PEFILEALIGN)
   861  	oh64.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
   862  	oh.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
   863  	oh64.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
   864  	oh.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
   865  	oh64.MajorImageVersion = 1
   866  	oh.MajorImageVersion = 1
   867  	oh64.MinorImageVersion = 0
   868  	oh.MinorImageVersion = 0
   869  	oh64.MajorSubsystemVersion = PeMinimumTargetMajorVersion
   870  	oh.MajorSubsystemVersion = PeMinimumTargetMajorVersion
   871  	oh64.MinorSubsystemVersion = PeMinimumTargetMinorVersion
   872  	oh.MinorSubsystemVersion = PeMinimumTargetMinorVersion
   873  	oh64.SizeOfImage = f.nextSectOffset
   874  	oh.SizeOfImage = f.nextSectOffset
   875  	oh64.SizeOfHeaders = uint32(PEFILEHEADR)
   876  	oh.SizeOfHeaders = uint32(PEFILEHEADR)
   877  	if windowsgui {
   878  		oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
   879  		oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
   880  	} else {
   881  		oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
   882  		oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
   883  	}
   884  
   885  	// Mark as having awareness of terminal services, to avoid ancient compatibility hacks.
   886  	oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
   887  	oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
   888  
   889  	// Enable DEP
   890  	oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
   891  	oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
   892  
   893  	// The DLL can be relocated at load time.
   894  	switch ctxt.Arch.Family {
   895  	case sys.AMD64, sys.I386:
   896  		if ctxt.BuildMode == BuildModePIE {
   897  			oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
   898  			oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
   899  		}
   900  	case sys.ARM:
   901  		oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
   902  		oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
   903  	}
   904  
   905  	// Image can handle a high entropy 64-bit virtual address space.
   906  	if ctxt.BuildMode == BuildModePIE {
   907  		oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
   908  	}
   909  
   910  	// Disable stack growth as we don't want Windows to
   911  	// fiddle with the thread stack limits, which we set
   912  	// ourselves to circumvent the stack checks in the
   913  	// Windows exception dispatcher.
   914  	// Commit size must be strictly less than reserve
   915  	// size otherwise reserve will be rounded up to a
   916  	// larger size, as verified with VMMap.
   917  
   918  	// On 64-bit, we always reserve 2MB stacks. "Pure" Go code is
   919  	// okay with much smaller stacks, but the syscall package
   920  	// makes it easy to call into arbitrary C code without cgo,
   921  	// and system calls even in "pure" Go code are actually C
   922  	// calls that may need more stack than we think.
   923  	//
   924  	// The default stack reserve size directly affects only the main
   925  	// thread, ctrlhandler thread, and profileloop thread. For
   926  	// these, it must be greater than the stack size assumed by
   927  	// externalthreadhandler.
   928  	//
   929  	// For other threads, the runtime explicitly asks the kernel
   930  	// to use the default stack size so that all stacks are
   931  	// consistent.
   932  	//
   933  	// At thread start, in minit, the runtime queries the OS for
   934  	// the actual stack bounds so that the stack size doesn't need
   935  	// to be hard-coded into the runtime.
   936  	oh64.SizeOfStackReserve = 0x00200000
   937  	if !iscgo {
   938  		oh64.SizeOfStackCommit = 0x00001000
   939  	} else {
   940  		// TODO(brainman): Maybe remove optional header writing altogether for cgo.
   941  		// For cgo it is the external linker that is building final executable.
   942  		// And it probably does not use any information stored in optional header.
   943  		oh64.SizeOfStackCommit = 0x00200000 - 0x2000 // account for 2 guard pages
   944  	}
   945  
   946  	oh.SizeOfStackReserve = 0x00100000
   947  	if !iscgo {
   948  		oh.SizeOfStackCommit = 0x00001000
   949  	} else {
   950  		oh.SizeOfStackCommit = 0x00100000 - 0x2000 // account for 2 guard pages
   951  	}
   952  
   953  	oh64.SizeOfHeapReserve = 0x00100000
   954  	oh.SizeOfHeapReserve = 0x00100000
   955  	oh64.SizeOfHeapCommit = 0x00001000
   956  	oh.SizeOfHeapCommit = 0x00001000
   957  	oh64.NumberOfRvaAndSizes = 16
   958  	oh.NumberOfRvaAndSizes = 16
   959  
   960  	if pe64 != 0 {
   961  		oh64.DataDirectory = f.dataDirectory
   962  	} else {
   963  		oh.DataDirectory = f.dataDirectory
   964  	}
   965  
   966  	if pe64 != 0 {
   967  		binary.Write(ctxt.Out, binary.LittleEndian, &oh64)
   968  	} else {
   969  		binary.Write(ctxt.Out, binary.LittleEndian, &oh)
   970  	}
   971  }
   972  
   973  var pefile peFile
   974  
   975  func Peinit(ctxt *Link) {
   976  	var l int
   977  
   978  	switch ctxt.Arch.Family {
   979  	// 64-bit architectures
   980  	case sys.AMD64:
   981  		pe64 = 1
   982  		var oh64 pe.OptionalHeader64
   983  		l = binary.Size(&oh64)
   984  
   985  	// 32-bit architectures
   986  	default:
   987  		var oh pe.OptionalHeader32
   988  		l = binary.Size(&oh)
   989  
   990  	}
   991  
   992  	if ctxt.LinkMode == LinkExternal {
   993  		// .rdata section will contain "masks" and "shifts" symbols, and they
   994  		// need to be aligned to 16-bytes. So make all sections aligned
   995  		// to 32-byte and mark them all IMAGE_SCN_ALIGN_32BYTES so external
   996  		// linker will honour that requirement.
   997  		PESECTALIGN = 32
   998  		PEFILEALIGN = 0
   999  	}
  1000  
  1001  	var sh [16]pe.SectionHeader32
  1002  	var fh pe.FileHeader
  1003  	PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
  1004  	if ctxt.LinkMode != LinkExternal {
  1005  		PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
  1006  	} else {
  1007  		PESECTHEADR = 0
  1008  	}
  1009  	pefile.nextSectOffset = uint32(PESECTHEADR)
  1010  	pefile.nextFileOffset = uint32(PEFILEHEADR)
  1011  
  1012  	if ctxt.LinkMode == LinkInternal {
  1013  		// some mingw libs depend on this symbol, for example, FindPESectionByName
  1014  		for _, name := range [2]string{"__image_base__", "_image_base__"} {
  1015  			sb := ctxt.loader.CreateSymForUpdate(name, 0)
  1016  			sb.SetType(sym.SDATA)
  1017  			sb.SetValue(PEBASE)
  1018  			ctxt.loader.SetAttrSpecial(sb.Sym(), true)
  1019  			ctxt.loader.SetAttrLocal(sb.Sym(), true)
  1020  		}
  1021  	}
  1022  
  1023  	HEADR = PEFILEHEADR
  1024  	if *FlagTextAddr == -1 {
  1025  		*FlagTextAddr = PEBASE + int64(PESECTHEADR)
  1026  	}
  1027  	if *FlagRound == -1 {
  1028  		*FlagRound = int(PESECTALIGN)
  1029  	}
  1030  }
  1031  
  1032  func pewrite(ctxt *Link) {
  1033  	ctxt.Out.SeekSet(0)
  1034  	if ctxt.LinkMode != LinkExternal {
  1035  		ctxt.Out.Write(dosstub)
  1036  		ctxt.Out.WriteStringN("PE", 4)
  1037  	}
  1038  
  1039  	pefile.writeFileHeader(ctxt)
  1040  
  1041  	pefile.writeOptionalHeader(ctxt)
  1042  
  1043  	for _, sect := range pefile.sections {
  1044  		sect.write(ctxt.Out, ctxt.LinkMode)
  1045  	}
  1046  }
  1047  
  1048  func strput(out *OutBuf, s string) {
  1049  	out.WriteString(s)
  1050  	out.Write8(0)
  1051  	// string must be padded to even size
  1052  	if (len(s)+1)%2 != 0 {
  1053  		out.Write8(0)
  1054  	}
  1055  }
  1056  
  1057  func initdynimport(ctxt *Link) *Dll {
  1058  	ldr := ctxt.loader
  1059  	var d *Dll
  1060  
  1061  	dr = nil
  1062  	var m *Imp
  1063  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
  1064  		if !ldr.AttrReachable(s) || ldr.SymType(s) != sym.SDYNIMPORT {
  1065  			continue
  1066  		}
  1067  		dynlib := ldr.SymDynimplib(s)
  1068  		for d = dr; d != nil; d = d.next {
  1069  			if d.name == dynlib {
  1070  				m = new(Imp)
  1071  				break
  1072  			}
  1073  		}
  1074  
  1075  		if d == nil {
  1076  			d = new(Dll)
  1077  			d.name = dynlib
  1078  			d.next = dr
  1079  			dr = d
  1080  			m = new(Imp)
  1081  		}
  1082  
  1083  		// Because external link requires properly stdcall decorated name,
  1084  		// all external symbols in runtime use %n to denote that the number
  1085  		// of uinptrs this function consumes. Store the argsize and discard
  1086  		// the %n suffix if any.
  1087  		m.argsize = -1
  1088  		extName := ldr.SymExtname(s)
  1089  		if i := strings.IndexByte(extName, '%'); i >= 0 {
  1090  			var err error
  1091  			m.argsize, err = strconv.Atoi(extName[i+1:])
  1092  			if err != nil {
  1093  				ctxt.Errorf(s, "failed to parse stdcall decoration: %v", err)
  1094  			}
  1095  			m.argsize *= ctxt.Arch.PtrSize
  1096  			ldr.SetSymExtname(s, extName[:i])
  1097  		}
  1098  
  1099  		m.s = s
  1100  		m.next = d.ms
  1101  		d.ms = m
  1102  	}
  1103  
  1104  	if ctxt.IsExternal() {
  1105  		// Add real symbol name
  1106  		for d := dr; d != nil; d = d.next {
  1107  			for m = d.ms; m != nil; m = m.next {
  1108  				sb := ldr.MakeSymbolUpdater(m.s)
  1109  				sb.SetType(sym.SDATA)
  1110  				sb.Grow(int64(ctxt.Arch.PtrSize))
  1111  				dynName := sb.Extname()
  1112  				// only windows/386 requires stdcall decoration
  1113  				if ctxt.Is386() && m.argsize >= 0 {
  1114  					dynName += fmt.Sprintf("@%d", m.argsize)
  1115  				}
  1116  				dynSym := ldr.CreateSymForUpdate(dynName, 0)
  1117  				dynSym.SetType(sym.SHOSTOBJ)
  1118  				r, _ := sb.AddRel(objabi.R_ADDR)
  1119  				r.SetSym(dynSym.Sym())
  1120  				r.SetSiz(uint8(ctxt.Arch.PtrSize))
  1121  			}
  1122  		}
  1123  	} else {
  1124  		dynamic := ldr.CreateSymForUpdate(".windynamic", 0)
  1125  		dynamic.SetType(sym.SWINDOWS)
  1126  		for d := dr; d != nil; d = d.next {
  1127  			for m = d.ms; m != nil; m = m.next {
  1128  				sb := ldr.MakeSymbolUpdater(m.s)
  1129  				sb.SetType(sym.SWINDOWS)
  1130  				sb.SetValue(dynamic.Size())
  1131  				dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
  1132  				dynamic.AddInteriorSym(m.s)
  1133  			}
  1134  
  1135  			dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
  1136  		}
  1137  	}
  1138  
  1139  	return dr
  1140  }
  1141  
  1142  // peimporteddlls returns the gcc command line argument to link all imported
  1143  // DLLs.
  1144  func peimporteddlls() []string {
  1145  	var dlls []string
  1146  
  1147  	for d := dr; d != nil; d = d.next {
  1148  		dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
  1149  	}
  1150  
  1151  	return dlls
  1152  }
  1153  
  1154  func addimports(ctxt *Link, datsect *peSection) {
  1155  	ldr := ctxt.loader
  1156  	startoff := ctxt.Out.Offset()
  1157  	dynamic := ldr.LookupOrCreateSym(".windynamic", 0)
  1158  
  1159  	// skip import descriptor table (will write it later)
  1160  	n := uint64(0)
  1161  
  1162  	for d := dr; d != nil; d = d.next {
  1163  		n++
  1164  	}
  1165  	ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
  1166  
  1167  	// write dll names
  1168  	for d := dr; d != nil; d = d.next {
  1169  		d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff)
  1170  		strput(ctxt.Out, d.name)
  1171  	}
  1172  
  1173  	// write function names
  1174  	for d := dr; d != nil; d = d.next {
  1175  		for m := d.ms; m != nil; m = m.next {
  1176  			m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
  1177  			ctxt.Out.Write16(0) // hint
  1178  			strput(ctxt.Out, ldr.SymExtname(m.s))
  1179  		}
  1180  	}
  1181  
  1182  	// write OriginalFirstThunks
  1183  	oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff)
  1184  
  1185  	n = uint64(ctxt.Out.Offset())
  1186  	for d := dr; d != nil; d = d.next {
  1187  		d.thunkoff = uint64(ctxt.Out.Offset()) - n
  1188  		for m := d.ms; m != nil; m = m.next {
  1189  			if pe64 != 0 {
  1190  				ctxt.Out.Write64(m.off)
  1191  			} else {
  1192  				ctxt.Out.Write32(uint32(m.off))
  1193  			}
  1194  		}
  1195  
  1196  		if pe64 != 0 {
  1197  			ctxt.Out.Write64(0)
  1198  		} else {
  1199  			ctxt.Out.Write32(0)
  1200  		}
  1201  	}
  1202  
  1203  	// add pe section and pad it at the end
  1204  	n = uint64(ctxt.Out.Offset()) - uint64(startoff)
  1205  
  1206  	isect := pefile.addSection(".idata", int(n), int(n))
  1207  	isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1208  	isect.checkOffset(startoff)
  1209  	isect.pad(ctxt.Out, uint32(n))
  1210  	endoff := ctxt.Out.Offset()
  1211  
  1212  	// write FirstThunks (allocated in .data section)
  1213  	ftbase := uint64(ldr.SymValue(dynamic)) - uint64(datsect.virtualAddress) - PEBASE
  1214  
  1215  	ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase))
  1216  	for d := dr; d != nil; d = d.next {
  1217  		for m := d.ms; m != nil; m = m.next {
  1218  			if pe64 != 0 {
  1219  				ctxt.Out.Write64(m.off)
  1220  			} else {
  1221  				ctxt.Out.Write32(uint32(m.off))
  1222  			}
  1223  		}
  1224  
  1225  		if pe64 != 0 {
  1226  			ctxt.Out.Write64(0)
  1227  		} else {
  1228  			ctxt.Out.Write32(0)
  1229  		}
  1230  	}
  1231  
  1232  	// finally write import descriptor table
  1233  	out := ctxt.Out
  1234  	out.SeekSet(startoff)
  1235  
  1236  	for d := dr; d != nil; d = d.next {
  1237  		out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff))
  1238  		out.Write32(0)
  1239  		out.Write32(0)
  1240  		out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff))
  1241  		out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff))
  1242  	}
  1243  
  1244  	out.Write32(0) //end
  1245  	out.Write32(0)
  1246  	out.Write32(0)
  1247  	out.Write32(0)
  1248  	out.Write32(0)
  1249  
  1250  	// update data directory
  1251  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
  1252  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
  1253  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(ldr.SymValue(dynamic) - PEBASE)
  1254  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(ldr.SymSize(dynamic))
  1255  
  1256  	out.SeekSet(endoff)
  1257  }
  1258  
  1259  func initdynexport(ctxt *Link) {
  1260  	ldr := ctxt.loader
  1261  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
  1262  		if !ldr.AttrReachable(s) || !ldr.AttrCgoExportDynamic(s) {
  1263  			continue
  1264  		}
  1265  		if len(dexport)+1 > cap(dexport) {
  1266  			ctxt.Errorf(s, "pe dynexport table is full")
  1267  			errorexit()
  1268  		}
  1269  
  1270  		dexport = append(dexport, s)
  1271  	}
  1272  
  1273  	sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) })
  1274  }
  1275  
  1276  func addexports(ctxt *Link) {
  1277  	ldr := ctxt.loader
  1278  	var e IMAGE_EXPORT_DIRECTORY
  1279  
  1280  	nexport := len(dexport)
  1281  	size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
  1282  	for _, s := range dexport {
  1283  		size += len(ldr.SymExtname(s)) + 1
  1284  	}
  1285  
  1286  	if nexport == 0 {
  1287  		return
  1288  	}
  1289  
  1290  	sect := pefile.addSection(".edata", size, size)
  1291  	sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
  1292  	sect.checkOffset(ctxt.Out.Offset())
  1293  	va := int(sect.virtualAddress)
  1294  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
  1295  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
  1296  
  1297  	vaName := va + binary.Size(&e) + nexport*4
  1298  	vaAddr := va + binary.Size(&e)
  1299  	vaNa := va + binary.Size(&e) + nexport*8
  1300  
  1301  	e.Characteristics = 0
  1302  	e.MajorVersion = 0
  1303  	e.MinorVersion = 0
  1304  	e.NumberOfFunctions = uint32(nexport)
  1305  	e.NumberOfNames = uint32(nexport)
  1306  	e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
  1307  	e.Base = 1
  1308  	e.AddressOfFunctions = uint32(vaAddr)
  1309  	e.AddressOfNames = uint32(vaName)
  1310  	e.AddressOfNameOrdinals = uint32(vaNa)
  1311  
  1312  	out := ctxt.Out
  1313  
  1314  	// put IMAGE_EXPORT_DIRECTORY
  1315  	binary.Write(out, binary.LittleEndian, &e)
  1316  
  1317  	// put EXPORT Address Table
  1318  	for _, s := range dexport {
  1319  		out.Write32(uint32(ldr.SymValue(s) - PEBASE))
  1320  	}
  1321  
  1322  	// put EXPORT Name Pointer Table
  1323  	v := int(e.Name + uint32(len(*flagOutfile)) + 1)
  1324  
  1325  	for _, s := range dexport {
  1326  		out.Write32(uint32(v))
  1327  		v += len(ldr.SymExtname(s)) + 1
  1328  	}
  1329  
  1330  	// put EXPORT Ordinal Table
  1331  	for i := 0; i < nexport; i++ {
  1332  		out.Write16(uint16(i))
  1333  	}
  1334  
  1335  	// put Names
  1336  	out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
  1337  
  1338  	for _, s := range dexport {
  1339  		name := ldr.SymExtname(s)
  1340  		out.WriteStringN(name, len(name)+1)
  1341  	}
  1342  	sect.pad(out, uint32(size))
  1343  }
  1344  
  1345  // peBaseRelocEntry represents a single relocation entry.
  1346  type peBaseRelocEntry struct {
  1347  	typeOff uint16
  1348  }
  1349  
  1350  // peBaseRelocBlock represents a Base Relocation Block. A block
  1351  // is a collection of relocation entries in a page, where each
  1352  // entry describes a single relocation.
  1353  // The block page RVA (Relative Virtual Address) is the index
  1354  // into peBaseRelocTable.blocks.
  1355  type peBaseRelocBlock struct {
  1356  	entries []peBaseRelocEntry
  1357  }
  1358  
  1359  // pePages is a type used to store the list of pages for which there
  1360  // are base relocation blocks. This is defined as a type so that
  1361  // it can be sorted.
  1362  type pePages []uint32
  1363  
  1364  func (p pePages) Len() int           { return len(p) }
  1365  func (p pePages) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
  1366  func (p pePages) Less(i, j int) bool { return p[i] < p[j] }
  1367  
  1368  // A PE base relocation table is a list of blocks, where each block
  1369  // contains relocation information for a single page. The blocks
  1370  // must be emitted in order of page virtual address.
  1371  // See https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-reloc-section-image-only
  1372  type peBaseRelocTable struct {
  1373  	blocks map[uint32]peBaseRelocBlock
  1374  
  1375  	// pePages is a list of keys into blocks map.
  1376  	// It is stored separately for ease of sorting.
  1377  	pages pePages
  1378  }
  1379  
  1380  func (rt *peBaseRelocTable) init(ctxt *Link) {
  1381  	rt.blocks = make(map[uint32]peBaseRelocBlock)
  1382  }
  1383  
  1384  func (rt *peBaseRelocTable) addentry(ldr *loader.Loader, s loader.Sym, r *loader.Reloc) {
  1385  	// pageSize is the size in bytes of a page
  1386  	// described by a base relocation block.
  1387  	const pageSize = 0x1000
  1388  	const pageMask = pageSize - 1
  1389  
  1390  	addr := ldr.SymValue(s) + int64(r.Off()) - int64(PEBASE)
  1391  	page := uint32(addr &^ pageMask)
  1392  	off := uint32(addr & pageMask)
  1393  
  1394  	b, ok := rt.blocks[page]
  1395  	if !ok {
  1396  		rt.pages = append(rt.pages, page)
  1397  	}
  1398  
  1399  	e := peBaseRelocEntry{
  1400  		typeOff: uint16(off & 0xFFF),
  1401  	}
  1402  
  1403  	// Set entry type
  1404  	switch r.Siz() {
  1405  	default:
  1406  		Exitf("unsupported relocation size %d\n", r.Siz)
  1407  	case 4:
  1408  		e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12)
  1409  	case 8:
  1410  		e.typeOff |= uint16(IMAGE_REL_BASED_DIR64 << 12)
  1411  	}
  1412  
  1413  	b.entries = append(b.entries, e)
  1414  	rt.blocks[page] = b
  1415  }
  1416  
  1417  func (rt *peBaseRelocTable) write(ctxt *Link) {
  1418  	out := ctxt.Out
  1419  
  1420  	// sort the pages array
  1421  	sort.Sort(rt.pages)
  1422  
  1423  	for _, p := range rt.pages {
  1424  		b := rt.blocks[p]
  1425  		const sizeOfPEbaseRelocBlock = 8 // 2 * sizeof(uint32)
  1426  		blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2)
  1427  		out.Write32(p)
  1428  		out.Write32(blockSize)
  1429  
  1430  		for _, e := range b.entries {
  1431  			out.Write16(e.typeOff)
  1432  		}
  1433  	}
  1434  }
  1435  
  1436  func addPEBaseRelocSym(ldr *loader.Loader, s loader.Sym, rt *peBaseRelocTable) {
  1437  	relocs := ldr.Relocs(s)
  1438  	for ri := 0; ri < relocs.Count(); ri++ {
  1439  		r := relocs.At(ri)
  1440  		if r.Type() >= objabi.ElfRelocOffset {
  1441  			continue
  1442  		}
  1443  		if r.Siz() == 0 { // informational relocation
  1444  			continue
  1445  		}
  1446  		if r.Type() == objabi.R_DWARFFILEREF {
  1447  			continue
  1448  		}
  1449  		rs := r.Sym()
  1450  		rs = ldr.ResolveABIAlias(rs)
  1451  		if rs == 0 {
  1452  			continue
  1453  		}
  1454  		if !ldr.AttrReachable(s) {
  1455  			continue
  1456  		}
  1457  
  1458  		switch r.Type() {
  1459  		default:
  1460  		case objabi.R_ADDR:
  1461  			rt.addentry(ldr, s, &r)
  1462  		}
  1463  	}
  1464  }
  1465  
  1466  func addPEBaseReloc(ctxt *Link) {
  1467  	// Arm does not work without base relocation table.
  1468  	// 386 and amd64 will only require the table for BuildModePIE.
  1469  	switch ctxt.Arch.Family {
  1470  	default:
  1471  		return
  1472  	case sys.I386, sys.AMD64:
  1473  		if ctxt.BuildMode != BuildModePIE {
  1474  			return
  1475  		}
  1476  	case sys.ARM:
  1477  	}
  1478  
  1479  	var rt peBaseRelocTable
  1480  	rt.init(ctxt)
  1481  
  1482  	// Get relocation information
  1483  	ldr := ctxt.loader
  1484  	for _, s := range ctxt.Textp {
  1485  		addPEBaseRelocSym(ldr, s, &rt)
  1486  	}
  1487  	for _, s := range ctxt.datap {
  1488  		addPEBaseRelocSym(ldr, s, &rt)
  1489  	}
  1490  
  1491  	// Write relocation information
  1492  	startoff := ctxt.Out.Offset()
  1493  	rt.write(ctxt)
  1494  	size := ctxt.Out.Offset() - startoff
  1495  
  1496  	// Add a PE section and pad it at the end
  1497  	rsect := pefile.addSection(".reloc", int(size), int(size))
  1498  	rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
  1499  	rsect.checkOffset(startoff)
  1500  	rsect.pad(ctxt.Out, uint32(size))
  1501  
  1502  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
  1503  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
  1504  }
  1505  
  1506  func (ctxt *Link) dope() {
  1507  	initdynimport(ctxt)
  1508  	initdynexport(ctxt)
  1509  }
  1510  
  1511  func setpersrc(ctxt *Link, syms []loader.Sym) {
  1512  	if len(rsrcsyms) != 0 {
  1513  		Errorf(nil, "too many .rsrc sections")
  1514  	}
  1515  	rsrcsyms = syms
  1516  }
  1517  
  1518  func addpersrc(ctxt *Link) {
  1519  	if len(rsrcsyms) == 0 {
  1520  		return
  1521  	}
  1522  
  1523  	var size int64
  1524  	for _, rsrcsym := range rsrcsyms {
  1525  		size += ctxt.loader.SymSize(rsrcsym)
  1526  	}
  1527  	h := pefile.addSection(".rsrc", int(size), int(size))
  1528  	h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA
  1529  	h.checkOffset(ctxt.Out.Offset())
  1530  
  1531  	for _, rsrcsym := range rsrcsyms {
  1532  		// A split resource happens when the actual resource data and its relocations are
  1533  		// split across multiple sections, denoted by a $01 or $02 at the end of the .rsrc
  1534  		// section name.
  1535  		splitResources := strings.Contains(ctxt.loader.SymName(rsrcsym), ".rsrc$")
  1536  		relocs := ctxt.loader.Relocs(rsrcsym)
  1537  		data := ctxt.loader.Data(rsrcsym)
  1538  		for ri := 0; ri < relocs.Count(); ri++ {
  1539  			r := relocs.At(ri)
  1540  			p := data[r.Off():]
  1541  			val := uint32(int64(h.virtualAddress) + r.Add())
  1542  			if splitResources {
  1543  				// If we're a split resource section, and that section has relocation
  1544  				// symbols, then the data that it points to doesn't actually begin at
  1545  				// the virtual address listed in this current section, but rather
  1546  				// begins at the section immediately after this one. So, in order to
  1547  				// calculate the proper virtual address of the data it's pointing to,
  1548  				// we have to add the length of this section to the virtual address.
  1549  				// This works because .rsrc sections are divided into two (but not more)
  1550  				// of these sections.
  1551  				val += uint32(len(data))
  1552  			}
  1553  			binary.LittleEndian.PutUint32(p, val)
  1554  		}
  1555  		ctxt.Out.Write(data)
  1556  	}
  1557  	h.pad(ctxt.Out, uint32(size))
  1558  
  1559  	// update data directory
  1560  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
  1561  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
  1562  }
  1563  
  1564  func asmbPe(ctxt *Link) {
  1565  	switch ctxt.Arch.Family {
  1566  	default:
  1567  		Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
  1568  	case sys.AMD64, sys.I386, sys.ARM:
  1569  	}
  1570  
  1571  	t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length))
  1572  	t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
  1573  	if ctxt.LinkMode == LinkExternal {
  1574  		// some data symbols (e.g. masks) end up in the .text section, and they normally
  1575  		// expect larger alignment requirement than the default text section alignment.
  1576  		t.characteristics |= IMAGE_SCN_ALIGN_32BYTES
  1577  	}
  1578  	t.checkSegment(&Segtext)
  1579  	pefile.textSect = t
  1580  
  1581  	ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length))
  1582  	ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
  1583  	if ctxt.LinkMode == LinkExternal {
  1584  		// some data symbols (e.g. masks) end up in the .rdata section, and they normally
  1585  		// expect larger alignment requirement than the default text section alignment.
  1586  		ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
  1587  	}
  1588  	ro.checkSegment(&Segrodata)
  1589  	pefile.rdataSect = ro
  1590  
  1591  	var d *peSection
  1592  	if ctxt.LinkMode != LinkExternal {
  1593  		d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
  1594  		d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1595  		d.checkSegment(&Segdata)
  1596  		pefile.dataSect = d
  1597  	} else {
  1598  		d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
  1599  		d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1600  		d.checkSegment(&Segdata)
  1601  		pefile.dataSect = d
  1602  
  1603  		b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
  1604  		b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1605  		b.pointerToRawData = 0
  1606  		pefile.bssSect = b
  1607  	}
  1608  
  1609  	pefile.addDWARF()
  1610  
  1611  	if ctxt.LinkMode == LinkExternal {
  1612  		pefile.ctorsSect = pefile.addInitArray(ctxt)
  1613  	}
  1614  
  1615  	ctxt.Out.SeekSet(int64(pefile.nextFileOffset))
  1616  	if ctxt.LinkMode != LinkExternal {
  1617  		addimports(ctxt, d)
  1618  		addexports(ctxt)
  1619  		addPEBaseReloc(ctxt)
  1620  	}
  1621  	pefile.writeSymbolTableAndStringTable(ctxt)
  1622  	addpersrc(ctxt)
  1623  	if ctxt.LinkMode == LinkExternal {
  1624  		pefile.emitRelocations(ctxt)
  1625  	}
  1626  
  1627  	pewrite(ctxt)
  1628  }
  1629  

View as plain text