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