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