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 PEBASE = 0
1066 }
1067
1068 var sh [16]pe.SectionHeader32
1069 var fh pe.FileHeader
1070 PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
1071 if ctxt.LinkMode != LinkExternal {
1072 PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
1073 } else {
1074 PESECTHEADR = 0
1075 }
1076 pefile.nextSectOffset = uint32(PESECTHEADR)
1077 pefile.nextFileOffset = uint32(PEFILEHEADR)
1078
1079 if ctxt.LinkMode == LinkInternal {
1080
1081 for _, name := range [2]string{"__image_base__", "_image_base__"} {
1082 sb := ctxt.loader.CreateSymForUpdate(name, 0)
1083 sb.SetType(sym.SDATA)
1084 sb.SetValue(PEBASE)
1085 ctxt.loader.SetAttrSpecial(sb.Sym(), true)
1086 ctxt.loader.SetAttrLocal(sb.Sym(), true)
1087 }
1088 }
1089
1090 HEADR = PEFILEHEADR
1091 if *FlagTextAddr == -1 {
1092 *FlagTextAddr = PEBASE + int64(PESECTHEADR)
1093 }
1094 if *FlagRound == -1 {
1095 *FlagRound = int(PESECTALIGN)
1096 }
1097 }
1098
1099 func pewrite(ctxt *Link) {
1100 ctxt.Out.SeekSet(0)
1101 if ctxt.LinkMode != LinkExternal {
1102 ctxt.Out.Write(dosstub)
1103 ctxt.Out.WriteStringN("PE", 4)
1104 }
1105
1106 pefile.writeFileHeader(ctxt)
1107
1108 pefile.writeOptionalHeader(ctxt)
1109
1110 for _, sect := range pefile.sections {
1111 sect.write(ctxt.Out, ctxt.LinkMode)
1112 }
1113 }
1114
1115 func strput(out *OutBuf, s string) {
1116 out.WriteString(s)
1117 out.Write8(0)
1118
1119 if (len(s)+1)%2 != 0 {
1120 out.Write8(0)
1121 }
1122 }
1123
1124 func initdynimport(ctxt *Link) *Dll {
1125 ldr := ctxt.loader
1126 var d *Dll
1127
1128 dr = nil
1129 var m *Imp
1130 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1131 if !ldr.AttrReachable(s) || ldr.SymType(s) != sym.SDYNIMPORT {
1132 continue
1133 }
1134 dynlib := ldr.SymDynimplib(s)
1135 for d = dr; d != nil; d = d.next {
1136 if d.name == dynlib {
1137 m = new(Imp)
1138 break
1139 }
1140 }
1141
1142 if d == nil {
1143 d = new(Dll)
1144 d.name = dynlib
1145 d.next = dr
1146 dr = d
1147 m = new(Imp)
1148 }
1149
1150
1151
1152
1153
1154 m.argsize = -1
1155 extName := ldr.SymExtname(s)
1156 if i := strings.IndexByte(extName, '%'); i >= 0 {
1157 var err error
1158 m.argsize, err = strconv.Atoi(extName[i+1:])
1159 if err != nil {
1160 ctxt.Errorf(s, "failed to parse stdcall decoration: %v", err)
1161 }
1162 m.argsize *= ctxt.Arch.PtrSize
1163 ldr.SetSymExtname(s, extName[:i])
1164 }
1165
1166 m.s = s
1167 m.next = d.ms
1168 d.ms = m
1169 }
1170
1171 if ctxt.IsExternal() {
1172
1173 for d := dr; d != nil; d = d.next {
1174 for m = d.ms; m != nil; m = m.next {
1175 sb := ldr.MakeSymbolUpdater(m.s)
1176 sb.SetType(sym.SDATA)
1177 sb.Grow(int64(ctxt.Arch.PtrSize))
1178 dynName := sb.Extname()
1179
1180 if ctxt.Is386() && m.argsize >= 0 {
1181 dynName += fmt.Sprintf("@%d", m.argsize)
1182 }
1183 dynSym := ldr.CreateSymForUpdate(dynName, 0)
1184 dynSym.SetType(sym.SHOSTOBJ)
1185 r, _ := sb.AddRel(objabi.R_ADDR)
1186 r.SetSym(dynSym.Sym())
1187 r.SetSiz(uint8(ctxt.Arch.PtrSize))
1188 }
1189 }
1190 } else {
1191 dynamic := ldr.CreateSymForUpdate(".windynamic", 0)
1192 dynamic.SetType(sym.SWINDOWS)
1193 for d := dr; d != nil; d = d.next {
1194 for m = d.ms; m != nil; m = m.next {
1195 sb := ldr.MakeSymbolUpdater(m.s)
1196 sb.SetType(sym.SWINDOWS)
1197 sb.SetValue(dynamic.Size())
1198 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
1199 dynamic.AddInteriorSym(m.s)
1200 }
1201
1202 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
1203 }
1204 }
1205
1206 return dr
1207 }
1208
1209
1210
1211 func peimporteddlls() []string {
1212 var dlls []string
1213
1214 for d := dr; d != nil; d = d.next {
1215 dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
1216 }
1217
1218 return dlls
1219 }
1220
1221 func addimports(ctxt *Link, datsect *peSection) {
1222 ldr := ctxt.loader
1223 startoff := ctxt.Out.Offset()
1224 dynamic := ldr.LookupOrCreateSym(".windynamic", 0)
1225
1226
1227 n := uint64(0)
1228
1229 for d := dr; d != nil; d = d.next {
1230 n++
1231 }
1232 ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
1233
1234
1235 for d := dr; d != nil; d = d.next {
1236 d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff)
1237 strput(ctxt.Out, d.name)
1238 }
1239
1240
1241 for d := dr; d != nil; d = d.next {
1242 for m := d.ms; m != nil; m = m.next {
1243 m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
1244 ctxt.Out.Write16(0)
1245 strput(ctxt.Out, ldr.SymExtname(m.s))
1246 }
1247 }
1248
1249
1250 oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff)
1251
1252 n = uint64(ctxt.Out.Offset())
1253 for d := dr; d != nil; d = d.next {
1254 d.thunkoff = uint64(ctxt.Out.Offset()) - n
1255 for m := d.ms; m != nil; m = m.next {
1256 if pe64 != 0 {
1257 ctxt.Out.Write64(m.off)
1258 } else {
1259 ctxt.Out.Write32(uint32(m.off))
1260 }
1261 }
1262
1263 if pe64 != 0 {
1264 ctxt.Out.Write64(0)
1265 } else {
1266 ctxt.Out.Write32(0)
1267 }
1268 }
1269
1270
1271 n = uint64(ctxt.Out.Offset()) - uint64(startoff)
1272
1273 isect := pefile.addSection(".idata", int(n), int(n))
1274 isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
1275 isect.checkOffset(startoff)
1276 isect.pad(ctxt.Out, uint32(n))
1277 endoff := ctxt.Out.Offset()
1278
1279
1280 ftbase := uint64(ldr.SymValue(dynamic)) - uint64(datsect.virtualAddress) - uint64(PEBASE)
1281
1282 ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase))
1283 for d := dr; d != nil; d = d.next {
1284 for m := d.ms; m != nil; m = m.next {
1285 if pe64 != 0 {
1286 ctxt.Out.Write64(m.off)
1287 } else {
1288 ctxt.Out.Write32(uint32(m.off))
1289 }
1290 }
1291
1292 if pe64 != 0 {
1293 ctxt.Out.Write64(0)
1294 } else {
1295 ctxt.Out.Write32(0)
1296 }
1297 }
1298
1299
1300 out := ctxt.Out
1301 out.SeekSet(startoff)
1302
1303 for d := dr; d != nil; d = d.next {
1304 out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff))
1305 out.Write32(0)
1306 out.Write32(0)
1307 out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff))
1308 out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff))
1309 }
1310
1311 out.Write32(0)
1312 out.Write32(0)
1313 out.Write32(0)
1314 out.Write32(0)
1315 out.Write32(0)
1316
1317
1318 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
1319 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
1320 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(ldr.SymValue(dynamic) - PEBASE)
1321 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(ldr.SymSize(dynamic))
1322
1323 out.SeekSet(endoff)
1324 }
1325
1326 func initdynexport(ctxt *Link) {
1327 ldr := ctxt.loader
1328 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1329 if !ldr.AttrReachable(s) || !ldr.AttrCgoExportDynamic(s) {
1330 continue
1331 }
1332 if len(dexport)+1 > cap(dexport) {
1333 ctxt.Errorf(s, "pe dynexport table is full")
1334 errorexit()
1335 }
1336
1337 dexport = append(dexport, s)
1338 }
1339
1340 sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) })
1341 }
1342
1343 func addexports(ctxt *Link) {
1344 ldr := ctxt.loader
1345 var e IMAGE_EXPORT_DIRECTORY
1346
1347 nexport := len(dexport)
1348 size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
1349 for _, s := range dexport {
1350 size += len(ldr.SymExtname(s)) + 1
1351 }
1352
1353 if nexport == 0 {
1354 return
1355 }
1356
1357 sect := pefile.addSection(".edata", size, size)
1358 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
1359 sect.checkOffset(ctxt.Out.Offset())
1360 va := int(sect.virtualAddress)
1361 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
1362 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
1363
1364 vaName := va + binary.Size(&e) + nexport*4
1365 vaAddr := va + binary.Size(&e)
1366 vaNa := va + binary.Size(&e) + nexport*8
1367
1368 e.Characteristics = 0
1369 e.MajorVersion = 0
1370 e.MinorVersion = 0
1371 e.NumberOfFunctions = uint32(nexport)
1372 e.NumberOfNames = uint32(nexport)
1373 e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10
1374 e.Base = 1
1375 e.AddressOfFunctions = uint32(vaAddr)
1376 e.AddressOfNames = uint32(vaName)
1377 e.AddressOfNameOrdinals = uint32(vaNa)
1378
1379 out := ctxt.Out
1380
1381
1382 binary.Write(out, binary.LittleEndian, &e)
1383
1384
1385 for _, s := range dexport {
1386 out.Write32(uint32(ldr.SymValue(s) - PEBASE))
1387 }
1388
1389
1390 v := int(e.Name + uint32(len(*flagOutfile)) + 1)
1391
1392 for _, s := range dexport {
1393 out.Write32(uint32(v))
1394 v += len(ldr.SymExtname(s)) + 1
1395 }
1396
1397
1398 for i := 0; i < nexport; i++ {
1399 out.Write16(uint16(i))
1400 }
1401
1402
1403 out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
1404
1405 for _, s := range dexport {
1406 name := ldr.SymExtname(s)
1407 out.WriteStringN(name, len(name)+1)
1408 }
1409 sect.pad(out, uint32(size))
1410 }
1411
1412
1413 type peBaseRelocEntry struct {
1414 typeOff uint16
1415 }
1416
1417
1418
1419
1420
1421
1422 type peBaseRelocBlock struct {
1423 entries []peBaseRelocEntry
1424 }
1425
1426
1427
1428
1429 type pePages []uint32
1430
1431 func (p pePages) Len() int { return len(p) }
1432 func (p pePages) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
1433 func (p pePages) Less(i, j int) bool { return p[i] < p[j] }
1434
1435
1436
1437
1438
1439 type peBaseRelocTable struct {
1440 blocks map[uint32]peBaseRelocBlock
1441
1442
1443
1444 pages pePages
1445 }
1446
1447 func (rt *peBaseRelocTable) init(ctxt *Link) {
1448 rt.blocks = make(map[uint32]peBaseRelocBlock)
1449 }
1450
1451 func (rt *peBaseRelocTable) addentry(ldr *loader.Loader, s loader.Sym, r *loader.Reloc) {
1452
1453
1454 const pageSize = 0x1000
1455 const pageMask = pageSize - 1
1456
1457 addr := ldr.SymValue(s) + int64(r.Off()) - int64(PEBASE)
1458 page := uint32(addr &^ pageMask)
1459 off := uint32(addr & pageMask)
1460
1461 b, ok := rt.blocks[page]
1462 if !ok {
1463 rt.pages = append(rt.pages, page)
1464 }
1465
1466 e := peBaseRelocEntry{
1467 typeOff: uint16(off & 0xFFF),
1468 }
1469
1470
1471 switch r.Siz() {
1472 default:
1473 Exitf("unsupported relocation size %d\n", r.Siz)
1474 case 4:
1475 e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12)
1476 case 8:
1477 e.typeOff |= uint16(IMAGE_REL_BASED_DIR64 << 12)
1478 }
1479
1480 b.entries = append(b.entries, e)
1481 rt.blocks[page] = b
1482 }
1483
1484 func (rt *peBaseRelocTable) write(ctxt *Link) {
1485 out := ctxt.Out
1486
1487
1488 sort.Sort(rt.pages)
1489
1490 for _, p := range rt.pages {
1491 b := rt.blocks[p]
1492 const sizeOfPEbaseRelocBlock = 8
1493 blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2)
1494 out.Write32(p)
1495 out.Write32(blockSize)
1496
1497 for _, e := range b.entries {
1498 out.Write16(e.typeOff)
1499 }
1500 }
1501 }
1502
1503 func addPEBaseRelocSym(ldr *loader.Loader, s loader.Sym, rt *peBaseRelocTable) {
1504 relocs := ldr.Relocs(s)
1505 for ri := 0; ri < relocs.Count(); ri++ {
1506 r := relocs.At(ri)
1507 if r.Type() >= objabi.ElfRelocOffset {
1508 continue
1509 }
1510 if r.Siz() == 0 {
1511 continue
1512 }
1513 if r.Type() == objabi.R_DWARFFILEREF {
1514 continue
1515 }
1516 rs := r.Sym()
1517 if rs == 0 {
1518 continue
1519 }
1520 if !ldr.AttrReachable(s) {
1521 continue
1522 }
1523
1524 switch r.Type() {
1525 default:
1526 case objabi.R_ADDR:
1527 rt.addentry(ldr, s, &r)
1528 }
1529 }
1530 }
1531
1532 func needPEBaseReloc(ctxt *Link) bool {
1533
1534
1535 if (ctxt.Arch.Family == sys.I386 || ctxt.Arch.Family == sys.AMD64) && ctxt.BuildMode != BuildModePIE {
1536 return false
1537 }
1538 return true
1539 }
1540
1541 func addPEBaseReloc(ctxt *Link) {
1542 if !needPEBaseReloc(ctxt) {
1543 return
1544 }
1545
1546 var rt peBaseRelocTable
1547 rt.init(ctxt)
1548
1549
1550 ldr := ctxt.loader
1551 for _, s := range ctxt.Textp {
1552 addPEBaseRelocSym(ldr, s, &rt)
1553 }
1554 for _, s := range ctxt.datap {
1555 addPEBaseRelocSym(ldr, s, &rt)
1556 }
1557
1558
1559 startoff := ctxt.Out.Offset()
1560 rt.write(ctxt)
1561 size := ctxt.Out.Offset() - startoff
1562
1563
1564 rsect := pefile.addSection(".reloc", int(size), int(size))
1565 rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
1566 rsect.checkOffset(startoff)
1567 rsect.pad(ctxt.Out, uint32(size))
1568
1569 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
1570 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
1571 }
1572
1573 func (ctxt *Link) dope() {
1574 initdynimport(ctxt)
1575 initdynexport(ctxt)
1576 }
1577
1578 func setpersrc(ctxt *Link, syms []loader.Sym) {
1579 if len(rsrcsyms) != 0 {
1580 Errorf(nil, "too many .rsrc sections")
1581 }
1582 rsrcsyms = syms
1583 }
1584
1585 func addpersrc(ctxt *Link) {
1586 if len(rsrcsyms) == 0 {
1587 return
1588 }
1589
1590 var size int64
1591 for _, rsrcsym := range rsrcsyms {
1592 size += ctxt.loader.SymSize(rsrcsym)
1593 }
1594 h := pefile.addSection(".rsrc", int(size), int(size))
1595 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA
1596 h.checkOffset(ctxt.Out.Offset())
1597
1598 for _, rsrcsym := range rsrcsyms {
1599
1600
1601
1602 splitResources := strings.Contains(ctxt.loader.SymName(rsrcsym), ".rsrc$")
1603 relocs := ctxt.loader.Relocs(rsrcsym)
1604 data := ctxt.loader.Data(rsrcsym)
1605 for ri := 0; ri < relocs.Count(); ri++ {
1606 r := relocs.At(ri)
1607 p := data[r.Off():]
1608 val := uint32(int64(h.virtualAddress) + r.Add())
1609 if splitResources {
1610
1611
1612
1613
1614
1615
1616
1617
1618 val += uint32(len(data))
1619 }
1620 binary.LittleEndian.PutUint32(p, val)
1621 }
1622 ctxt.Out.Write(data)
1623 }
1624 h.pad(ctxt.Out, uint32(size))
1625
1626
1627 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
1628 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
1629 }
1630
1631 func asmbPe(ctxt *Link) {
1632 t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length))
1633 t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
1634 if ctxt.LinkMode == LinkExternal {
1635
1636
1637 t.characteristics |= IMAGE_SCN_ALIGN_32BYTES
1638 }
1639 t.checkSegment(&Segtext)
1640 pefile.textSect = t
1641
1642 ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length))
1643 ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
1644 if ctxt.LinkMode == LinkExternal {
1645
1646
1647 ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
1648 }
1649 ro.checkSegment(&Segrodata)
1650 pefile.rdataSect = ro
1651
1652 var d *peSection
1653 if ctxt.LinkMode != LinkExternal {
1654 d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
1655 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
1656 d.checkSegment(&Segdata)
1657 pefile.dataSect = d
1658 } else {
1659 d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
1660 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
1661 d.checkSegment(&Segdata)
1662 pefile.dataSect = d
1663
1664 b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
1665 b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
1666 b.pointerToRawData = 0
1667 pefile.bssSect = b
1668 }
1669
1670 pefile.addDWARF()
1671
1672 if ctxt.LinkMode == LinkExternal {
1673 pefile.ctorsSect = pefile.addInitArray(ctxt)
1674 }
1675
1676 ctxt.Out.SeekSet(int64(pefile.nextFileOffset))
1677 if ctxt.LinkMode != LinkExternal {
1678 addimports(ctxt, d)
1679 addexports(ctxt)
1680 addPEBaseReloc(ctxt)
1681 }
1682 pefile.writeSymbolTableAndStringTable(ctxt)
1683 addpersrc(ctxt)
1684 if ctxt.LinkMode == LinkExternal {
1685 pefile.emitRelocations(ctxt)
1686 }
1687
1688 pewrite(ctxt)
1689 }
1690
View as plain text