...
Run Format

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

Documentation: cmd/link/internal/ld

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

View as plain text