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

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

View as plain text