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