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

View as plain text