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