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