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 int
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 switch buildcfg.GOARCH {
545 default:
546 Exitf("peFile.addInitArray: unsupported GOARCH=%q\n", buildcfg.GOARCH)
547 case "386", "arm":
548 size = 4
549 alignment = IMAGE_SCN_ALIGN_4BYTES
550 case "amd64", "arm64":
551 size = 8
552 alignment = IMAGE_SCN_ALIGN_8BYTES
553 }
554 sect := f.addSection(".ctors", size, size)
555 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | alignment
556 sect.sizeOfRawData = uint32(size)
557 ctxt.Out.SeekSet(int64(sect.pointerToRawData))
558 sect.checkOffset(ctxt.Out.Offset())
559
560 init_entry := ctxt.loader.Lookup(*flagEntrySymbol, 0)
561 addr := uint64(ctxt.loader.SymValue(init_entry)) - ctxt.loader.SymSect(init_entry).Vaddr
562 switch buildcfg.GOARCH {
563 case "386", "arm":
564 ctxt.Out.Write32(uint32(addr))
565 case "amd64", "arm64":
566 ctxt.Out.Write64(addr)
567 }
568 return sect
569 }
570
571
572 func (f *peFile) emitRelocations(ctxt *Link) {
573 for ctxt.Out.Offset()&7 != 0 {
574 ctxt.Out.Write8(0)
575 }
576
577 ldr := ctxt.loader
578
579
580
581 relocsect := func(sect *sym.Section, syms []loader.Sym, base uint64) int {
582
583 if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
584 return 0
585 }
586 sect.Reloff = uint64(ctxt.Out.Offset())
587 for i, s := range syms {
588 if !ldr.AttrReachable(s) {
589 continue
590 }
591 if uint64(ldr.SymValue(s)) >= sect.Vaddr {
592 syms = syms[i:]
593 break
594 }
595 }
596 eaddr := int64(sect.Vaddr + sect.Length)
597 for _, s := range syms {
598 if !ldr.AttrReachable(s) {
599 continue
600 }
601 if ldr.SymValue(s) >= eaddr {
602 break
603 }
604
605
606 relocs := ldr.Relocs(s)
607 for ri := 0; ri < relocs.Count(); ri++ {
608 r := relocs.At(ri)
609 rr, ok := extreloc(ctxt, ldr, s, r)
610 if !ok {
611 continue
612 }
613 if rr.Xsym == 0 {
614 ctxt.Errorf(s, "missing xsym in relocation")
615 continue
616 }
617 if ldr.SymDynid(rr.Xsym) < 0 {
618 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()))
619 }
620 if !thearch.PEreloc1(ctxt.Arch, ctxt.Out, ldr, s, rr, int64(uint64(ldr.SymValue(s)+int64(r.Off()))-base)) {
621 ctxt.Errorf(s, "unsupported obj reloc %v/%d to %s", r.Type(), r.Siz(), ldr.SymName(r.Sym()))
622 }
623 }
624 }
625 sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
626 const relocLen = 4 + 4 + 2
627 return int(sect.Rellen / relocLen)
628 }
629
630 type relsect struct {
631 peSect *peSection
632 seg *sym.Segment
633 syms []loader.Sym
634 }
635 sects := []relsect{
636 {f.textSect, &Segtext, ctxt.Textp},
637 {f.rdataSect, &Segrodata, ctxt.datap},
638 {f.dataSect, &Segdata, ctxt.datap},
639 }
640 if len(sehp.pdata) != 0 {
641 sects = append(sects, relsect{f.pdataSect, &Segpdata, sehp.pdata})
642 }
643 if len(sehp.xdata) != 0 {
644 sects = append(sects, relsect{f.xdataSect, &Segxdata, sehp.xdata})
645 }
646 for _, s := range sects {
647 s.peSect.emitRelocations(ctxt.Out, func() int {
648 var n int
649 for _, sect := range s.seg.Sections {
650 n += relocsect(sect, s.syms, s.seg.Vaddr)
651 }
652 return n
653 })
654 }
655
656 dwarfLoop:
657 for i := 0; i < len(Segdwarf.Sections); i++ {
658 sect := Segdwarf.Sections[i]
659 si := dwarfp[i]
660 if si.secSym() != loader.Sym(sect.Sym) ||
661 ldr.SymSect(si.secSym()) != sect {
662 panic("inconsistency between dwarfp and Segdwarf")
663 }
664 for _, pesect := range f.sections {
665 if sect.Name == pesect.name {
666 pesect.emitRelocations(ctxt.Out, func() int {
667 return relocsect(sect, si.syms, sect.Vaddr)
668 })
669 continue dwarfLoop
670 }
671 }
672 Errorf("emitRelocations: could not find %q section", sect.Name)
673 }
674
675 if f.ctorsSect == nil {
676 return
677 }
678
679 f.ctorsSect.emitRelocations(ctxt.Out, func() int {
680 dottext := ldr.Lookup(".text", 0)
681 ctxt.Out.Write32(0)
682 ctxt.Out.Write32(uint32(ldr.SymDynid(dottext)))
683 switch buildcfg.GOARCH {
684 default:
685 ctxt.Errorf(dottext, "unknown architecture for PE: %q\n", buildcfg.GOARCH)
686 case "386":
687 ctxt.Out.Write16(IMAGE_REL_I386_DIR32)
688 case "amd64":
689 ctxt.Out.Write16(IMAGE_REL_AMD64_ADDR64)
690 case "arm":
691 ctxt.Out.Write16(IMAGE_REL_ARM_ADDR32)
692 case "arm64":
693 ctxt.Out.Write16(IMAGE_REL_ARM64_ADDR64)
694 }
695 return 1
696 })
697 }
698
699
700
701 func (f *peFile) writeSymbol(out *OutBuf, ldr *loader.Loader, s loader.Sym, name string, value int64, sectidx int, typ uint16, class uint8) {
702 if len(name) > 8 {
703 out.Write32(0)
704 out.Write32(uint32(f.stringTable.add(name)))
705 } else {
706 out.WriteStringN(name, 8)
707 }
708 out.Write32(uint32(value))
709 out.Write16(uint16(sectidx))
710 out.Write16(typ)
711 out.Write8(class)
712 out.Write8(0)
713
714 ldr.SetSymDynid(s, int32(f.symbolCount))
715
716 f.symbolCount++
717 }
718
719
720
721 func (f *peFile) mapToPESection(ldr *loader.Loader, s loader.Sym, linkmode LinkMode) (pesectidx int, offset int64, err error) {
722 sect := ldr.SymSect(s)
723 if sect == nil {
724 return 0, 0, fmt.Errorf("could not map %s symbol with no section", ldr.SymName(s))
725 }
726 if sect.Seg == &Segtext {
727 return f.textSect.index, int64(uint64(ldr.SymValue(s)) - Segtext.Vaddr), nil
728 }
729 if sect.Seg == &Segrodata {
730 return f.rdataSect.index, int64(uint64(ldr.SymValue(s)) - Segrodata.Vaddr), nil
731 }
732 if sect.Seg != &Segdata {
733 return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .rdata or .data section", ldr.SymName(s))
734 }
735 v := uint64(ldr.SymValue(s)) - Segdata.Vaddr
736 if linkmode != LinkExternal {
737 return f.dataSect.index, int64(v), nil
738 }
739 if ldr.SymType(s).IsDATA() {
740 return f.dataSect.index, int64(v), nil
741 }
742
743
744 if v < Segdata.Filelen {
745 return f.dataSect.index, int64(v), nil
746 }
747 return f.bssSect.index, int64(v - Segdata.Filelen), nil
748 }
749
750 var isLabel = make(map[loader.Sym]bool)
751
752 func AddPELabelSym(ldr *loader.Loader, s loader.Sym) {
753 isLabel[s] = true
754 }
755
756
757 func (f *peFile) writeSymbols(ctxt *Link) {
758 ldr := ctxt.loader
759 addsym := func(s loader.Sym) {
760 t := ldr.SymType(s)
761 if ldr.SymSect(s) == nil && t != sym.SDYNIMPORT && t != sym.SHOSTOBJ && t != sym.SUNDEFEXT {
762 return
763 }
764
765 name := ldr.SymName(s)
766
767
768 if ctxt.Is386() && ctxt.IsExternal() &&
769 (t == sym.SHOSTOBJ || t == sym.SUNDEFEXT || ldr.AttrCgoExport(s) ||
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789 name == "go:buildid" || name == "type:*") {
790 name = "_" + name
791 }
792
793 name = mangleABIName(ctxt, ldr, s, name)
794
795 var peSymType uint16 = IMAGE_SYM_TYPE_NULL
796 switch {
797 case t.IsText(), t == sym.SDYNIMPORT, t == sym.SHOSTOBJ, t == sym.SUNDEFEXT:
798
799
800
801
802
803 peSymType = IMAGE_SYM_DTYPE_FUNCTION<<4 + IMAGE_SYM_TYPE_NULL
804 }
805 sect, value, err := f.mapToPESection(ldr, s, ctxt.LinkMode)
806 if err != nil {
807 switch t {
808 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
809 default:
810 ctxt.Errorf(s, "addpesym: %v", err)
811 }
812 }
813 class := IMAGE_SYM_CLASS_EXTERNAL
814 if ldr.IsFileLocal(s) || ldr.AttrVisibilityHidden(s) || ldr.AttrLocal(s) {
815 class = IMAGE_SYM_CLASS_STATIC
816 }
817 f.writeSymbol(ctxt.Out, ldr, s, name, value, sect, peSymType, uint8(class))
818 }
819
820 if ctxt.LinkMode == LinkExternal {
821
822
823 for _, pesect := range f.sections {
824 s := ldr.LookupOrCreateSym(pesect.name, 0)
825 f.writeSymbol(ctxt.Out, ldr, s, pesect.name, 0, pesect.index, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC)
826 }
827 }
828
829
830 s := ldr.Lookup("runtime.text", 0)
831 if ldr.SymType(s).IsText() {
832 addsym(s)
833 }
834 s = ldr.Lookup("runtime.etext", 0)
835 if ldr.SymType(s).IsText() {
836 addsym(s)
837 }
838
839
840 for _, s := range ctxt.Textp {
841 addsym(s)
842 }
843
844 shouldBeInSymbolTable := func(s loader.Sym) bool {
845 if ldr.AttrNotInSymbolTable(s) {
846 return false
847 }
848 name := ldr.SymName(s)
849 if name == "" || name[0] == '.' {
850 return false
851 }
852 return true
853 }
854
855
856 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
857 if !ldr.AttrReachable(s) {
858 continue
859 }
860 t := ldr.SymType(s)
861 if t >= sym.SELFRXSECT && t < sym.SXREF {
862 if t == sym.STLSBSS {
863 continue
864 }
865 if !shouldBeInSymbolTable(s) {
866 continue
867 }
868 addsym(s)
869 }
870
871 switch t {
872 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
873 addsym(s)
874 default:
875 if len(isLabel) > 0 && isLabel[s] {
876 addsym(s)
877 }
878 }
879 }
880 }
881
882
883 func (f *peFile) writeSymbolTableAndStringTable(ctxt *Link) {
884 f.symtabOffset = ctxt.Out.Offset()
885
886
887 if !*FlagS || ctxt.LinkMode == LinkExternal {
888 f.writeSymbols(ctxt)
889 }
890
891
892 size := f.stringTable.size() + 18*f.symbolCount
893 var h *peSection
894 if ctxt.LinkMode != LinkExternal {
895
896
897 h = f.addSection(".symtab", size, size)
898 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
899 h.checkOffset(f.symtabOffset)
900 }
901
902
903 f.stringTable.write(ctxt.Out)
904 if ctxt.LinkMode != LinkExternal {
905 h.pad(ctxt.Out, uint32(size))
906 }
907 }
908
909
910 func (f *peFile) writeFileHeader(ctxt *Link) {
911 var fh pe.FileHeader
912
913 switch ctxt.Arch.Family {
914 default:
915 Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
916 case sys.AMD64:
917 fh.Machine = pe.IMAGE_FILE_MACHINE_AMD64
918 case sys.I386:
919 fh.Machine = pe.IMAGE_FILE_MACHINE_I386
920 case sys.ARM:
921 fh.Machine = pe.IMAGE_FILE_MACHINE_ARMNT
922 case sys.ARM64:
923 fh.Machine = pe.IMAGE_FILE_MACHINE_ARM64
924 }
925
926 fh.NumberOfSections = uint16(len(f.sections))
927
928
929
930 fh.TimeDateStamp = 0
931
932 if ctxt.LinkMode != LinkExternal {
933 fh.Characteristics = pe.IMAGE_FILE_EXECUTABLE_IMAGE
934 switch ctxt.Arch.Family {
935 case sys.AMD64, sys.I386:
936 if ctxt.BuildMode != BuildModePIE {
937 fh.Characteristics |= pe.IMAGE_FILE_RELOCS_STRIPPED
938 }
939 }
940 }
941 if pe64 != 0 {
942 var oh64 pe.OptionalHeader64
943 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
944 fh.Characteristics |= pe.IMAGE_FILE_LARGE_ADDRESS_AWARE
945 } else {
946 var oh pe.OptionalHeader32
947 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
948 fh.Characteristics |= pe.IMAGE_FILE_32BIT_MACHINE
949 }
950
951 fh.PointerToSymbolTable = uint32(f.symtabOffset)
952 fh.NumberOfSymbols = uint32(f.symbolCount)
953
954 binary.Write(ctxt.Out, binary.LittleEndian, &fh)
955 }
956
957
958 func (f *peFile) writeOptionalHeader(ctxt *Link) {
959 var oh pe.OptionalHeader32
960 var oh64 pe.OptionalHeader64
961
962 if pe64 != 0 {
963 oh64.Magic = 0x20b
964 } else {
965 oh.Magic = 0x10b
966 oh.BaseOfData = f.dataSect.virtualAddress
967 }
968
969
970 oh64.MajorLinkerVersion = 3
971 oh.MajorLinkerVersion = 3
972 oh64.MinorLinkerVersion = 0
973 oh.MinorLinkerVersion = 0
974 oh64.SizeOfCode = f.textSect.sizeOfRawData
975 oh.SizeOfCode = f.textSect.sizeOfRawData
976 oh64.SizeOfInitializedData = f.dataSect.sizeOfRawData
977 oh.SizeOfInitializedData = f.dataSect.sizeOfRawData
978 oh64.SizeOfUninitializedData = 0
979 oh.SizeOfUninitializedData = 0
980 if ctxt.LinkMode != LinkExternal {
981 oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
982 oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
983 }
984 oh64.BaseOfCode = f.textSect.virtualAddress
985 oh.BaseOfCode = f.textSect.virtualAddress
986 oh64.ImageBase = uint64(PEBASE)
987 oh.ImageBase = uint32(PEBASE)
988 oh64.SectionAlignment = uint32(PESECTALIGN)
989 oh.SectionAlignment = uint32(PESECTALIGN)
990 oh64.FileAlignment = uint32(PEFILEALIGN)
991 oh.FileAlignment = uint32(PEFILEALIGN)
992 oh64.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
993 oh.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
994 oh64.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
995 oh.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
996 oh64.MajorImageVersion = 1
997 oh.MajorImageVersion = 1
998 oh64.MinorImageVersion = 0
999 oh.MinorImageVersion = 0
1000 oh64.MajorSubsystemVersion = PeMinimumTargetMajorVersion
1001 oh.MajorSubsystemVersion = PeMinimumTargetMajorVersion
1002 oh64.MinorSubsystemVersion = PeMinimumTargetMinorVersion
1003 oh.MinorSubsystemVersion = PeMinimumTargetMinorVersion
1004 oh64.SizeOfImage = f.nextSectOffset
1005 oh.SizeOfImage = f.nextSectOffset
1006 oh64.SizeOfHeaders = uint32(PEFILEHEADR)
1007 oh.SizeOfHeaders = uint32(PEFILEHEADR)
1008 if windowsgui {
1009 oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
1010 oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
1011 } else {
1012 oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
1013 oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
1014 }
1015
1016
1017 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
1018 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
1019
1020
1021 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
1022 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
1023
1024
1025 if needPEBaseReloc(ctxt) {
1026 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
1027 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
1028 }
1029
1030
1031 if ctxt.BuildMode == BuildModePIE {
1032 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
1033 }
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059 oh64.SizeOfStackReserve = 0x00200000
1060 if !iscgo {
1061 oh64.SizeOfStackCommit = 0x00001000
1062 } else {
1063
1064
1065
1066 oh64.SizeOfStackCommit = 0x00200000 - 0x2000
1067 }
1068
1069 oh.SizeOfStackReserve = 0x00100000
1070 if !iscgo {
1071 oh.SizeOfStackCommit = 0x00001000
1072 } else {
1073 oh.SizeOfStackCommit = 0x00100000 - 0x2000
1074 }
1075
1076 oh64.SizeOfHeapReserve = 0x00100000
1077 oh.SizeOfHeapReserve = 0x00100000
1078 oh64.SizeOfHeapCommit = 0x00001000
1079 oh.SizeOfHeapCommit = 0x00001000
1080 oh64.NumberOfRvaAndSizes = 16
1081 oh.NumberOfRvaAndSizes = 16
1082
1083 if pe64 != 0 {
1084 oh64.DataDirectory = f.dataDirectory
1085 } else {
1086 oh.DataDirectory = f.dataDirectory
1087 }
1088
1089 if pe64 != 0 {
1090 binary.Write(ctxt.Out, binary.LittleEndian, &oh64)
1091 } else {
1092 binary.Write(ctxt.Out, binary.LittleEndian, &oh)
1093 }
1094 }
1095
1096 var pefile peFile
1097
1098 func Peinit(ctxt *Link) {
1099 var l int
1100
1101 if ctxt.Arch.PtrSize == 8 {
1102
1103 pe64 = 1
1104 PEBASE = 1 << 32
1105 if ctxt.Arch.Family == sys.AMD64 {
1106
1107
1108
1109 PEBASE = 1 << 22
1110 }
1111 var oh64 pe.OptionalHeader64
1112 l = binary.Size(&oh64)
1113 } else {
1114
1115 PEBASE = 1 << 22
1116 var oh pe.OptionalHeader32
1117 l = binary.Size(&oh)
1118 }
1119
1120 if ctxt.LinkMode == LinkExternal {
1121
1122
1123
1124
1125 PESECTALIGN = 32
1126 PEFILEALIGN = 0
1127
1128 PEBASE = 0
1129 }
1130
1131 var sh [16]pe.SectionHeader32
1132 var fh pe.FileHeader
1133 PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
1134 if ctxt.LinkMode != LinkExternal {
1135 PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
1136 } else {
1137 PESECTHEADR = 0
1138 }
1139 pefile.nextSectOffset = uint32(PESECTHEADR)
1140 pefile.nextFileOffset = uint32(PEFILEHEADR)
1141
1142 if ctxt.LinkMode == LinkInternal {
1143
1144 for _, name := range [2]string{"__image_base__", "_image_base__"} {
1145 sb := ctxt.loader.CreateSymForUpdate(name, 0)
1146 sb.SetType(sym.SDATA)
1147 sb.SetValue(PEBASE)
1148 ctxt.loader.SetAttrSpecial(sb.Sym(), true)
1149 ctxt.loader.SetAttrLocal(sb.Sym(), true)
1150 }
1151 }
1152
1153 HEADR = PEFILEHEADR
1154 if *FlagRound == -1 {
1155 *FlagRound = PESECTALIGN
1156 }
1157 if *FlagTextAddr == -1 {
1158 *FlagTextAddr = Rnd(PEBASE, *FlagRound) + int64(PESECTHEADR)
1159 }
1160 }
1161
1162 func pewrite(ctxt *Link) {
1163 ctxt.Out.SeekSet(0)
1164 if ctxt.LinkMode != LinkExternal {
1165 ctxt.Out.Write(dosstub)
1166 ctxt.Out.WriteStringN("PE", 4)
1167 }
1168
1169 pefile.writeFileHeader(ctxt)
1170
1171 pefile.writeOptionalHeader(ctxt)
1172
1173 for _, sect := range pefile.sections {
1174 sect.write(ctxt.Out, ctxt.LinkMode)
1175 }
1176 }
1177
1178 func strput(out *OutBuf, s string) {
1179 out.WriteString(s)
1180 out.Write8(0)
1181
1182 if (len(s)+1)%2 != 0 {
1183 out.Write8(0)
1184 }
1185 }
1186
1187 func initdynimport(ctxt *Link) *Dll {
1188 ldr := ctxt.loader
1189 var d *Dll
1190
1191 dr = nil
1192 var m *Imp
1193 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1194 if !ldr.AttrReachable(s) || ldr.SymType(s) != sym.SDYNIMPORT {
1195 continue
1196 }
1197 dynlib := ldr.SymDynimplib(s)
1198 for d = dr; d != nil; d = d.next {
1199 if d.name == dynlib {
1200 m = new(Imp)
1201 break
1202 }
1203 }
1204
1205 if d == nil {
1206 d = new(Dll)
1207 d.name = dynlib
1208 d.next = dr
1209 dr = d
1210 m = new(Imp)
1211 }
1212
1213
1214
1215
1216
1217 m.argsize = -1
1218 extName := ldr.SymExtname(s)
1219 if i := strings.IndexByte(extName, '%'); i >= 0 {
1220 var err error
1221 m.argsize, err = strconv.Atoi(extName[i+1:])
1222 if err != nil {
1223 ctxt.Errorf(s, "failed to parse stdcall decoration: %v", err)
1224 }
1225 m.argsize *= ctxt.Arch.PtrSize
1226 ldr.SetSymExtname(s, extName[:i])
1227 }
1228
1229 m.s = s
1230 m.next = d.ms
1231 d.ms = m
1232 }
1233
1234 if ctxt.IsExternal() {
1235
1236 for d := dr; d != nil; d = d.next {
1237 for m = d.ms; m != nil; m = m.next {
1238 sb := ldr.MakeSymbolUpdater(m.s)
1239 sb.SetType(sym.SDATA)
1240 sb.Grow(int64(ctxt.Arch.PtrSize))
1241 dynName := sb.Extname()
1242
1243 if ctxt.Is386() && m.argsize >= 0 {
1244 dynName += fmt.Sprintf("@%d", m.argsize)
1245 }
1246 dynSym := ldr.CreateSymForUpdate(dynName, 0)
1247 dynSym.SetType(sym.SHOSTOBJ)
1248 r, _ := sb.AddRel(objabi.R_ADDR)
1249 r.SetSym(dynSym.Sym())
1250 r.SetSiz(uint8(ctxt.Arch.PtrSize))
1251 }
1252 }
1253 } else {
1254 dynamic := ldr.CreateSymForUpdate(".windynamic", 0)
1255 dynamic.SetType(sym.SWINDOWS)
1256 for d := dr; d != nil; d = d.next {
1257 for m = d.ms; m != nil; m = m.next {
1258 sb := ldr.MakeSymbolUpdater(m.s)
1259 sb.SetType(sym.SWINDOWS)
1260 sb.SetValue(dynamic.Size())
1261 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
1262 dynamic.AddInteriorSym(m.s)
1263 }
1264
1265 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
1266 }
1267 }
1268
1269 return dr
1270 }
1271
1272
1273
1274 func peimporteddlls() []string {
1275 var dlls []string
1276
1277 for d := dr; d != nil; d = d.next {
1278 dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
1279 }
1280
1281 return dlls
1282 }
1283
1284 func addimports(ctxt *Link, datsect *peSection) {
1285 ldr := ctxt.loader
1286 startoff := ctxt.Out.Offset()
1287 dynamic := ldr.LookupOrCreateSym(".windynamic", 0)
1288
1289
1290 n := uint64(0)
1291
1292 for d := dr; d != nil; d = d.next {
1293 n++
1294 }
1295 ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
1296
1297
1298 for d := dr; d != nil; d = d.next {
1299 d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff)
1300 strput(ctxt.Out, d.name)
1301 }
1302
1303
1304 for d := dr; d != nil; d = d.next {
1305 for m := d.ms; m != nil; m = m.next {
1306 m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
1307 ctxt.Out.Write16(0)
1308 strput(ctxt.Out, ldr.SymExtname(m.s))
1309 }
1310 }
1311
1312
1313 oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff)
1314
1315 n = uint64(ctxt.Out.Offset())
1316 for d := dr; d != nil; d = d.next {
1317 d.thunkoff = uint64(ctxt.Out.Offset()) - n
1318 for m := d.ms; m != nil; m = m.next {
1319 if pe64 != 0 {
1320 ctxt.Out.Write64(m.off)
1321 } else {
1322 ctxt.Out.Write32(uint32(m.off))
1323 }
1324 }
1325
1326 if pe64 != 0 {
1327 ctxt.Out.Write64(0)
1328 } else {
1329 ctxt.Out.Write32(0)
1330 }
1331 }
1332
1333
1334 n = uint64(ctxt.Out.Offset()) - uint64(startoff)
1335
1336 isect := pefile.addSection(".idata", int(n), int(n))
1337 isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
1338 isect.checkOffset(startoff)
1339 isect.pad(ctxt.Out, uint32(n))
1340 endoff := ctxt.Out.Offset()
1341
1342
1343 ftbase := uint64(ldr.SymValue(dynamic)) - uint64(datsect.virtualAddress) - uint64(PEBASE)
1344
1345 ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase))
1346 for d := dr; d != nil; d = d.next {
1347 for m := d.ms; m != nil; m = m.next {
1348 if pe64 != 0 {
1349 ctxt.Out.Write64(m.off)
1350 } else {
1351 ctxt.Out.Write32(uint32(m.off))
1352 }
1353 }
1354
1355 if pe64 != 0 {
1356 ctxt.Out.Write64(0)
1357 } else {
1358 ctxt.Out.Write32(0)
1359 }
1360 }
1361
1362
1363 out := ctxt.Out
1364 out.SeekSet(startoff)
1365
1366 for d := dr; d != nil; d = d.next {
1367 out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff))
1368 out.Write32(0)
1369 out.Write32(0)
1370 out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff))
1371 out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff))
1372 }
1373
1374 out.Write32(0)
1375 out.Write32(0)
1376 out.Write32(0)
1377 out.Write32(0)
1378 out.Write32(0)
1379
1380
1381 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
1382 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
1383 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(ldr.SymValue(dynamic) - PEBASE)
1384 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(ldr.SymSize(dynamic))
1385
1386 out.SeekSet(endoff)
1387 }
1388
1389 func initdynexport(ctxt *Link) {
1390 ldr := ctxt.loader
1391 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1392 if !ldr.AttrReachable(s) || !ldr.AttrCgoExportDynamic(s) {
1393 continue
1394 }
1395 if len(dexport) >= math.MaxUint16 {
1396 ctxt.Errorf(s, "pe dynexport table is full")
1397 errorexit()
1398 }
1399
1400 dexport = append(dexport, s)
1401 }
1402
1403 sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) })
1404 }
1405
1406 func addexports(ctxt *Link) {
1407 ldr := ctxt.loader
1408 var e IMAGE_EXPORT_DIRECTORY
1409
1410 nexport := len(dexport)
1411 size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
1412 for _, s := range dexport {
1413 size += len(ldr.SymExtname(s)) + 1
1414 }
1415
1416 if nexport == 0 {
1417 return
1418 }
1419
1420 sect := pefile.addSection(".edata", size, size)
1421 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
1422 sect.checkOffset(ctxt.Out.Offset())
1423 va := int(sect.virtualAddress)
1424 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
1425 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
1426
1427 vaName := va + binary.Size(&e) + nexport*4
1428 vaAddr := va + binary.Size(&e)
1429 vaNa := va + binary.Size(&e) + nexport*8
1430
1431 e.Characteristics = 0
1432 e.MajorVersion = 0
1433 e.MinorVersion = 0
1434 e.NumberOfFunctions = uint32(nexport)
1435 e.NumberOfNames = uint32(nexport)
1436 e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10
1437 e.Base = 1
1438 e.AddressOfFunctions = uint32(vaAddr)
1439 e.AddressOfNames = uint32(vaName)
1440 e.AddressOfNameOrdinals = uint32(vaNa)
1441
1442 out := ctxt.Out
1443
1444
1445 binary.Write(out, binary.LittleEndian, &e)
1446
1447
1448 for _, s := range dexport {
1449 out.Write32(uint32(ldr.SymValue(s) - PEBASE))
1450 }
1451
1452
1453 v := int(e.Name + uint32(len(*flagOutfile)) + 1)
1454
1455 for _, s := range dexport {
1456 out.Write32(uint32(v))
1457 v += len(ldr.SymExtname(s)) + 1
1458 }
1459
1460
1461 for i := 0; i < nexport; i++ {
1462 out.Write16(uint16(i))
1463 }
1464
1465
1466 out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
1467
1468 for _, s := range dexport {
1469 name := ldr.SymExtname(s)
1470 out.WriteStringN(name, len(name)+1)
1471 }
1472 sect.pad(out, uint32(size))
1473 }
1474
1475
1476 type peBaseRelocEntry struct {
1477 typeOff uint16
1478 }
1479
1480
1481
1482
1483
1484
1485 type peBaseRelocBlock struct {
1486 entries []peBaseRelocEntry
1487 }
1488
1489
1490
1491
1492 type pePages []uint32
1493
1494
1495
1496
1497
1498 type peBaseRelocTable struct {
1499 blocks map[uint32]peBaseRelocBlock
1500
1501
1502
1503 pages pePages
1504 }
1505
1506 func (rt *peBaseRelocTable) init(ctxt *Link) {
1507 rt.blocks = make(map[uint32]peBaseRelocBlock)
1508 }
1509
1510 func (rt *peBaseRelocTable) addentry(ldr *loader.Loader, s loader.Sym, r *loader.Reloc) {
1511
1512
1513 const pageSize = 0x1000
1514 const pageMask = pageSize - 1
1515
1516 addr := ldr.SymValue(s) + int64(r.Off()) - int64(PEBASE)
1517 page := uint32(addr &^ pageMask)
1518 off := uint32(addr & pageMask)
1519
1520 b, ok := rt.blocks[page]
1521 if !ok {
1522 rt.pages = append(rt.pages, page)
1523 }
1524
1525 e := peBaseRelocEntry{
1526 typeOff: uint16(off & 0xFFF),
1527 }
1528
1529
1530 switch r.Siz() {
1531 default:
1532 Exitf("unsupported relocation size %d\n", r.Siz)
1533 case 4:
1534 e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12)
1535 case 8:
1536 e.typeOff |= uint16(IMAGE_REL_BASED_DIR64 << 12)
1537 }
1538
1539 b.entries = append(b.entries, e)
1540 rt.blocks[page] = b
1541 }
1542
1543 func (rt *peBaseRelocTable) write(ctxt *Link) {
1544 out := ctxt.Out
1545
1546
1547 slices.Sort(rt.pages)
1548
1549
1550 if out.Offset()&3 != 0 {
1551 Errorf("internal error, start of .reloc not 32-bit aligned")
1552 }
1553
1554 for _, p := range rt.pages {
1555 b := rt.blocks[p]
1556
1557
1558
1559
1560 if len(b.entries)&1 != 0 {
1561 b.entries = append(b.entries, peBaseRelocEntry{})
1562 }
1563
1564 const sizeOfPEbaseRelocBlock = 8
1565 blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2)
1566 out.Write32(p)
1567 out.Write32(blockSize)
1568
1569 for _, e := range b.entries {
1570 out.Write16(e.typeOff)
1571 }
1572 }
1573 }
1574
1575 func addPEBaseRelocSym(ldr *loader.Loader, s loader.Sym, rt *peBaseRelocTable) {
1576 relocs := ldr.Relocs(s)
1577 for ri := 0; ri < relocs.Count(); ri++ {
1578 r := relocs.At(ri)
1579 if r.Type() >= objabi.ElfRelocOffset {
1580 continue
1581 }
1582 if r.Siz() == 0 {
1583 continue
1584 }
1585 if r.Type() == objabi.R_DWARFFILEREF {
1586 continue
1587 }
1588 rs := r.Sym()
1589 if rs == 0 {
1590 continue
1591 }
1592 if !ldr.AttrReachable(s) {
1593 continue
1594 }
1595
1596 switch r.Type() {
1597 default:
1598 case objabi.R_ADDR:
1599 rt.addentry(ldr, s, &r)
1600 }
1601 }
1602 }
1603
1604 func needPEBaseReloc(ctxt *Link) bool {
1605
1606
1607 if (ctxt.Arch.Family == sys.I386 || ctxt.Arch.Family == sys.AMD64) && ctxt.BuildMode != BuildModePIE {
1608 return false
1609 }
1610 return true
1611 }
1612
1613 func addPEBaseReloc(ctxt *Link) {
1614 if !needPEBaseReloc(ctxt) {
1615 return
1616 }
1617
1618 var rt peBaseRelocTable
1619 rt.init(ctxt)
1620
1621
1622 ldr := ctxt.loader
1623 for _, s := range ctxt.Textp {
1624 addPEBaseRelocSym(ldr, s, &rt)
1625 }
1626 for _, s := range ctxt.datap {
1627 addPEBaseRelocSym(ldr, s, &rt)
1628 }
1629
1630
1631 startoff := ctxt.Out.Offset()
1632 rt.write(ctxt)
1633 size := ctxt.Out.Offset() - startoff
1634
1635
1636 rsect := pefile.addSection(".reloc", int(size), int(size))
1637 rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
1638 rsect.checkOffset(startoff)
1639 rsect.pad(ctxt.Out, uint32(size))
1640
1641 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
1642 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
1643 }
1644
1645 func (ctxt *Link) dope() {
1646 initdynimport(ctxt)
1647 initdynexport(ctxt)
1648 writeSEH(ctxt)
1649 }
1650
1651 func setpersrc(ctxt *Link, syms []loader.Sym) {
1652 if len(rsrcsyms) != 0 {
1653 Errorf("too many .rsrc sections")
1654 }
1655 rsrcsyms = syms
1656 }
1657
1658 func addpersrc(ctxt *Link) {
1659 if len(rsrcsyms) == 0 {
1660 return
1661 }
1662
1663 var size int64
1664 for _, rsrcsym := range rsrcsyms {
1665 size += ctxt.loader.SymSize(rsrcsym)
1666 }
1667 h := pefile.addSection(".rsrc", int(size), int(size))
1668 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA
1669 h.checkOffset(ctxt.Out.Offset())
1670
1671 for _, rsrcsym := range rsrcsyms {
1672
1673
1674
1675 splitResources := strings.Contains(ctxt.loader.SymName(rsrcsym), ".rsrc$")
1676 relocs := ctxt.loader.Relocs(rsrcsym)
1677 data := ctxt.loader.Data(rsrcsym)
1678 for ri := 0; ri < relocs.Count(); ri++ {
1679 r := relocs.At(ri)
1680 p := data[r.Off():]
1681 val := uint32(int64(h.virtualAddress) + r.Add())
1682 if splitResources {
1683
1684
1685
1686
1687
1688
1689
1690
1691 val += uint32(len(data))
1692 }
1693 binary.LittleEndian.PutUint32(p, val)
1694 }
1695 ctxt.Out.Write(data)
1696 }
1697 h.pad(ctxt.Out, uint32(size))
1698
1699
1700 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
1701 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
1702 }
1703
1704 func asmbPe(ctxt *Link) {
1705 t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length))
1706 t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
1707 if ctxt.LinkMode == LinkExternal {
1708
1709
1710 t.characteristics |= IMAGE_SCN_ALIGN_32BYTES
1711 }
1712 t.checkSegment(&Segtext)
1713 pefile.textSect = t
1714
1715 ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length))
1716 ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
1717 if ctxt.LinkMode == LinkExternal {
1718
1719
1720 ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
1721 }
1722 ro.checkSegment(&Segrodata)
1723 pefile.rdataSect = ro
1724
1725 var d *peSection
1726 if ctxt.LinkMode != LinkExternal {
1727 d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
1728 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
1729 d.checkSegment(&Segdata)
1730 pefile.dataSect = d
1731 } else {
1732 d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
1733 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
1734 d.checkSegment(&Segdata)
1735 pefile.dataSect = d
1736
1737 b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
1738 b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
1739 b.pointerToRawData = 0
1740 pefile.bssSect = b
1741 }
1742
1743 pefile.addSEH(ctxt)
1744 pefile.addDWARF()
1745
1746 if ctxt.LinkMode == LinkExternal {
1747 pefile.ctorsSect = pefile.addInitArray(ctxt)
1748 }
1749
1750 ctxt.Out.SeekSet(int64(pefile.nextFileOffset))
1751 if ctxt.LinkMode != LinkExternal {
1752 addimports(ctxt, d)
1753 addexports(ctxt)
1754 addPEBaseReloc(ctxt)
1755 }
1756 pefile.writeSymbolTableAndStringTable(ctxt)
1757 addpersrc(ctxt)
1758 if ctxt.LinkMode == LinkExternal {
1759 pefile.emitRelocations(ctxt)
1760 }
1761
1762 pewrite(ctxt)
1763 }
1764
View as plain text