Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/link/internal/ld

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // PE (Portable Executable) file writing
     6  // https://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  	}
  1065  
  1066  	var sh [16]pe.SectionHeader32
  1067  	var fh pe.FileHeader
  1068  	PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
  1069  	if ctxt.LinkMode != LinkExternal {
  1070  		PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
  1071  	} else {
  1072  		PESECTHEADR = 0
  1073  	}
  1074  	pefile.nextSectOffset = uint32(PESECTHEADR)
  1075  	pefile.nextFileOffset = uint32(PEFILEHEADR)
  1076  
  1077  	if ctxt.LinkMode == LinkInternal {
  1078  		// some mingw libs depend on this symbol, for example, FindPESectionByName
  1079  		for _, name := range [2]string{"__image_base__", "_image_base__"} {
  1080  			sb := ctxt.loader.CreateSymForUpdate(name, 0)
  1081  			sb.SetType(sym.SDATA)
  1082  			sb.SetValue(PEBASE)
  1083  			ctxt.loader.SetAttrSpecial(sb.Sym(), true)
  1084  			ctxt.loader.SetAttrLocal(sb.Sym(), true)
  1085  		}
  1086  	}
  1087  
  1088  	HEADR = PEFILEHEADR
  1089  	if *FlagTextAddr == -1 {
  1090  		*FlagTextAddr = PEBASE + int64(PESECTHEADR)
  1091  	}
  1092  	if *FlagRound == -1 {
  1093  		*FlagRound = int(PESECTALIGN)
  1094  	}
  1095  }
  1096  
  1097  func pewrite(ctxt *Link) {
  1098  	ctxt.Out.SeekSet(0)
  1099  	if ctxt.LinkMode != LinkExternal {
  1100  		ctxt.Out.Write(dosstub)
  1101  		ctxt.Out.WriteStringN("PE", 4)
  1102  	}
  1103  
  1104  	pefile.writeFileHeader(ctxt)
  1105  
  1106  	pefile.writeOptionalHeader(ctxt)
  1107  
  1108  	for _, sect := range pefile.sections {
  1109  		sect.write(ctxt.Out, ctxt.LinkMode)
  1110  	}
  1111  }
  1112  
  1113  func strput(out *OutBuf, s string) {
  1114  	out.WriteString(s)
  1115  	out.Write8(0)
  1116  	// string must be padded to even size
  1117  	if (len(s)+1)%2 != 0 {
  1118  		out.Write8(0)
  1119  	}
  1120  }
  1121  
  1122  func initdynimport(ctxt *Link) *Dll {
  1123  	ldr := ctxt.loader
  1124  	var d *Dll
  1125  
  1126  	dr = nil
  1127  	var m *Imp
  1128  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
  1129  		if !ldr.AttrReachable(s) || ldr.SymType(s) != sym.SDYNIMPORT {
  1130  			continue
  1131  		}
  1132  		dynlib := ldr.SymDynimplib(s)
  1133  		for d = dr; d != nil; d = d.next {
  1134  			if d.name == dynlib {
  1135  				m = new(Imp)
  1136  				break
  1137  			}
  1138  		}
  1139  
  1140  		if d == nil {
  1141  			d = new(Dll)
  1142  			d.name = dynlib
  1143  			d.next = dr
  1144  			dr = d
  1145  			m = new(Imp)
  1146  		}
  1147  
  1148  		// Because external link requires properly stdcall decorated name,
  1149  		// all external symbols in runtime use %n to denote that the number
  1150  		// of uinptrs this function consumes. Store the argsize and discard
  1151  		// the %n suffix if any.
  1152  		m.argsize = -1
  1153  		extName := ldr.SymExtname(s)
  1154  		if i := strings.IndexByte(extName, '%'); i >= 0 {
  1155  			var err error
  1156  			m.argsize, err = strconv.Atoi(extName[i+1:])
  1157  			if err != nil {
  1158  				ctxt.Errorf(s, "failed to parse stdcall decoration: %v", err)
  1159  			}
  1160  			m.argsize *= ctxt.Arch.PtrSize
  1161  			ldr.SetSymExtname(s, extName[:i])
  1162  		}
  1163  
  1164  		m.s = s
  1165  		m.next = d.ms
  1166  		d.ms = m
  1167  	}
  1168  
  1169  	if ctxt.IsExternal() {
  1170  		// Add real symbol name
  1171  		for d := dr; d != nil; d = d.next {
  1172  			for m = d.ms; m != nil; m = m.next {
  1173  				sb := ldr.MakeSymbolUpdater(m.s)
  1174  				sb.SetType(sym.SDATA)
  1175  				sb.Grow(int64(ctxt.Arch.PtrSize))
  1176  				dynName := sb.Extname()
  1177  				// only windows/386 requires stdcall decoration
  1178  				if ctxt.Is386() && m.argsize >= 0 {
  1179  					dynName += fmt.Sprintf("@%d", m.argsize)
  1180  				}
  1181  				dynSym := ldr.CreateSymForUpdate(dynName, 0)
  1182  				dynSym.SetType(sym.SHOSTOBJ)
  1183  				r, _ := sb.AddRel(objabi.R_ADDR)
  1184  				r.SetSym(dynSym.Sym())
  1185  				r.SetSiz(uint8(ctxt.Arch.PtrSize))
  1186  			}
  1187  		}
  1188  	} else {
  1189  		dynamic := ldr.CreateSymForUpdate(".windynamic", 0)
  1190  		dynamic.SetType(sym.SWINDOWS)
  1191  		for d := dr; d != nil; d = d.next {
  1192  			for m = d.ms; m != nil; m = m.next {
  1193  				sb := ldr.MakeSymbolUpdater(m.s)
  1194  				sb.SetType(sym.SWINDOWS)
  1195  				sb.SetValue(dynamic.Size())
  1196  				dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
  1197  				dynamic.AddInteriorSym(m.s)
  1198  			}
  1199  
  1200  			dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
  1201  		}
  1202  	}
  1203  
  1204  	return dr
  1205  }
  1206  
  1207  // peimporteddlls returns the gcc command line argument to link all imported
  1208  // DLLs.
  1209  func peimporteddlls() []string {
  1210  	var dlls []string
  1211  
  1212  	for d := dr; d != nil; d = d.next {
  1213  		dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
  1214  	}
  1215  
  1216  	return dlls
  1217  }
  1218  
  1219  func addimports(ctxt *Link, datsect *peSection) {
  1220  	ldr := ctxt.loader
  1221  	startoff := ctxt.Out.Offset()
  1222  	dynamic := ldr.LookupOrCreateSym(".windynamic", 0)
  1223  
  1224  	// skip import descriptor table (will write it later)
  1225  	n := uint64(0)
  1226  
  1227  	for d := dr; d != nil; d = d.next {
  1228  		n++
  1229  	}
  1230  	ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
  1231  
  1232  	// write dll names
  1233  	for d := dr; d != nil; d = d.next {
  1234  		d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff)
  1235  		strput(ctxt.Out, d.name)
  1236  	}
  1237  
  1238  	// write function names
  1239  	for d := dr; d != nil; d = d.next {
  1240  		for m := d.ms; m != nil; m = m.next {
  1241  			m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
  1242  			ctxt.Out.Write16(0) // hint
  1243  			strput(ctxt.Out, ldr.SymExtname(m.s))
  1244  		}
  1245  	}
  1246  
  1247  	// write OriginalFirstThunks
  1248  	oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff)
  1249  
  1250  	n = uint64(ctxt.Out.Offset())
  1251  	for d := dr; d != nil; d = d.next {
  1252  		d.thunkoff = uint64(ctxt.Out.Offset()) - n
  1253  		for m := d.ms; m != nil; m = m.next {
  1254  			if pe64 != 0 {
  1255  				ctxt.Out.Write64(m.off)
  1256  			} else {
  1257  				ctxt.Out.Write32(uint32(m.off))
  1258  			}
  1259  		}
  1260  
  1261  		if pe64 != 0 {
  1262  			ctxt.Out.Write64(0)
  1263  		} else {
  1264  			ctxt.Out.Write32(0)
  1265  		}
  1266  	}
  1267  
  1268  	// add pe section and pad it at the end
  1269  	n = uint64(ctxt.Out.Offset()) - uint64(startoff)
  1270  
  1271  	isect := pefile.addSection(".idata", int(n), int(n))
  1272  	isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1273  	isect.checkOffset(startoff)
  1274  	isect.pad(ctxt.Out, uint32(n))
  1275  	endoff := ctxt.Out.Offset()
  1276  
  1277  	// write FirstThunks (allocated in .data section)
  1278  	ftbase := uint64(ldr.SymValue(dynamic)) - uint64(datsect.virtualAddress) - uint64(PEBASE)
  1279  
  1280  	ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase))
  1281  	for d := dr; d != nil; d = d.next {
  1282  		for m := d.ms; m != nil; m = m.next {
  1283  			if pe64 != 0 {
  1284  				ctxt.Out.Write64(m.off)
  1285  			} else {
  1286  				ctxt.Out.Write32(uint32(m.off))
  1287  			}
  1288  		}
  1289  
  1290  		if pe64 != 0 {
  1291  			ctxt.Out.Write64(0)
  1292  		} else {
  1293  			ctxt.Out.Write32(0)
  1294  		}
  1295  	}
  1296  
  1297  	// finally write import descriptor table
  1298  	out := ctxt.Out
  1299  	out.SeekSet(startoff)
  1300  
  1301  	for d := dr; d != nil; d = d.next {
  1302  		out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff))
  1303  		out.Write32(0)
  1304  		out.Write32(0)
  1305  		out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff))
  1306  		out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff))
  1307  	}
  1308  
  1309  	out.Write32(0) //end
  1310  	out.Write32(0)
  1311  	out.Write32(0)
  1312  	out.Write32(0)
  1313  	out.Write32(0)
  1314  
  1315  	// update data directory
  1316  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
  1317  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
  1318  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(ldr.SymValue(dynamic) - PEBASE)
  1319  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(ldr.SymSize(dynamic))
  1320  
  1321  	out.SeekSet(endoff)
  1322  }
  1323  
  1324  func initdynexport(ctxt *Link) {
  1325  	ldr := ctxt.loader
  1326  	for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
  1327  		if !ldr.AttrReachable(s) || !ldr.AttrCgoExportDynamic(s) {
  1328  			continue
  1329  		}
  1330  		if len(dexport)+1 > cap(dexport) {
  1331  			ctxt.Errorf(s, "pe dynexport table is full")
  1332  			errorexit()
  1333  		}
  1334  
  1335  		dexport = append(dexport, s)
  1336  	}
  1337  
  1338  	sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) })
  1339  }
  1340  
  1341  func addexports(ctxt *Link) {
  1342  	ldr := ctxt.loader
  1343  	var e IMAGE_EXPORT_DIRECTORY
  1344  
  1345  	nexport := len(dexport)
  1346  	size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
  1347  	for _, s := range dexport {
  1348  		size += len(ldr.SymExtname(s)) + 1
  1349  	}
  1350  
  1351  	if nexport == 0 {
  1352  		return
  1353  	}
  1354  
  1355  	sect := pefile.addSection(".edata", size, size)
  1356  	sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
  1357  	sect.checkOffset(ctxt.Out.Offset())
  1358  	va := int(sect.virtualAddress)
  1359  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
  1360  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
  1361  
  1362  	vaName := va + binary.Size(&e) + nexport*4
  1363  	vaAddr := va + binary.Size(&e)
  1364  	vaNa := va + binary.Size(&e) + nexport*8
  1365  
  1366  	e.Characteristics = 0
  1367  	e.MajorVersion = 0
  1368  	e.MinorVersion = 0
  1369  	e.NumberOfFunctions = uint32(nexport)
  1370  	e.NumberOfNames = uint32(nexport)
  1371  	e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
  1372  	e.Base = 1
  1373  	e.AddressOfFunctions = uint32(vaAddr)
  1374  	e.AddressOfNames = uint32(vaName)
  1375  	e.AddressOfNameOrdinals = uint32(vaNa)
  1376  
  1377  	out := ctxt.Out
  1378  
  1379  	// put IMAGE_EXPORT_DIRECTORY
  1380  	binary.Write(out, binary.LittleEndian, &e)
  1381  
  1382  	// put EXPORT Address Table
  1383  	for _, s := range dexport {
  1384  		out.Write32(uint32(ldr.SymValue(s) - PEBASE))
  1385  	}
  1386  
  1387  	// put EXPORT Name Pointer Table
  1388  	v := int(e.Name + uint32(len(*flagOutfile)) + 1)
  1389  
  1390  	for _, s := range dexport {
  1391  		out.Write32(uint32(v))
  1392  		v += len(ldr.SymExtname(s)) + 1
  1393  	}
  1394  
  1395  	// put EXPORT Ordinal Table
  1396  	for i := 0; i < nexport; i++ {
  1397  		out.Write16(uint16(i))
  1398  	}
  1399  
  1400  	// put Names
  1401  	out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
  1402  
  1403  	for _, s := range dexport {
  1404  		name := ldr.SymExtname(s)
  1405  		out.WriteStringN(name, len(name)+1)
  1406  	}
  1407  	sect.pad(out, uint32(size))
  1408  }
  1409  
  1410  // peBaseRelocEntry represents a single relocation entry.
  1411  type peBaseRelocEntry struct {
  1412  	typeOff uint16
  1413  }
  1414  
  1415  // peBaseRelocBlock represents a Base Relocation Block. A block
  1416  // is a collection of relocation entries in a page, where each
  1417  // entry describes a single relocation.
  1418  // The block page RVA (Relative Virtual Address) is the index
  1419  // into peBaseRelocTable.blocks.
  1420  type peBaseRelocBlock struct {
  1421  	entries []peBaseRelocEntry
  1422  }
  1423  
  1424  // pePages is a type used to store the list of pages for which there
  1425  // are base relocation blocks. This is defined as a type so that
  1426  // it can be sorted.
  1427  type pePages []uint32
  1428  
  1429  func (p pePages) Len() int           { return len(p) }
  1430  func (p pePages) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
  1431  func (p pePages) Less(i, j int) bool { return p[i] < p[j] }
  1432  
  1433  // A PE base relocation table is a list of blocks, where each block
  1434  // contains relocation information for a single page. The blocks
  1435  // must be emitted in order of page virtual address.
  1436  // See https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-reloc-section-image-only
  1437  type peBaseRelocTable struct {
  1438  	blocks map[uint32]peBaseRelocBlock
  1439  
  1440  	// pePages is a list of keys into blocks map.
  1441  	// It is stored separately for ease of sorting.
  1442  	pages pePages
  1443  }
  1444  
  1445  func (rt *peBaseRelocTable) init(ctxt *Link) {
  1446  	rt.blocks = make(map[uint32]peBaseRelocBlock)
  1447  }
  1448  
  1449  func (rt *peBaseRelocTable) addentry(ldr *loader.Loader, s loader.Sym, r *loader.Reloc) {
  1450  	// pageSize is the size in bytes of a page
  1451  	// described by a base relocation block.
  1452  	const pageSize = 0x1000
  1453  	const pageMask = pageSize - 1
  1454  
  1455  	addr := ldr.SymValue(s) + int64(r.Off()) - int64(PEBASE)
  1456  	page := uint32(addr &^ pageMask)
  1457  	off := uint32(addr & pageMask)
  1458  
  1459  	b, ok := rt.blocks[page]
  1460  	if !ok {
  1461  		rt.pages = append(rt.pages, page)
  1462  	}
  1463  
  1464  	e := peBaseRelocEntry{
  1465  		typeOff: uint16(off & 0xFFF),
  1466  	}
  1467  
  1468  	// Set entry type
  1469  	switch r.Siz() {
  1470  	default:
  1471  		Exitf("unsupported relocation size %d\n", r.Siz)
  1472  	case 4:
  1473  		e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12)
  1474  	case 8:
  1475  		e.typeOff |= uint16(IMAGE_REL_BASED_DIR64 << 12)
  1476  	}
  1477  
  1478  	b.entries = append(b.entries, e)
  1479  	rt.blocks[page] = b
  1480  }
  1481  
  1482  func (rt *peBaseRelocTable) write(ctxt *Link) {
  1483  	out := ctxt.Out
  1484  
  1485  	// sort the pages array
  1486  	sort.Sort(rt.pages)
  1487  
  1488  	for _, p := range rt.pages {
  1489  		b := rt.blocks[p]
  1490  		const sizeOfPEbaseRelocBlock = 8 // 2 * sizeof(uint32)
  1491  		blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2)
  1492  		out.Write32(p)
  1493  		out.Write32(blockSize)
  1494  
  1495  		for _, e := range b.entries {
  1496  			out.Write16(e.typeOff)
  1497  		}
  1498  	}
  1499  }
  1500  
  1501  func addPEBaseRelocSym(ldr *loader.Loader, s loader.Sym, rt *peBaseRelocTable) {
  1502  	relocs := ldr.Relocs(s)
  1503  	for ri := 0; ri < relocs.Count(); ri++ {
  1504  		r := relocs.At(ri)
  1505  		if r.Type() >= objabi.ElfRelocOffset {
  1506  			continue
  1507  		}
  1508  		if r.Siz() == 0 { // informational relocation
  1509  			continue
  1510  		}
  1511  		if r.Type() == objabi.R_DWARFFILEREF {
  1512  			continue
  1513  		}
  1514  		rs := r.Sym()
  1515  		rs = ldr.ResolveABIAlias(rs)
  1516  		if rs == 0 {
  1517  			continue
  1518  		}
  1519  		if !ldr.AttrReachable(s) {
  1520  			continue
  1521  		}
  1522  
  1523  		switch r.Type() {
  1524  		default:
  1525  		case objabi.R_ADDR:
  1526  			rt.addentry(ldr, s, &r)
  1527  		}
  1528  	}
  1529  }
  1530  
  1531  func needPEBaseReloc(ctxt *Link) bool {
  1532  	// Non-PIE x86 binaries don't need the base relocation table.
  1533  	// Everyone else does.
  1534  	if (ctxt.Arch.Family == sys.I386 || ctxt.Arch.Family == sys.AMD64) && ctxt.BuildMode != BuildModePIE {
  1535  		return false
  1536  	}
  1537  	return true
  1538  }
  1539  
  1540  func addPEBaseReloc(ctxt *Link) {
  1541  	if !needPEBaseReloc(ctxt) {
  1542  		return
  1543  	}
  1544  
  1545  	var rt peBaseRelocTable
  1546  	rt.init(ctxt)
  1547  
  1548  	// Get relocation information
  1549  	ldr := ctxt.loader
  1550  	for _, s := range ctxt.Textp {
  1551  		addPEBaseRelocSym(ldr, s, &rt)
  1552  	}
  1553  	for _, s := range ctxt.datap {
  1554  		addPEBaseRelocSym(ldr, s, &rt)
  1555  	}
  1556  
  1557  	// Write relocation information
  1558  	startoff := ctxt.Out.Offset()
  1559  	rt.write(ctxt)
  1560  	size := ctxt.Out.Offset() - startoff
  1561  
  1562  	// Add a PE section and pad it at the end
  1563  	rsect := pefile.addSection(".reloc", int(size), int(size))
  1564  	rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
  1565  	rsect.checkOffset(startoff)
  1566  	rsect.pad(ctxt.Out, uint32(size))
  1567  
  1568  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
  1569  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
  1570  }
  1571  
  1572  func (ctxt *Link) dope() {
  1573  	initdynimport(ctxt)
  1574  	initdynexport(ctxt)
  1575  }
  1576  
  1577  func setpersrc(ctxt *Link, syms []loader.Sym) {
  1578  	if len(rsrcsyms) != 0 {
  1579  		Errorf(nil, "too many .rsrc sections")
  1580  	}
  1581  	rsrcsyms = syms
  1582  }
  1583  
  1584  func addpersrc(ctxt *Link) {
  1585  	if len(rsrcsyms) == 0 {
  1586  		return
  1587  	}
  1588  
  1589  	var size int64
  1590  	for _, rsrcsym := range rsrcsyms {
  1591  		size += ctxt.loader.SymSize(rsrcsym)
  1592  	}
  1593  	h := pefile.addSection(".rsrc", int(size), int(size))
  1594  	h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA
  1595  	h.checkOffset(ctxt.Out.Offset())
  1596  
  1597  	for _, rsrcsym := range rsrcsyms {
  1598  		// A split resource happens when the actual resource data and its relocations are
  1599  		// split across multiple sections, denoted by a $01 or $02 at the end of the .rsrc
  1600  		// section name.
  1601  		splitResources := strings.Contains(ctxt.loader.SymName(rsrcsym), ".rsrc$")
  1602  		relocs := ctxt.loader.Relocs(rsrcsym)
  1603  		data := ctxt.loader.Data(rsrcsym)
  1604  		for ri := 0; ri < relocs.Count(); ri++ {
  1605  			r := relocs.At(ri)
  1606  			p := data[r.Off():]
  1607  			val := uint32(int64(h.virtualAddress) + r.Add())
  1608  			if splitResources {
  1609  				// If we're a split resource section, and that section has relocation
  1610  				// symbols, then the data that it points to doesn't actually begin at
  1611  				// the virtual address listed in this current section, but rather
  1612  				// begins at the section immediately after this one. So, in order to
  1613  				// calculate the proper virtual address of the data it's pointing to,
  1614  				// we have to add the length of this section to the virtual address.
  1615  				// This works because .rsrc sections are divided into two (but not more)
  1616  				// of these sections.
  1617  				val += uint32(len(data))
  1618  			}
  1619  			binary.LittleEndian.PutUint32(p, val)
  1620  		}
  1621  		ctxt.Out.Write(data)
  1622  	}
  1623  	h.pad(ctxt.Out, uint32(size))
  1624  
  1625  	// update data directory
  1626  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
  1627  	pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
  1628  }
  1629  
  1630  func asmbPe(ctxt *Link) {
  1631  	t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length))
  1632  	t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
  1633  	if ctxt.LinkMode == LinkExternal {
  1634  		// some data symbols (e.g. masks) end up in the .text section, and they normally
  1635  		// expect larger alignment requirement than the default text section alignment.
  1636  		t.characteristics |= IMAGE_SCN_ALIGN_32BYTES
  1637  	}
  1638  	t.checkSegment(&Segtext)
  1639  	pefile.textSect = t
  1640  
  1641  	ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length))
  1642  	ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
  1643  	if ctxt.LinkMode == LinkExternal {
  1644  		// some data symbols (e.g. masks) end up in the .rdata section, and they normally
  1645  		// expect larger alignment requirement than the default text section alignment.
  1646  		ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
  1647  	}
  1648  	ro.checkSegment(&Segrodata)
  1649  	pefile.rdataSect = ro
  1650  
  1651  	var d *peSection
  1652  	if ctxt.LinkMode != LinkExternal {
  1653  		d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
  1654  		d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
  1655  		d.checkSegment(&Segdata)
  1656  		pefile.dataSect = d
  1657  	} else {
  1658  		d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
  1659  		d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1660  		d.checkSegment(&Segdata)
  1661  		pefile.dataSect = d
  1662  
  1663  		b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
  1664  		b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
  1665  		b.pointerToRawData = 0
  1666  		pefile.bssSect = b
  1667  	}
  1668  
  1669  	pefile.addDWARF()
  1670  
  1671  	if ctxt.LinkMode == LinkExternal {
  1672  		pefile.ctorsSect = pefile.addInitArray(ctxt)
  1673  	}
  1674  
  1675  	ctxt.Out.SeekSet(int64(pefile.nextFileOffset))
  1676  	if ctxt.LinkMode != LinkExternal {
  1677  		addimports(ctxt, d)
  1678  		addexports(ctxt)
  1679  		addPEBaseReloc(ctxt)
  1680  	}
  1681  	pefile.writeSymbolTableAndStringTable(ctxt)
  1682  	addpersrc(ctxt)
  1683  	if ctxt.LinkMode == LinkExternal {
  1684  		pefile.emitRelocations(ctxt)
  1685  	}
  1686  
  1687  	pewrite(ctxt)
  1688  }
  1689  

View as plain text