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 (ldr.IsContentHashed(s) && ldr.SymType(s).IsText()) {
942 class = IMAGE_SYM_CLASS_STATIC
943 }
944 f.writeSymbol(ctxt.Out, ldr, s, name, value, sect, peSymType, uint8(class))
945 }
946
947 if ctxt.LinkMode == LinkExternal {
948
949
950 for _, pesect := range f.sections {
951 s := ldr.LookupOrCreateSym(pesect.name, 0)
952 f.writeSymbol(ctxt.Out, ldr, s, pesect.name, 0, pesect.index, IMAGE_SYM_TYPE_NULL, IMAGE_SYM_CLASS_STATIC)
953 }
954 }
955
956
957 s := ldr.Lookup("runtime.text", 0)
958 if ldr.SymType(s).IsText() {
959 addsym(s)
960 }
961 s = ldr.Lookup("runtime.etext", 0)
962 if ldr.SymType(s).IsText() {
963 addsym(s)
964 }
965
966
967 for _, s := range ctxt.Textp {
968 addsym(s)
969 }
970
971 shouldBeInSymbolTable := func(s loader.Sym) bool {
972 if ldr.AttrNotInSymbolTable(s) {
973 return false
974 }
975 name := ldr.SymName(s)
976 if name == "" || name[0] == '.' {
977 return false
978 }
979 return true
980 }
981
982
983 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
984 if !ldr.AttrReachable(s) {
985 continue
986 }
987 t := ldr.SymType(s)
988 if t >= sym.SELFRXSECT && t < sym.SFirstUnallocated {
989 if t == sym.STLSBSS {
990 continue
991 }
992 if !shouldBeInSymbolTable(s) {
993 continue
994 }
995 addsym(s)
996 }
997
998 switch t {
999 case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
1000 addsym(s)
1001 default:
1002 if len(isLabel) > 0 && isLabel[s] {
1003 addsym(s)
1004 }
1005 }
1006 }
1007 }
1008
1009
1010 func (f *peFile) writeSymbolTableAndStringTable(ctxt *Link) {
1011 f.symtabOffset = ctxt.Out.Offset()
1012
1013
1014 if !*FlagS || ctxt.LinkMode == LinkExternal {
1015 f.writeSymbols(ctxt)
1016 }
1017
1018
1019 size := f.stringTable.size() + 18*f.symbolCount
1020 var h *peSection
1021 if ctxt.LinkMode != LinkExternal {
1022
1023
1024 h = f.addSection(".symtab", size, size)
1025 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
1026 h.checkOffset(f.symtabOffset)
1027 }
1028
1029
1030 f.stringTable.write(ctxt.Out)
1031 if ctxt.LinkMode != LinkExternal {
1032 h.pad(ctxt.Out, uint32(size))
1033 }
1034 }
1035
1036
1037 func (f *peFile) writeFileHeader(ctxt *Link) {
1038 var fh pe.FileHeader
1039
1040 switch ctxt.Arch.Family {
1041 default:
1042 Exitf("unknown PE architecture: %v", ctxt.Arch.Family)
1043 case sys.AMD64:
1044 fh.Machine = pe.IMAGE_FILE_MACHINE_AMD64
1045 case sys.I386:
1046 fh.Machine = pe.IMAGE_FILE_MACHINE_I386
1047 case sys.ARM64:
1048 fh.Machine = pe.IMAGE_FILE_MACHINE_ARM64
1049 }
1050
1051 fh.NumberOfSections = uint16(len(f.sections))
1052
1053
1054
1055 fh.TimeDateStamp = 0
1056
1057 if ctxt.LinkMode != LinkExternal {
1058 fh.Characteristics = pe.IMAGE_FILE_EXECUTABLE_IMAGE
1059 switch ctxt.Arch.Family {
1060 case sys.AMD64, sys.I386:
1061 if ctxt.BuildMode != BuildModePIE {
1062 fh.Characteristics |= pe.IMAGE_FILE_RELOCS_STRIPPED
1063 }
1064 }
1065 }
1066 if pe64 {
1067 var oh64 pe.OptionalHeader64
1068 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
1069 fh.Characteristics |= pe.IMAGE_FILE_LARGE_ADDRESS_AWARE
1070 } else {
1071 var oh pe.OptionalHeader32
1072 fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
1073 fh.Characteristics |= pe.IMAGE_FILE_32BIT_MACHINE
1074 }
1075
1076 fh.PointerToSymbolTable = uint32(f.symtabOffset)
1077 fh.NumberOfSymbols = uint32(f.symbolCount)
1078
1079 binary.Write(ctxt.Out, binary.LittleEndian, &fh)
1080 }
1081
1082
1083 func (f *peFile) writeOptionalHeader(ctxt *Link) {
1084 var oh pe.OptionalHeader32
1085 var oh64 pe.OptionalHeader64
1086
1087 if pe64 {
1088 oh64.Magic = 0x20b
1089 } else {
1090 oh.Magic = 0x10b
1091 oh.BaseOfData = f.dataSect.virtualAddress
1092 }
1093
1094
1095 oh64.MajorLinkerVersion = 3
1096 oh.MajorLinkerVersion = 3
1097 oh64.MinorLinkerVersion = 0
1098 oh.MinorLinkerVersion = 0
1099 oh64.SizeOfCode = f.textSect.sizeOfRawData
1100 oh.SizeOfCode = f.textSect.sizeOfRawData
1101 oh64.SizeOfInitializedData = f.dataSect.sizeOfRawData
1102 oh.SizeOfInitializedData = f.dataSect.sizeOfRawData
1103 oh64.SizeOfUninitializedData = 0
1104 oh.SizeOfUninitializedData = 0
1105 if ctxt.LinkMode != LinkExternal {
1106 oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
1107 oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
1108 }
1109 oh64.BaseOfCode = f.textSect.virtualAddress
1110 oh.BaseOfCode = f.textSect.virtualAddress
1111 oh64.ImageBase = uint64(PEBASE)
1112 oh.ImageBase = uint32(PEBASE)
1113 oh64.SectionAlignment = uint32(PESECTALIGN)
1114 oh.SectionAlignment = uint32(PESECTALIGN)
1115 oh64.FileAlignment = uint32(PEFILEALIGN)
1116 oh.FileAlignment = uint32(PEFILEALIGN)
1117 oh64.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
1118 oh.MajorOperatingSystemVersion = PeMinimumTargetMajorVersion
1119 oh64.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
1120 oh.MinorOperatingSystemVersion = PeMinimumTargetMinorVersion
1121 oh64.MajorImageVersion = 1
1122 oh.MajorImageVersion = 1
1123 oh64.MinorImageVersion = 0
1124 oh.MinorImageVersion = 0
1125 oh64.MajorSubsystemVersion = PeMinimumTargetMajorVersion
1126 oh.MajorSubsystemVersion = PeMinimumTargetMajorVersion
1127 oh64.MinorSubsystemVersion = PeMinimumTargetMinorVersion
1128 oh.MinorSubsystemVersion = PeMinimumTargetMinorVersion
1129 oh64.SizeOfImage = f.nextSectOffset
1130 oh.SizeOfImage = f.nextSectOffset
1131 oh64.SizeOfHeaders = uint32(PEFILEHEADR)
1132 oh.SizeOfHeaders = uint32(PEFILEHEADR)
1133 if windowsgui {
1134 oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
1135 oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_GUI
1136 } else {
1137 oh64.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
1138 oh.Subsystem = pe.IMAGE_SUBSYSTEM_WINDOWS_CUI
1139 }
1140
1141
1142 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
1143 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
1144
1145
1146 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
1147 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_NX_COMPAT
1148
1149
1150 if needPEBaseReloc(ctxt) {
1151 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
1152 oh.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
1153 }
1154
1155
1156 if ctxt.BuildMode == BuildModePIE {
1157 oh64.DllCharacteristics |= pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
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
1184 oh64.SizeOfStackReserve = 0x00200000
1185 if !iscgo {
1186 oh64.SizeOfStackCommit = 0x00001000
1187 } else {
1188
1189
1190
1191 oh64.SizeOfStackCommit = 0x00200000 - 0x2000
1192 }
1193
1194 oh.SizeOfStackReserve = 0x00100000
1195 if !iscgo {
1196 oh.SizeOfStackCommit = 0x00001000
1197 } else {
1198 oh.SizeOfStackCommit = 0x00100000 - 0x2000
1199 }
1200
1201 oh64.SizeOfHeapReserve = 0x00100000
1202 oh.SizeOfHeapReserve = 0x00100000
1203 oh64.SizeOfHeapCommit = 0x00001000
1204 oh.SizeOfHeapCommit = 0x00001000
1205 oh64.NumberOfRvaAndSizes = 16
1206 oh.NumberOfRvaAndSizes = 16
1207
1208 if pe64 {
1209 oh64.DataDirectory = f.dataDirectory
1210 } else {
1211 oh.DataDirectory = f.dataDirectory
1212 }
1213
1214 if pe64 {
1215 binary.Write(ctxt.Out, binary.LittleEndian, &oh64)
1216 } else {
1217 binary.Write(ctxt.Out, binary.LittleEndian, &oh)
1218 }
1219 }
1220
1221 var pefile peFile
1222
1223 func Peinit(ctxt *Link) {
1224 var l int
1225
1226 if ctxt.Arch.PtrSize == 8 {
1227
1228 pe64 = true
1229 var oh64 pe.OptionalHeader64
1230 l = binary.Size(&oh64)
1231 } else {
1232
1233 var oh pe.OptionalHeader32
1234 l = binary.Size(&oh)
1235 }
1236
1237 if ctxt.LinkMode == LinkExternal {
1238
1239
1240
1241
1242 PESECTALIGN = 32
1243 PEFILEALIGN = 0
1244
1245 PEBASE = 0
1246 } else {
1247
1248 if pe64 {
1249 PEBASE = 0x140000000
1250 } else {
1251 PEBASE = 0x400000
1252 }
1253 }
1254
1255 var sh [16]pe.SectionHeader32
1256 var fh pe.FileHeader
1257 PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
1258 if ctxt.LinkMode != LinkExternal {
1259 PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
1260 } else {
1261 PESECTHEADR = 0
1262 }
1263 pefile.nextSectOffset = uint32(PESECTHEADR)
1264 pefile.nextFileOffset = uint32(PEFILEHEADR)
1265
1266 if ctxt.LinkMode == LinkInternal {
1267
1268 for _, name := range [2]string{"__image_base__", "_image_base__"} {
1269 sb := ctxt.loader.CreateSymForUpdate(name, 0)
1270 sb.SetType(sym.SDATA)
1271 sb.SetValue(PEBASE)
1272 ctxt.loader.SetAttrSpecial(sb.Sym(), true)
1273 ctxt.loader.SetAttrLocal(sb.Sym(), true)
1274 }
1275
1276
1277
1278 sb := ctxt.loader.CreateSymForUpdate("_load_config_used", 0)
1279 sb.SetType(sym.SRODATA)
1280 sb.SetAlign(int32(ctxt.Arch.PtrSize))
1281 var buf bytes.Buffer
1282 if pe64 {
1283 lc := IMAGE_LOAD_CONFIG_DIRECTORY64{
1284 Size: uint32(binary.Size(&IMAGE_LOAD_CONFIG_DIRECTORY64{})),
1285 GuardFlags: IMAGE_GUARD_SECURITY_COOKIE_UNUSED,
1286 }
1287 binary.Write(&buf, binary.LittleEndian, &lc)
1288 } else {
1289 lc := IMAGE_LOAD_CONFIG_DIRECTORY32{
1290 Size: uint32(binary.Size(&IMAGE_LOAD_CONFIG_DIRECTORY32{})),
1291 GuardFlags: IMAGE_GUARD_SECURITY_COOKIE_UNUSED,
1292 }
1293 binary.Write(&buf, binary.LittleEndian, &lc)
1294 }
1295 sb.SetData(buf.Bytes())
1296 sb.SetSize(int64(buf.Len()))
1297 ctxt.loader.SetAttrReachable(sb.Sym(), true)
1298 }
1299
1300 HEADR = PEFILEHEADR
1301 if *FlagRound == -1 {
1302 *FlagRound = PESECTALIGN
1303 }
1304 if *FlagTextAddr == -1 {
1305 *FlagTextAddr = Rnd(PEBASE, *FlagRound) + int64(PESECTHEADR)
1306 }
1307 }
1308
1309 func pewrite(ctxt *Link) {
1310 ctxt.Out.SeekSet(0)
1311 if ctxt.LinkMode != LinkExternal {
1312 ctxt.Out.Write(dosstub)
1313 ctxt.Out.WriteStringN("PE", 4)
1314 }
1315
1316 pefile.writeFileHeader(ctxt)
1317
1318 pefile.writeOptionalHeader(ctxt)
1319
1320 for _, sect := range pefile.sections {
1321 sect.write(ctxt.Out, ctxt.LinkMode)
1322 }
1323 }
1324
1325 func strput(out *OutBuf, s string) {
1326 out.WriteString(s)
1327 out.Write8(0)
1328
1329 if (len(s)+1)%2 != 0 {
1330 out.Write8(0)
1331 }
1332 }
1333
1334 func initdynimport(ctxt *Link) *Dll {
1335 ldr := ctxt.loader
1336 var d *Dll
1337
1338 dr = nil
1339 var m *Imp
1340 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1341 if !ldr.AttrReachable(s) || ldr.SymType(s) != sym.SDYNIMPORT {
1342 continue
1343 }
1344 dynlib := ldr.SymDynimplib(s)
1345 for d = dr; d != nil; d = d.next {
1346 if d.name == dynlib {
1347 m = new(Imp)
1348 break
1349 }
1350 }
1351
1352 if d == nil {
1353 d = new(Dll)
1354 d.name = dynlib
1355 d.next = dr
1356 dr = d
1357 m = new(Imp)
1358 }
1359
1360
1361
1362
1363
1364 m.argsize = -1
1365 extName := ldr.SymExtname(s)
1366 if i := strings.IndexByte(extName, '%'); i >= 0 {
1367 var err error
1368 m.argsize, err = strconv.Atoi(extName[i+1:])
1369 if err != nil {
1370 ctxt.Errorf(s, "failed to parse stdcall decoration: %v", err)
1371 }
1372 m.argsize *= ctxt.Arch.PtrSize
1373 ldr.SetSymExtname(s, extName[:i])
1374 }
1375
1376 m.s = s
1377 m.next = d.ms
1378 d.ms = m
1379 }
1380
1381 if ctxt.IsExternal() {
1382
1383 for d := dr; d != nil; d = d.next {
1384 for m = d.ms; m != nil; m = m.next {
1385 sb := ldr.MakeSymbolUpdater(m.s)
1386 sb.SetType(sym.SDATA)
1387 sb.Grow(int64(ctxt.Arch.PtrSize))
1388 dynName := sb.Extname()
1389
1390 if ctxt.Is386() && m.argsize >= 0 {
1391 dynName += fmt.Sprintf("@%d", m.argsize)
1392 }
1393 dynSym := ldr.CreateSymForUpdate(dynName, 0)
1394 dynSym.SetType(sym.SHOSTOBJ)
1395 r, _ := sb.AddRel(objabi.R_ADDR)
1396 r.SetSym(dynSym.Sym())
1397 r.SetSiz(uint8(ctxt.Arch.PtrSize))
1398 }
1399 }
1400 } else {
1401 dynamic := ldr.CreateSymForUpdate(".windynamic", 0)
1402 dynamic.SetType(sym.SWINDOWS)
1403 for d := dr; d != nil; d = d.next {
1404 for m = d.ms; m != nil; m = m.next {
1405 sb := ldr.MakeSymbolUpdater(m.s)
1406 sb.SetType(sym.SWINDOWS)
1407 sb.SetValue(dynamic.Size())
1408 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
1409 dynamic.AddInteriorSym(m.s)
1410 }
1411
1412 dynamic.SetSize(dynamic.Size() + int64(ctxt.Arch.PtrSize))
1413 }
1414 }
1415
1416 return dr
1417 }
1418
1419
1420
1421 func peimporteddlls() []string {
1422 var dlls []string
1423
1424 for d := dr; d != nil; d = d.next {
1425 dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
1426 }
1427
1428 return dlls
1429 }
1430
1431 func addimports(ctxt *Link, datsect *peSection) {
1432 ldr := ctxt.loader
1433 startoff := ctxt.Out.Offset()
1434 dynamic := ldr.LookupOrCreateSym(".windynamic", 0)
1435
1436
1437 n := uint64(0)
1438
1439 for d := dr; d != nil; d = d.next {
1440 n++
1441 }
1442 ctxt.Out.SeekSet(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
1443
1444
1445 for d := dr; d != nil; d = d.next {
1446 d.nameoff = uint64(ctxt.Out.Offset()) - uint64(startoff)
1447 strput(ctxt.Out, d.name)
1448 }
1449
1450
1451 for d := dr; d != nil; d = d.next {
1452 for m := d.ms; m != nil; m = m.next {
1453 m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff)
1454 ctxt.Out.Write16(0)
1455 strput(ctxt.Out, ldr.SymExtname(m.s))
1456 }
1457 }
1458
1459
1460 oftbase := uint64(ctxt.Out.Offset()) - uint64(startoff)
1461
1462 n = uint64(ctxt.Out.Offset())
1463 for d := dr; d != nil; d = d.next {
1464 d.thunkoff = uint64(ctxt.Out.Offset()) - n
1465 for m := d.ms; m != nil; m = m.next {
1466 if pe64 {
1467 ctxt.Out.Write64(m.off)
1468 } else {
1469 ctxt.Out.Write32(uint32(m.off))
1470 }
1471 }
1472
1473 if pe64 {
1474 ctxt.Out.Write64(0)
1475 } else {
1476 ctxt.Out.Write32(0)
1477 }
1478 }
1479
1480
1481 n = uint64(ctxt.Out.Offset()) - uint64(startoff)
1482
1483 isect := pefile.addSection(".idata", int(n), int(n))
1484 isect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
1485 isect.checkOffset(startoff)
1486 isect.pad(ctxt.Out, uint32(n))
1487 endoff := ctxt.Out.Offset()
1488
1489
1490 ftbase := uint64(ldr.SymValue(dynamic)) - uint64(datsect.virtualAddress) - uint64(PEBASE)
1491
1492 ctxt.Out.SeekSet(int64(uint64(datsect.pointerToRawData) + ftbase))
1493 for d := dr; d != nil; d = d.next {
1494 for m := d.ms; m != nil; m = m.next {
1495 if pe64 {
1496 ctxt.Out.Write64(m.off)
1497 } else {
1498 ctxt.Out.Write32(uint32(m.off))
1499 }
1500 }
1501
1502 if pe64 {
1503 ctxt.Out.Write64(0)
1504 } else {
1505 ctxt.Out.Write32(0)
1506 }
1507 }
1508
1509
1510 out := ctxt.Out
1511 out.SeekSet(startoff)
1512
1513 for d := dr; d != nil; d = d.next {
1514 out.Write32(uint32(uint64(isect.virtualAddress) + oftbase + d.thunkoff))
1515 out.Write32(0)
1516 out.Write32(0)
1517 out.Write32(uint32(uint64(isect.virtualAddress) + d.nameoff))
1518 out.Write32(uint32(uint64(datsect.virtualAddress) + ftbase + d.thunkoff))
1519 }
1520
1521 out.Write32(0)
1522 out.Write32(0)
1523 out.Write32(0)
1524 out.Write32(0)
1525 out.Write32(0)
1526
1527
1528 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.virtualAddress
1529 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.virtualSize
1530 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(ldr.SymValue(dynamic) - PEBASE)
1531 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(ldr.SymSize(dynamic))
1532
1533 out.SeekSet(endoff)
1534 }
1535
1536 func initdynexport(ctxt *Link) {
1537 ldr := ctxt.loader
1538 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
1539 if !ldr.AttrReachable(s) || !ldr.AttrCgoExportDynamic(s) {
1540 continue
1541 }
1542 if len(dexport) >= math.MaxUint16 {
1543 ctxt.Errorf(s, "pe dynexport table is full")
1544 errorexit()
1545 }
1546
1547 dexport = append(dexport, s)
1548 }
1549
1550 sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) })
1551 }
1552
1553 func addexports(ctxt *Link) {
1554 ldr := ctxt.loader
1555 var e IMAGE_EXPORT_DIRECTORY
1556
1557 nexport := len(dexport)
1558 size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
1559 for _, s := range dexport {
1560 size += len(ldr.SymExtname(s)) + 1
1561 }
1562
1563 if nexport == 0 {
1564 return
1565 }
1566
1567 sect := pefile.addSection(".edata", size, size)
1568 sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
1569 sect.checkOffset(ctxt.Out.Offset())
1570 va := int(sect.virtualAddress)
1571 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
1572 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.virtualSize
1573
1574 vaName := va + binary.Size(&e) + nexport*4
1575 vaAddr := va + binary.Size(&e)
1576 vaNa := va + binary.Size(&e) + nexport*8
1577
1578 e.Characteristics = 0
1579 e.MajorVersion = 0
1580 e.MinorVersion = 0
1581 e.NumberOfFunctions = uint32(nexport)
1582 e.NumberOfNames = uint32(nexport)
1583 e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10
1584 e.Base = 1
1585 e.AddressOfFunctions = uint32(vaAddr)
1586 e.AddressOfNames = uint32(vaName)
1587 e.AddressOfNameOrdinals = uint32(vaNa)
1588
1589 out := ctxt.Out
1590
1591
1592 binary.Write(out, binary.LittleEndian, &e)
1593
1594
1595 for _, s := range dexport {
1596 out.Write32(uint32(ldr.SymValue(s) - PEBASE))
1597 }
1598
1599
1600 v := int(e.Name + uint32(len(*flagOutfile)) + 1)
1601
1602 for _, s := range dexport {
1603 out.Write32(uint32(v))
1604 v += len(ldr.SymExtname(s)) + 1
1605 }
1606
1607
1608 for i := 0; i < nexport; i++ {
1609 out.Write16(uint16(i))
1610 }
1611
1612
1613 out.WriteStringN(*flagOutfile, len(*flagOutfile)+1)
1614
1615 for _, s := range dexport {
1616 name := ldr.SymExtname(s)
1617 out.WriteStringN(name, len(name)+1)
1618 }
1619 sect.pad(out, uint32(size))
1620 }
1621
1622
1623 type peBaseRelocEntry struct {
1624 typeOff uint16
1625 }
1626
1627
1628
1629
1630
1631
1632 type peBaseRelocBlock struct {
1633 entries []peBaseRelocEntry
1634 }
1635
1636
1637
1638
1639 type pePages []uint32
1640
1641
1642
1643
1644
1645 type peBaseRelocTable struct {
1646 blocks map[uint32]peBaseRelocBlock
1647
1648
1649
1650 pages pePages
1651 }
1652
1653 func (rt *peBaseRelocTable) init(ctxt *Link) {
1654 rt.blocks = make(map[uint32]peBaseRelocBlock)
1655 }
1656
1657 func (rt *peBaseRelocTable) addentry(ldr *loader.Loader, s loader.Sym, r *loader.Reloc) {
1658
1659
1660 const pageSize = 0x1000
1661 const pageMask = pageSize - 1
1662
1663 addr := ldr.SymValue(s) + int64(r.Off()) - PEBASE
1664 page := uint32(addr &^ pageMask)
1665 off := uint32(addr & pageMask)
1666
1667 b, ok := rt.blocks[page]
1668 if !ok {
1669 rt.pages = append(rt.pages, page)
1670 }
1671
1672 e := peBaseRelocEntry{
1673 typeOff: uint16(off & 0xFFF),
1674 }
1675
1676
1677 switch r.Siz() {
1678 default:
1679 Exitf("unsupported relocation size %d\n", r.Siz)
1680 case 4:
1681 e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12)
1682 case 8:
1683 e.typeOff |= uint16(IMAGE_REL_BASED_DIR64 << 12)
1684 }
1685
1686 b.entries = append(b.entries, e)
1687 rt.blocks[page] = b
1688 }
1689
1690 func (rt *peBaseRelocTable) write(ctxt *Link) {
1691 out := ctxt.Out
1692
1693
1694 slices.Sort(rt.pages)
1695
1696
1697 if out.Offset()&3 != 0 {
1698 Errorf("internal error, start of .reloc not 32-bit aligned")
1699 }
1700
1701 for _, p := range rt.pages {
1702 b := rt.blocks[p]
1703
1704
1705
1706
1707 if len(b.entries)&1 != 0 {
1708 b.entries = append(b.entries, peBaseRelocEntry{})
1709 }
1710
1711 const sizeOfPEbaseRelocBlock = 8
1712 blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2)
1713 out.Write32(p)
1714 out.Write32(blockSize)
1715
1716 for _, e := range b.entries {
1717 out.Write16(e.typeOff)
1718 }
1719 }
1720 }
1721
1722 func addPEBaseRelocSym(ldr *loader.Loader, s loader.Sym, rt *peBaseRelocTable) {
1723 relocs := ldr.Relocs(s)
1724 for ri := 0; ri < relocs.Count(); ri++ {
1725 r := relocs.At(ri)
1726 if r.Type() >= objabi.ElfRelocOffset {
1727 continue
1728 }
1729 if r.Siz() == 0 {
1730 continue
1731 }
1732 rs := r.Sym()
1733 if rs == 0 {
1734 continue
1735 }
1736 if !ldr.AttrReachable(s) {
1737 continue
1738 }
1739
1740 switch r.Type() {
1741 default:
1742 case objabi.R_ADDR:
1743 rt.addentry(ldr, s, &r)
1744 }
1745 }
1746 }
1747
1748 func needPEBaseReloc(ctxt *Link) bool {
1749
1750
1751 if (ctxt.Arch.Family == sys.I386 || ctxt.Arch.Family == sys.AMD64) && ctxt.BuildMode != BuildModePIE {
1752 return false
1753 }
1754 return true
1755 }
1756
1757 func addPEBaseReloc(ctxt *Link) {
1758 if !needPEBaseReloc(ctxt) {
1759 return
1760 }
1761
1762 var rt peBaseRelocTable
1763 rt.init(ctxt)
1764
1765
1766 ldr := ctxt.loader
1767 for _, s := range ctxt.Textp {
1768 addPEBaseRelocSym(ldr, s, &rt)
1769 }
1770 for _, s := range ctxt.datap {
1771 addPEBaseRelocSym(ldr, s, &rt)
1772 }
1773
1774
1775 startoff := ctxt.Out.Offset()
1776 rt.write(ctxt)
1777 size := ctxt.Out.Offset() - startoff
1778
1779
1780 rsect := pefile.addSection(".reloc", int(size), int(size))
1781 rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
1782 rsect.checkOffset(startoff)
1783 rsect.pad(ctxt.Out, uint32(size))
1784
1785 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress
1786 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize
1787 }
1788
1789 func (ctxt *Link) dope() {
1790 initdynimport(ctxt)
1791 initdynexport(ctxt)
1792 }
1793
1794 func setpersrc(ctxt *Link, syms []loader.Sym) {
1795 if len(rsrcsyms) != 0 {
1796 Errorf("too many .rsrc sections")
1797 }
1798 rsrcsyms = syms
1799 }
1800
1801 func addpersrc(ctxt *Link) {
1802 if len(rsrcsyms) == 0 {
1803 return
1804 }
1805
1806 var size int64
1807 for _, rsrcsym := range rsrcsyms {
1808 size += ctxt.loader.SymSize(rsrcsym)
1809 }
1810 h := pefile.addSection(".rsrc", int(size), int(size))
1811 h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA
1812 h.checkOffset(ctxt.Out.Offset())
1813
1814 for _, rsrcsym := range rsrcsyms {
1815
1816
1817
1818 splitResources := strings.Contains(ctxt.loader.SymName(rsrcsym), ".rsrc$")
1819 relocs := ctxt.loader.Relocs(rsrcsym)
1820 data := ctxt.loader.Data(rsrcsym)
1821 for ri := 0; ri < relocs.Count(); ri++ {
1822 r := relocs.At(ri)
1823 p := data[r.Off():]
1824 val := uint32(int64(h.virtualAddress) + r.Add())
1825 if splitResources {
1826
1827
1828
1829
1830
1831
1832
1833
1834 val += uint32(len(data))
1835 }
1836 binary.LittleEndian.PutUint32(p, val)
1837 }
1838 ctxt.Out.Write(data)
1839 }
1840 h.pad(ctxt.Out, uint32(size))
1841
1842
1843 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress
1844 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize
1845 }
1846
1847 func asmbPe(ctxt *Link) {
1848 t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length))
1849 t.characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
1850 if ctxt.LinkMode == LinkExternal {
1851
1852
1853 t.characteristics |= IMAGE_SCN_ALIGN_32BYTES
1854 }
1855 t.checkSegment(&Segtext)
1856 pefile.textSect = t
1857
1858 ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length))
1859 ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
1860 if ctxt.LinkMode == LinkExternal {
1861
1862
1863 ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
1864 }
1865 ro.checkSegment(&Segrodata)
1866 pefile.rdataSect = ro
1867
1868
1869
1870 s := ctxt.loader.Lookup("_load_config_used", 0)
1871 if s != 0 {
1872 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = uint32(ctxt.loader.SymValue(s) - PEBASE)
1873 pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = uint32(ctxt.loader.SymSize(s))
1874 }
1875
1876 var d *peSection
1877 if ctxt.LinkMode != LinkExternal {
1878 d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
1879 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
1880 d.checkSegment(&Segdata)
1881 pefile.dataSect = d
1882 } else {
1883 d = pefile.addSection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
1884 d.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
1885 d.checkSegment(&Segdata)
1886 pefile.dataSect = d
1887
1888 b := pefile.addSection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
1889 b.characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
1890 b.pointerToRawData = 0
1891 pefile.bssSect = b
1892 }
1893
1894 pefile.addSEH(ctxt)
1895 pefile.addDWARF()
1896
1897 if ctxt.LinkMode == LinkExternal {
1898 pefile.ctorsSect = pefile.addInitArray(ctxt)
1899 }
1900
1901 ctxt.Out.SeekSet(int64(pefile.nextFileOffset))
1902 if ctxt.LinkMode != LinkExternal {
1903 addimports(ctxt, d)
1904 addexports(ctxt)
1905 addPEBaseReloc(ctxt)
1906 }
1907 pefile.writeSymbolTableAndStringTable(ctxt)
1908 addpersrc(ctxt)
1909 if ctxt.LinkMode == LinkExternal {
1910 pefile.emitRelocations(ctxt)
1911 }
1912
1913 pewrite(ctxt)
1914 }
1915
1916
1917
1918 func peCreateExportFile(ctxt *Link, libName string) (fname string) {
1919 fname = filepath.Join(*flagTmpdir, "export_file.def")
1920 var buf bytes.Buffer
1921
1922 if ctxt.BuildMode == BuildModeCShared {
1923 fmt.Fprintf(&buf, "LIBRARY %s\n", libName)
1924 }
1925 buf.WriteString("EXPORTS\n")
1926
1927 ldr := ctxt.loader
1928 var exports []string
1929 for s := range ldr.ForAllCgoExportStatic() {
1930 extname := ldr.SymExtname(s)
1931 if !strings.HasPrefix(extname, "_cgoexp_") {
1932 continue
1933 }
1934 if ldr.IsFileLocal(s) {
1935 continue
1936 }
1937
1938
1939
1940
1941 name := strings.SplitN(extname, "_", 4)[3]
1942 exports = append(exports, name)
1943 }
1944 if len(exports) == 0 {
1945
1946 exports = append(exports, "_cgo_stub_export")
1947 }
1948 sort.Strings(exports)
1949 buf.WriteString(strings.Join(exports, "\n"))
1950
1951 err := os.WriteFile(fname, buf.Bytes(), 0666)
1952 if err != nil {
1953 Errorf("WriteFile %s failed: %v", fname, err)
1954 }
1955
1956 return fname
1957 }
1958
View as plain text