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