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.ARM64:
917 fh.Machine = pe.IMAGE_FILE_MACHINE_ARM64
918 }
919
920 fh.NumberOfSections = uint16(len(f.sections))
921
922
923
924 fh.TimeDateStamp = 0
925
926 if ctxt.LinkMode != LinkExternal {
927 fh.Characteristics = pe.IMAGE_FILE_EXECUTABLE_IMAGE
928 switch ctxt.Arch.Family {
929 case sys.AMD64, sys.I386:
930 if ctxt.BuildMode != BuildModePIE {
931 fh.Characteristics |= pe.IMAGE_FILE_RELOCS_STRIPPED
932 }
933 }
934 }
935 if pe64 {
936 var oh64 pe.OptionalHeader64
937 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
938 fh.Characteristics |= pe.IMAGE_FILE_LARGE_ADDRESS_AWARE
939 } else {
940 var oh pe.OptionalHeader32
941 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
942 fh.Characteristics |= pe.IMAGE_FILE_32BIT_MACHINE
943 }
944
945 fh.PointerToSymbolTable = uint32(f.symtabOffset)
946 fh.NumberOfSymbols = uint32(f.symbolCount)
947
948 binary.Write(ctxt.Out, binary.LittleEndian, &fh)
949 }
950
951
952 func (f *peFile) writeOptionalHeader(ctxt *Link) {
953 var oh pe.OptionalHeader32
954 var oh64 pe.OptionalHeader64
955
956 if pe64 {
957 oh64.Magic = 0x20b
958 } else {
959 oh.Magic = 0x10b
960 oh.BaseOfData = f.dataSect.virtualAddress
961 }
962
963
964 oh64.MajorLinkerVersion = 3
965 oh.MajorLinkerVersion = 3
966 oh64.MinorLinkerVersion = 0
967 oh.MinorLinkerVersion = 0
968 oh64.SizeOfCode = f.textSect.sizeOfRawData
969 oh.SizeOfCode = f.textSect.sizeOfRawData
970 oh64.SizeOfInitializedData = f.dataSect.sizeOfRawData
971 oh.SizeOfInitializedData = f.dataSect.sizeOfRawData
972 oh64.SizeOfUninitializedData = 0
973 oh.SizeOfUninitializedData = 0
974 if ctxt.LinkMode != LinkExternal {
975 oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
976 oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
977 }
978 oh64.BaseOfCode = f.textSect.virtualAddress
979 oh.BaseOfCode = f.textSect.virtualAddress
980 oh64.ImageBase = uint64(PEBASE)
981 oh.ImageBase = uint32(PEBASE)
982 oh64.SectionAlignment = uint32(PESECTALIGN)
983 oh.SectionAlignment = uint32(PESECTALIGN)
984 oh64.FileAlignment = uint32(PEFILEALIGN)
985 oh.FileAlignment = uint32(PEFILEALIGN)
986 oh64.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
987 oh.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
988 oh64.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
989 oh.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
990 oh64.MajorImageVersion = 1
991 oh.MajorImageVersion = 1
992 oh64.MinorImageVersion = 0
993 oh.MinorImageVersion = 0
994 oh64.MajorSubsystemVersion = PeMinimumTargetMajorVersion
995 oh.MajorSubsystemVersion = PeMinimumTargetMajorVersion
996 oh64.MinorSubsystemVersion = PeMinimumTargetMinorVersion
997 oh.MinorSubsystemVersion = PeMinimumTargetMinorVersion
998 oh64.SizeOfImage = f.nextSectOffset
999 oh.SizeOfImage = f.nextSectOffset
1000 oh64.SizeOfHeaders = uint32(PEFILEHEADR)
1001 oh.SizeOfHeaders = uint32(PEFILEHEADR)
1002 if windowsgui {
1003 oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
1004 oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
1005 } else {
1006 oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
1007 oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
1008 }
1009
1010
1011 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
1012 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
1013
1014
1015 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
1016 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
1017
1018
1019 if needPEBaseReloc(ctxt) {
1020 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
1021 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
1022 }
1023
1024
1025 if ctxt.BuildMode == BuildModePIE {
1026 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
1027 }
1028
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 oh64.SizeOfStackReserve = 0x00200000
1054 if !iscgo {
1055 oh64.SizeOfStackCommit = 0x00001000
1056 } else {
1057
1058
1059
1060 oh64.SizeOfStackCommit = 0x00200000 - 0x2000
1061 }
1062
1063 oh.SizeOfStackReserve = 0x00100000
1064 if !iscgo {
1065 oh.SizeOfStackCommit = 0x00001000
1066 } else {
1067 oh.SizeOfStackCommit = 0x00100000 - 0x2000
1068 }
1069
1070 oh64.SizeOfHeapReserve = 0x00100000
1071 oh.SizeOfHeapReserve = 0x00100000
1072 oh64.SizeOfHeapCommit = 0x00001000
1073 oh.SizeOfHeapCommit = 0x00001000
1074 oh64.NumberOfRvaAndSizes = 16
1075 oh.NumberOfRvaAndSizes = 16
1076
1077 if pe64 {
1078 oh64.DataDirectory = f.dataDirectory
1079 } else {
1080 oh.DataDirectory = f.dataDirectory
1081 }
1082
1083 if pe64 {
1084 binary.Write(ctxt.Out, binary.LittleEndian, &oh64)
1085 } else {
1086 binary.Write(ctxt.Out, binary.LittleEndian, &oh)
1087 }
1088 }
1089
1090 var pefile peFile
1091
1092 func Peinit(ctxt *Link) {
1093 var l int
1094
1095 if ctxt.Arch.PtrSize == 8 {
1096
1097 pe64 = true
1098 var oh64 pe.OptionalHeader64
1099 l = binary.Size(&oh64)
1100 } else {
1101
1102 var oh pe.OptionalHeader32
1103 l = binary.Size(&oh)
1104 }
1105
1106 if ctxt.LinkMode == LinkExternal {
1107
1108
1109
1110
1111 PESECTALIGN = 32
1112 PEFILEALIGN = 0
1113
1114 PEBASE = 0
1115 } else {
1116
1117 if pe64 {
1118 PEBASE = 0x140000000
1119 } else {
1120 PEBASE = 0x400000
1121 }
1122 }
1123
1124 var sh [16]pe.SectionHeader32
1125 var fh pe.FileHeader
1126 PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
1127 if ctxt.LinkMode != LinkExternal {
1128 PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
1129 } else {
1130 PESECTHEADR = 0
1131 }
1132 pefile.nextSectOffset = uint32(PESECTHEADR)
1133 pefile.nextFileOffset = uint32(PEFILEHEADR)
1134
1135 if ctxt.LinkMode == LinkInternal {
1136
1137 for _, name := range [2]string{"__image_base__", "_image_base__"} {
1138 sb := ctxt.loader.CreateSymForUpdate(name, 0)
1139 sb.SetType(sym.SDATA)
1140 sb.SetValue(PEBASE)
1141 ctxt.loader.SetAttrSpecial(sb.Sym(), true)
1142 ctxt.loader.SetAttrLocal(sb.Sym(), true)
1143 }
1144 }
1145
1146 HEADR = PEFILEHEADR
1147 if *FlagRound == -1 {
1148 *FlagRound = PESECTALIGN
1149 }
1150 if *FlagTextAddr == -1 {
1151 *FlagTextAddr = Rnd(PEBASE, *FlagRound) + int64(PESECTHEADR)
1152 }
1153 }
1154
1155 func pewrite(ctxt *Link) {
1156 ctxt.Out.SeekSet(0)
1157 if ctxt.LinkMode != LinkExternal {
1158 ctxt.Out.Write(dosstub)
1159 ctxt.Out.WriteStringN("PE", 4)
1160 }
1161
1162 pefile.writeFileHeader(ctxt)
1163
1164 pefile.writeOptionalHeader(ctxt)
1165
1166 for _, sect := range pefile.sections {
1167 sect.write(ctxt.Out, ctxt.LinkMode)
1168 }
1169 }
1170
1171 func strput(out *OutBuf, s string) {
1172 out.WriteString(s)
1173 out.Write8(0)
1174
1175 if (len(s)+1)%2 != 0 {
1176 out.Write8(0)
1177 }
1178 }
1179
1180 func initdynimport(ctxt *Link) *Dll {
1181 ldr := ctxt.loader
1182 var d *Dll
1183
1184 dr = nil
1185 var m *Imp
1186 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1187 if !ldr.AttrReachable(s) || ldr.SymType(s) != sym.SDYNIMPORT {
1188 continue
1189 }
1190 dynlib := ldr.SymDynimplib(s)
1191 for d = dr; d != nil; d = d.next {
1192 if d.name == dynlib {
1193 m = new(Imp)
1194 break
1195 }
1196 }
1197
1198 if d == nil {
1199 d = new(Dll)
1200 d.name = dynlib
1201 d.next = dr
1202 dr = d
1203 m = new(Imp)
1204 }
1205
1206
1207
1208
1209
1210 m.argsize = -1
1211 extName := ldr.SymExtname(s)
1212 if i := strings.IndexByte(extName, '%'); i >= 0 {
1213 var err error
1214 m.argsize, err = strconv.Atoi(extName[i+1:])
1215 if err != nil {
1216 ctxt.Errorf(s, "failed to parse stdcall decoration: %v", err)
1217 }
1218 m.argsize *= ctxt.Arch.PtrSize
1219 ldr.SetSymExtname(s, extName[:i])
1220 }
1221
1222 m.s = s
1223 m.next = d.ms
1224 d.ms = m
1225 }
1226
1227 if ctxt.IsExternal() {
1228
1229 for d := dr; d != nil; d = d.next {
1230 for m = d.ms; m != nil; m = m.next {
1231 sb := ldr.MakeSymbolUpdater(m.s)
1232 sb.SetType(sym.SDATA)
1233 sb.Grow(int64(ctxt.Arch.PtrSize))
1234 dynName := sb.Extname()
1235
1236 if ctxt.Is386() && m.argsize >= 0 {
1237 dynName += fmt.Sprintf("@%d", m.argsize)
1238 }
1239 dynSym := ldr.CreateSymForUpdate(dynName, 0)
1240 dynSym.SetType(sym.SHOSTOBJ)
1241 r, _ := sb.AddRel(objabi.R_ADDR)
1242 r.SetSym(dynSym.Sym())
1243 r.SetSiz(uint8(ctxt.Arch.PtrSize))
1244 }
1245 }
1246 } else {
1247 dynamic := ldr.CreateSymForUpdate(".windynamic", 0)
1248 dynamic.SetType(sym.SWINDOWS)
1249 for d := dr; d != nil; d = d.next {
1250 for m = d.ms; m != nil; m = m.next {
1251 sb := ldr.MakeSymbolUpdater(m.s)
1252 sb.SetType(sym.SWINDOWS)
1253 sb.SetValue(dynamic.Size())
1254 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
1255 dynamic.AddInteriorSym(m.s)
1256 }
1257
1258 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
1259 }
1260 }
1261
1262 return dr
1263 }
1264
1265
1266
1267 func peimporteddlls() []string {
1268 var dlls []string
1269
1270 for d := dr; d != nil; d = d.next {
1271 dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
1272 }
1273
1274 return dlls
1275 }
1276
1277 func addimports(ctxt *Link, datsect *peSection) {
1278 ldr := ctxt.loader
1279 startoff := ctxt.Out.Offset()
1280 dynamic := ldr.LookupOrCreateSym(".windynamic", 0)
1281
1282
1283 n := uint64(0)
1284
1285 for d := dr; d != nil; d = d.next {
1286 n++
1287 }
1288 ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
1289
1290
1291 for d := dr; d != nil; d = d.next {
1292 d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff)
1293 strput(ctxt.Out, d.name)
1294 }
1295
1296
1297 for d := dr; d != nil; d = d.next {
1298 for m := d.ms; m != nil; m = m.next {
1299 m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
1300 ctxt.Out.Write16(0)
1301 strput(ctxt.Out, ldr.SymExtname(m.s))
1302 }
1303 }
1304
1305
1306 oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff)
1307
1308 n = uint64(ctxt.Out.Offset())
1309 for d := dr; d != nil; d = d.next {
1310 d.thunkoff = uint64(ctxt.Out.Offset()) - n
1311 for m := d.ms; m != nil; m = m.next {
1312 if pe64 {
1313 ctxt.Out.Write64(m.off)
1314 } else {
1315 ctxt.Out.Write32(uint32(m.off))
1316 }
1317 }
1318
1319 if pe64 {
1320 ctxt.Out.Write64(0)
1321 } else {
1322 ctxt.Out.Write32(0)
1323 }
1324 }
1325
1326
1327 n = uint64(ctxt.Out.Offset()) - uint64(startoff)
1328
1329 isect := pefile.addSection(".idata", int(n), int(n))
1330 isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
1331 isect.checkOffset(startoff)
1332 isect.pad(ctxt.Out, uint32(n))
1333 endoff := ctxt.Out.Offset()
1334
1335
1336 ftbase := uint64(ldr.SymValue(dynamic)) - uint64(datsect.virtualAddress) - uint64(PEBASE)
1337
1338 ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase))
1339 for d := dr; d != nil; d = d.next {
1340 for m := d.ms; m != nil; m = m.next {
1341 if pe64 {
1342 ctxt.Out.Write64(m.off)
1343 } else {
1344 ctxt.Out.Write32(uint32(m.off))
1345 }
1346 }
1347
1348 if pe64 {
1349 ctxt.Out.Write64(0)
1350 } else {
1351 ctxt.Out.Write32(0)
1352 }
1353 }
1354
1355
1356 out := ctxt.Out
1357 out.SeekSet(startoff)
1358
1359 for d := dr; d != nil; d = d.next {
1360 out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff))
1361 out.Write32(0)
1362 out.Write32(0)
1363 out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff))
1364 out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff))
1365 }
1366
1367 out.Write32(0)
1368 out.Write32(0)
1369 out.Write32(0)
1370 out.Write32(0)
1371 out.Write32(0)
1372
1373
1374 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
1375 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
1376 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(ldr.SymValue(dynamic) - PEBASE)
1377 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(ldr.SymSize(dynamic))
1378
1379 out.SeekSet(endoff)
1380 }
1381
1382 func initdynexport(ctxt *Link) {
1383 ldr := ctxt.loader
1384 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1385 if !ldr.AttrReachable(s) || !ldr.AttrCgoExportDynamic(s) {
1386 continue
1387 }
1388 if len(dexport) >= math.MaxUint16 {
1389 ctxt.Errorf(s, "pe dynexport table is full")
1390 errorexit()
1391 }
1392
1393 dexport = append(dexport, s)
1394 }
1395
1396 sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) })
1397 }
1398
1399 func addexports(ctxt *Link) {
1400 ldr := ctxt.loader
1401 var e IMAGE_EXPORT_DIRECTORY
1402
1403 nexport := len(dexport)
1404 size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
1405 for _, s := range dexport {
1406 size += len(ldr.SymExtname(s)) + 1
1407 }
1408
1409 if nexport == 0 {
1410 return
1411 }
1412
1413 sect := pefile.addSection(".edata", size, size)
1414 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
1415 sect.checkOffset(ctxt.Out.Offset())
1416 va := int(sect.virtualAddress)
1417 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
1418 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
1419
1420 vaName := va + binary.Size(&e) + nexport*4
1421 vaAddr := va + binary.Size(&e)
1422 vaNa := va + binary.Size(&e) + nexport*8
1423
1424 e.Characteristics = 0
1425 e.MajorVersion = 0
1426 e.MinorVersion = 0
1427 e.NumberOfFunctions = uint32(nexport)
1428 e.NumberOfNames = uint32(nexport)
1429 e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10
1430 e.Base = 1
1431 e.AddressOfFunctions = uint32(vaAddr)
1432 e.AddressOfNames = uint32(vaName)
1433 e.AddressOfNameOrdinals = uint32(vaNa)
1434
1435 out := ctxt.Out
1436
1437
1438 binary.Write(out, binary.LittleEndian, &e)
1439
1440
1441 for _, s := range dexport {
1442 out.Write32(uint32(ldr.SymValue(s) - PEBASE))
1443 }
1444
1445
1446 v := int(e.Name + uint32(len(*flagOutfile)) + 1)
1447
1448 for _, s := range dexport {
1449 out.Write32(uint32(v))
1450 v += len(ldr.SymExtname(s)) + 1
1451 }
1452
1453
1454 for i := 0; i < nexport; i++ {
1455 out.Write16(uint16(i))
1456 }
1457
1458
1459 out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
1460
1461 for _, s := range dexport {
1462 name := ldr.SymExtname(s)
1463 out.WriteStringN(name, len(name)+1)
1464 }
1465 sect.pad(out, uint32(size))
1466 }
1467
1468
1469 type peBaseRelocEntry struct {
1470 typeOff uint16
1471 }
1472
1473
1474
1475
1476
1477
1478 type peBaseRelocBlock struct {
1479 entries []peBaseRelocEntry
1480 }
1481
1482
1483
1484
1485 type pePages []uint32
1486
1487
1488
1489
1490
1491 type peBaseRelocTable struct {
1492 blocks map[uint32]peBaseRelocBlock
1493
1494
1495
1496 pages pePages
1497 }
1498
1499 func (rt *peBaseRelocTable) init(ctxt *Link) {
1500 rt.blocks = make(map[uint32]peBaseRelocBlock)
1501 }
1502
1503 func (rt *peBaseRelocTable) addentry(ldr *loader.Loader, s loader.Sym, r *loader.Reloc) {
1504
1505
1506 const pageSize = 0x1000
1507 const pageMask = pageSize - 1
1508
1509 addr := ldr.SymValue(s) + int64(r.Off()) - int64(PEBASE)
1510 page := uint32(addr &^ pageMask)
1511 off := uint32(addr & pageMask)
1512
1513 b, ok := rt.blocks[page]
1514 if !ok {
1515 rt.pages = append(rt.pages, page)
1516 }
1517
1518 e := peBaseRelocEntry{
1519 typeOff: uint16(off & 0xFFF),
1520 }
1521
1522
1523 switch r.Siz() {
1524 default:
1525 Exitf("unsupported relocation size %d\n", r.Siz)
1526 case 4:
1527 e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12)
1528 case 8:
1529 e.typeOff |= uint16(IMAGE_REL_BASED_DIR64 << 12)
1530 }
1531
1532 b.entries = append(b.entries, e)
1533 rt.blocks[page] = b
1534 }
1535
1536 func (rt *peBaseRelocTable) write(ctxt *Link) {
1537 out := ctxt.Out
1538
1539
1540 slices.Sort(rt.pages)
1541
1542
1543 if out.Offset()&3 != 0 {
1544 Errorf("internal error, start of .reloc not 32-bit aligned")
1545 }
1546
1547 for _, p := range rt.pages {
1548 b := rt.blocks[p]
1549
1550
1551
1552
1553 if len(b.entries)&1 != 0 {
1554 b.entries = append(b.entries, peBaseRelocEntry{})
1555 }
1556
1557 const sizeOfPEbaseRelocBlock = 8
1558 blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2)
1559 out.Write32(p)
1560 out.Write32(blockSize)
1561
1562 for _, e := range b.entries {
1563 out.Write16(e.typeOff)
1564 }
1565 }
1566 }
1567
1568 func addPEBaseRelocSym(ldr *loader.Loader, s loader.Sym, rt *peBaseRelocTable) {
1569 relocs := ldr.Relocs(s)
1570 for ri := 0; ri < relocs.Count(); ri++ {
1571 r := relocs.At(ri)
1572 if r.Type() >= objabi.ElfRelocOffset {
1573 continue
1574 }
1575 if r.Siz() == 0 {
1576 continue
1577 }
1578 rs := r.Sym()
1579 if rs == 0 {
1580 continue
1581 }
1582 if !ldr.AttrReachable(s) {
1583 continue
1584 }
1585
1586 switch r.Type() {
1587 default:
1588 case objabi.R_ADDR:
1589 rt.addentry(ldr, s, &r)
1590 }
1591 }
1592 }
1593
1594 func needPEBaseReloc(ctxt *Link) bool {
1595
1596
1597 if (ctxt.Arch.Family == sys.I386 || ctxt.Arch.Family == sys.AMD64) && ctxt.BuildMode != BuildModePIE {
1598 return false
1599 }
1600 return true
1601 }
1602
1603 func addPEBaseReloc(ctxt *Link) {
1604 if !needPEBaseReloc(ctxt) {
1605 return
1606 }
1607
1608 var rt peBaseRelocTable
1609 rt.init(ctxt)
1610
1611
1612 ldr := ctxt.loader
1613 for _, s := range ctxt.Textp {
1614 addPEBaseRelocSym(ldr, s, &rt)
1615 }
1616 for _, s := range ctxt.datap {
1617 addPEBaseRelocSym(ldr, s, &rt)
1618 }
1619
1620
1621 startoff := ctxt.Out.Offset()
1622 rt.write(ctxt)
1623 size := ctxt.Out.Offset() - startoff
1624
1625
1626 rsect := pefile.addSection(".reloc", int(size), int(size))
1627 rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
1628 rsect.checkOffset(startoff)
1629 rsect.pad(ctxt.Out, uint32(size))
1630
1631 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
1632 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
1633 }
1634
1635 func (ctxt *Link) dope() {
1636 initdynimport(ctxt)
1637 initdynexport(ctxt)
1638 writeSEH(ctxt)
1639 }
1640
1641 func setpersrc(ctxt *Link, syms []loader.Sym) {
1642 if len(rsrcsyms) != 0 {
1643 Errorf("too many .rsrc sections")
1644 }
1645 rsrcsyms = syms
1646 }
1647
1648 func addpersrc(ctxt *Link) {
1649 if len(rsrcsyms) == 0 {
1650 return
1651 }
1652
1653 var size int64
1654 for _, rsrcsym := range rsrcsyms {
1655 size += ctxt.loader.SymSize(rsrcsym)
1656 }
1657 h := pefile.addSection(".rsrc", int(size), int(size))
1658 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA
1659 h.checkOffset(ctxt.Out.Offset())
1660
1661 for _, rsrcsym := range rsrcsyms {
1662
1663
1664
1665 splitResources := strings.Contains(ctxt.loader.SymName(rsrcsym), ".rsrc$")
1666 relocs := ctxt.loader.Relocs(rsrcsym)
1667 data := ctxt.loader.Data(rsrcsym)
1668 for ri := 0; ri < relocs.Count(); ri++ {
1669 r := relocs.At(ri)
1670 p := data[r.Off():]
1671 val := uint32(int64(h.virtualAddress) + r.Add())
1672 if splitResources {
1673
1674
1675
1676
1677
1678
1679
1680
1681 val += uint32(len(data))
1682 }
1683 binary.LittleEndian.PutUint32(p, val)
1684 }
1685 ctxt.Out.Write(data)
1686 }
1687 h.pad(ctxt.Out, uint32(size))
1688
1689
1690 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
1691 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
1692 }
1693
1694 func asmbPe(ctxt *Link) {
1695 t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length))
1696 t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
1697 if ctxt.LinkMode == LinkExternal {
1698
1699
1700 t.characteristics |= IMAGE_SCN_ALIGN_32BYTES
1701 }
1702 t.checkSegment(&Segtext)
1703 pefile.textSect = t
1704
1705 ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length))
1706 ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
1707 if ctxt.LinkMode == LinkExternal {
1708
1709
1710 ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
1711 }
1712 ro.checkSegment(&Segrodata)
1713 pefile.rdataSect = ro
1714
1715 var d *peSection
1716 if ctxt.LinkMode != LinkExternal {
1717 d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
1718 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
1719 d.checkSegment(&Segdata)
1720 pefile.dataSect = d
1721 } else {
1722 d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
1723 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
1724 d.checkSegment(&Segdata)
1725 pefile.dataSect = d
1726
1727 b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
1728 b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
1729 b.pointerToRawData = 0
1730 pefile.bssSect = b
1731 }
1732
1733 pefile.addSEH(ctxt)
1734 pefile.addDWARF()
1735
1736 if ctxt.LinkMode == LinkExternal {
1737 pefile.ctorsSect = pefile.addInitArray(ctxt)
1738 }
1739
1740 ctxt.Out.SeekSet(int64(pefile.nextFileOffset))
1741 if ctxt.LinkMode != LinkExternal {
1742 addimports(ctxt, d)
1743 addexports(ctxt)
1744 addPEBaseReloc(ctxt)
1745 }
1746 pefile.writeSymbolTableAndStringTable(ctxt)
1747 addpersrc(ctxt)
1748 if ctxt.LinkMode == LinkExternal {
1749 pefile.emitRelocations(ctxt)
1750 }
1751
1752 pewrite(ctxt)
1753 }
1754
View as plain text