1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package ld
32
33 import (
34 "bytes"
35 "debug/elf"
36 "debug/macho"
37 "debug/pe"
38 "encoding/base64"
39 "encoding/binary"
40 "fmt"
41 "internal/buildcfg"
42 "internal/platform"
43 "io"
44 "log"
45 "os"
46 "os/exec"
47 "path/filepath"
48 "runtime"
49 "slices"
50 "sort"
51 "strings"
52 "sync"
53 "time"
54
55 "cmd/internal/bio"
56 "cmd/internal/goobj"
57 "cmd/internal/hash"
58 "cmd/internal/objabi"
59 "cmd/internal/sys"
60 "cmd/link/internal/loadelf"
61 "cmd/link/internal/loader"
62 "cmd/link/internal/loadmacho"
63 "cmd/link/internal/loadpe"
64 "cmd/link/internal/loadxcoff"
65 "cmd/link/internal/sym"
66 )
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 type ArchSyms struct {
104 Rel loader.Sym
105 Rela loader.Sym
106 RelPLT loader.Sym
107 RelaPLT loader.Sym
108
109 LinkEditGOT loader.Sym
110 LinkEditPLT loader.Sym
111
112 TOC loader.Sym
113 DotTOC []loader.Sym
114
115 GOT loader.Sym
116 PLT loader.Sym
117 GOTPLT loader.Sym
118
119 Tlsg loader.Sym
120 Tlsoffset int
121
122 Dynamic loader.Sym
123 DynSym loader.Sym
124 DynStr loader.Sym
125
126 unreachableMethod loader.Sym
127
128
129
130 mainInittasks loader.Sym
131 }
132
133
134 func (ctxt *Link) mkArchSym(name string, ver int, ls *loader.Sym) {
135 *ls = ctxt.loader.LookupOrCreateSym(name, ver)
136 ctxt.loader.SetAttrReachable(*ls, true)
137 }
138
139
140
141 func (ctxt *Link) mkArchSymVec(name string, ver int, ls []loader.Sym) {
142 ls[ver] = ctxt.loader.LookupOrCreateSym(name, ver)
143 ctxt.loader.SetAttrReachable(ls[ver], true)
144 }
145
146
147
148 func (ctxt *Link) setArchSyms() {
149 ctxt.mkArchSym(".got", 0, &ctxt.GOT)
150 ctxt.mkArchSym(".plt", 0, &ctxt.PLT)
151 ctxt.mkArchSym(".got.plt", 0, &ctxt.GOTPLT)
152 ctxt.mkArchSym(".dynamic", 0, &ctxt.Dynamic)
153 ctxt.mkArchSym(".dynsym", 0, &ctxt.DynSym)
154 ctxt.mkArchSym(".dynstr", 0, &ctxt.DynStr)
155 ctxt.mkArchSym("runtime.unreachableMethod", abiInternalVer, &ctxt.unreachableMethod)
156
157 if ctxt.IsPPC64() {
158 ctxt.mkArchSym("TOC", 0, &ctxt.TOC)
159
160 ctxt.DotTOC = make([]loader.Sym, ctxt.MaxVersion()+1)
161 for i := 0; i <= ctxt.MaxVersion(); i++ {
162 if i >= sym.SymVerABICount && i < sym.SymVerStatic {
163 continue
164 }
165 ctxt.mkArchSymVec(".TOC.", i, ctxt.DotTOC)
166 }
167 }
168 if ctxt.IsElf() {
169 ctxt.mkArchSym(".rel", 0, &ctxt.Rel)
170 ctxt.mkArchSym(".rela", 0, &ctxt.Rela)
171 ctxt.mkArchSym(".rel.plt", 0, &ctxt.RelPLT)
172 ctxt.mkArchSym(".rela.plt", 0, &ctxt.RelaPLT)
173 }
174 if ctxt.IsDarwin() {
175 ctxt.mkArchSym(".linkedit.got", 0, &ctxt.LinkEditGOT)
176 ctxt.mkArchSym(".linkedit.plt", 0, &ctxt.LinkEditPLT)
177 }
178 }
179
180 type Arch struct {
181 Funcalign int
182 Maxalign int
183 Minalign int
184 Dwarfregsp int
185 Dwarfreglr int
186
187
188
189
190
191 TrampLimit uint64
192
193
194
195
196
197 CodePad []byte
198
199
200 Plan9Magic uint32
201 Plan9_64Bit bool
202
203 Adddynrel func(*Target, *loader.Loader, *ArchSyms, loader.Sym, loader.Reloc, int) bool
204 Archinit func(*Link)
205
206
207
208
209
210
211
212
213
214
215 Archreloc func(*Target, *loader.Loader, *ArchSyms, loader.Reloc, loader.Sym,
216 int64) (relocatedOffset int64, nExtReloc int, ok bool)
217
218
219
220
221
222
223
224
225 Archrelocvariant func(target *Target, ldr *loader.Loader, rel loader.Reloc,
226 rv sym.RelocVariant, sym loader.Sym, offset int64, data []byte) (relocatedOffset int64)
227
228
229
230 Trampoline func(ctxt *Link, ldr *loader.Loader, ri int, rs, s loader.Sym)
231
232
233
234
235
236
237
238
239 Asmb func(*Link, *loader.Loader)
240 Asmb2 func(*Link, *loader.Loader)
241
242
243
244
245 Extreloc func(*Target, *loader.Loader, loader.Reloc, loader.Sym) (loader.ExtReloc, bool)
246
247 Gentext func(*Link, *loader.Loader)
248 Machoreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
249 MachorelocSize uint32
250 PEreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
251 Xcoffreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
252
253
254
255 GenSymsLate func(*Link, *loader.Loader)
256
257
258
259
260
261
262
263 TLSIEtoLE func(P []byte, off, size int)
264
265
266 AssignAddress func(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, va uint64, isTramp bool) (*sym.Section, int, uint64)
267
268
269 ELF ELFArch
270 }
271
272 var (
273 thearch Arch
274 lcSize int32
275 rpath Rpath
276 spSize int32
277 symSize int32
278 )
279
280
281
282 var abiInternalVer = sym.SymVerABIInternal
283
284
285
286 func (ctxt *Link) DynlinkingGo() bool {
287 if !ctxt.Loaded {
288 panic("DynlinkingGo called before all symbols loaded")
289 }
290 return ctxt.BuildMode == BuildModeShared || ctxt.linkShared || ctxt.BuildMode == BuildModePlugin || ctxt.canUsePlugins
291 }
292
293
294 func (ctxt *Link) CanUsePlugins() bool {
295 if !ctxt.Loaded {
296 panic("CanUsePlugins called before all symbols loaded")
297 }
298 return ctxt.canUsePlugins
299 }
300
301
302 func (ctxt *Link) NeedCodeSign() bool {
303 return ctxt.IsDarwin() && ctxt.IsARM64()
304 }
305
306 var (
307 dynlib []string
308 ldflag []string
309 havedynamic int
310 Funcalign int
311 iscgo bool
312 elfglobalsymndx int
313 interpreter string
314
315 debug_s bool
316 HEADR int32
317
318 nerrors int
319 liveness int64
320
321
322 checkStrictDups int
323 strictDupMsgCount int
324 )
325
326 var (
327 Segtext sym.Segment
328 Segrodata sym.Segment
329 Segrelrodata sym.Segment
330 Segdata sym.Segment
331 Segdwarf sym.Segment
332 Segpdata sym.Segment
333 Segxdata sym.Segment
334
335 Segments = []*sym.Segment{&Segtext, &Segrodata, &Segrelrodata, &Segdata, &Segdwarf, &Segpdata, &Segxdata}
336 )
337
338 const pkgdef = "__.PKGDEF"
339
340 var (
341
342
343
344 externalobj = false
345
346
347
348
349 dynimportfail []string
350
351
352
353
354
355 preferlinkext []string
356
357
358
359 unknownObjFormat = false
360
361 theline string
362 )
363
364 func Lflag(ctxt *Link, arg string) {
365 ctxt.Libdir = append(ctxt.Libdir, arg)
366 }
367
368
374 func mayberemoveoutfile() {
375 if fi, err := os.Lstat(*flagOutfile); err == nil && !fi.Mode().IsRegular() {
376 return
377 }
378 os.Remove(*flagOutfile)
379 }
380
381 func libinit(ctxt *Link) {
382 if *FlagFuncAlign != 0 {
383 Funcalign = *FlagFuncAlign
384 } else {
385 Funcalign = thearch.Funcalign
386 }
387
388
389 suffix := ""
390
391 suffixsep := ""
392 if *flagInstallSuffix != "" {
393 suffixsep = "_"
394 suffix = *flagInstallSuffix
395 } else if *flagRace {
396 suffixsep = "_"
397 suffix = "race"
398 } else if *flagMsan {
399 suffixsep = "_"
400 suffix = "msan"
401 } else if *flagAsan {
402 suffixsep = "_"
403 suffix = "asan"
404 }
405
406 if buildcfg.GOROOT != "" {
407 Lflag(ctxt, filepath.Join(buildcfg.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", buildcfg.GOOS, buildcfg.GOARCH, suffixsep, suffix)))
408 }
409
410 mayberemoveoutfile()
411
412 if err := ctxt.Out.Open(*flagOutfile); err != nil {
413 Exitf("cannot create %s: %v", *flagOutfile, err)
414 }
415
416 if *flagEntrySymbol == "" {
417 switch ctxt.BuildMode {
418 case BuildModeCShared, BuildModeCArchive:
419 *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s_lib", buildcfg.GOARCH, buildcfg.GOOS)
420 case BuildModeExe, BuildModePIE:
421 *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s", buildcfg.GOARCH, buildcfg.GOOS)
422 case BuildModeShared, BuildModePlugin:
423
424 default:
425 Errorf("unknown *flagEntrySymbol for buildmode %v", ctxt.BuildMode)
426 }
427 }
428 }
429
430 func exitIfErrors() {
431 if nerrors != 0 || checkStrictDups > 1 && strictDupMsgCount > 0 {
432 mayberemoveoutfile()
433 Exit(2)
434 }
435
436 }
437
438 func errorexit() {
439 exitIfErrors()
440 Exit(0)
441 }
442
443 func loadinternal(ctxt *Link, name string) *sym.Library {
444 zerofp := goobj.FingerprintType{}
445 if ctxt.linkShared && ctxt.PackageShlib != nil {
446 if shlib := ctxt.PackageShlib[name]; shlib != "" {
447 return addlibpath(ctxt, "internal", "internal", "", name, shlib, zerofp)
448 }
449 }
450 if ctxt.PackageFile != nil {
451 if pname := ctxt.PackageFile[name]; pname != "" {
452 return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
453 }
454 ctxt.Logf("loadinternal: cannot find %s\n", name)
455 return nil
456 }
457
458 for _, libdir := range ctxt.Libdir {
459 if ctxt.linkShared {
460 shlibname := filepath.Join(libdir, name+".shlibname")
461 if ctxt.Debugvlog != 0 {
462 ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
463 }
464 if _, err := os.Stat(shlibname); err == nil {
465 return addlibpath(ctxt, "internal", "internal", "", name, shlibname, zerofp)
466 }
467 }
468 pname := filepath.Join(libdir, name+".a")
469 if ctxt.Debugvlog != 0 {
470 ctxt.Logf("searching for %s.a in %s\n", name, pname)
471 }
472 if _, err := os.Stat(pname); err == nil {
473 return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
474 }
475 }
476
477 if name == "runtime" {
478 Exitf("error: unable to find runtime.a")
479 }
480 ctxt.Logf("warning: unable to find %s.a\n", name)
481 return nil
482 }
483
484
485 func (ctxt *Link) extld() []string {
486 if len(flagExtld) == 0 {
487
488
489
490 switch buildcfg.GOOS {
491 case "darwin", "freebsd", "openbsd":
492 flagExtld = []string{"clang"}
493 default:
494 flagExtld = []string{"gcc"}
495 }
496 }
497 return flagExtld
498 }
499
500
501
502 func (ctxt *Link) findLibPathCmd(cmd, libname string) string {
503 extld := ctxt.extld()
504 name, args := extld[0], extld[1:]
505 args = append(args, hostlinkArchArgs(ctxt.Arch)...)
506 args = append(args, cmd)
507 if ctxt.Debugvlog != 0 {
508 ctxt.Logf("%s %v\n", extld, args)
509 }
510 out, err := exec.Command(name, args...).Output()
511 if err != nil {
512 if ctxt.Debugvlog != 0 {
513 ctxt.Logf("not using a %s file because compiler failed\n%v\n%s\n", libname, err, out)
514 }
515 return "none"
516 }
517 return strings.TrimSpace(string(out))
518 }
519
520
521
522 func (ctxt *Link) findLibPath(libname string) string {
523 return ctxt.findLibPathCmd("--print-file-name="+libname, libname)
524 }
525
526 func (ctxt *Link) loadlib() {
527 var flags uint32
528 if *flagCheckLinkname {
529 flags |= loader.FlagCheckLinkname
530 }
531 switch *FlagStrictDups {
532 case 0:
533
534 case 1, 2:
535 flags |= loader.FlagStrictDups
536 default:
537 log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
538 }
539 ctxt.loader = loader.NewLoader(flags, &ctxt.ErrorReporter.ErrorReporter)
540 ctxt.ErrorReporter.SymName = func(s loader.Sym) string {
541 return ctxt.loader.SymName(s)
542 }
543
544
545 i := 0
546 for ; i < len(ctxt.Library); i++ {
547 lib := ctxt.Library[i]
548 if lib.Shlib == "" {
549 if ctxt.Debugvlog > 1 {
550 ctxt.Logf("autolib: %s (from %s)\n", lib.File, lib.Objref)
551 }
552 loadobjfile(ctxt, lib)
553 }
554 }
555
556
557 if *flagRace {
558 loadinternal(ctxt, "runtime/race")
559 }
560 if *flagMsan {
561 loadinternal(ctxt, "runtime/msan")
562 }
563 if *flagAsan {
564 loadinternal(ctxt, "runtime/asan")
565 }
566 loadinternal(ctxt, "runtime")
567 for ; i < len(ctxt.Library); i++ {
568 lib := ctxt.Library[i]
569 if lib.Shlib == "" {
570 loadobjfile(ctxt, lib)
571 }
572 }
573
574
575
576
577 iscgo = ctxt.LibraryByPkg["runtime/cgo"] != nil
578
579
580
581 ctxt.canUsePlugins = ctxt.LibraryByPkg["plugin"] != nil && iscgo &&
582 platform.BuildModeSupported("gc", "plugin", buildcfg.GOOS, buildcfg.GOARCH)
583
584
585 determineLinkMode(ctxt)
586
587 if ctxt.LinkMode == LinkExternal && !iscgo && !(buildcfg.GOOS == "darwin" && ctxt.BuildMode != BuildModePlugin && ctxt.Arch.Family == sys.AMD64) {
588
589
590
591
592 if lib := loadinternal(ctxt, "runtime/cgo"); lib != nil && lib.Shlib == "" {
593 if ctxt.BuildMode == BuildModeShared || ctxt.linkShared {
594 Exitf("cannot implicitly include runtime/cgo in a shared library")
595 }
596 for ; i < len(ctxt.Library); i++ {
597 lib := ctxt.Library[i]
598 if lib.Shlib == "" {
599 loadobjfile(ctxt, lib)
600 }
601 }
602 }
603 }
604
605
606 ctxt.loader.LoadSyms(ctxt.Arch)
607
608
609 for _, lib := range ctxt.Library {
610 if lib.Shlib != "" {
611 if ctxt.Debugvlog > 1 {
612 ctxt.Logf("autolib: %s (from %s)\n", lib.Shlib, lib.Objref)
613 }
614 ldshlibsyms(ctxt, lib.Shlib)
615 }
616 }
617
618
619 ctxt.loadcgodirectives()
620
621
622 hostobjs(ctxt)
623 hostlinksetup(ctxt)
624
625 if ctxt.LinkMode == LinkInternal && len(hostobj) != 0 {
626
627
628 any := false
629 undefs, froms := ctxt.loader.UndefinedRelocTargets(1)
630 if len(undefs) > 0 {
631 any = true
632 if ctxt.Debugvlog > 1 {
633 ctxt.Logf("loadlib: first unresolved is %s [%d] from %s [%d]\n",
634 ctxt.loader.SymName(undefs[0]), undefs[0],
635 ctxt.loader.SymName(froms[0]), froms[0])
636 }
637 }
638 if any {
639 if *flagLibGCC == "" {
640 *flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc")
641 }
642 if runtime.GOOS == "freebsd" && strings.HasPrefix(filepath.Base(*flagLibGCC), "libclang_rt.builtins") {
643
644
645
646
647 *flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
648 }
649 if runtime.GOOS == "openbsd" && *flagLibGCC == "libgcc.a" {
650
651
652
653 *flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
654 }
655 if ctxt.HeadType == objabi.Hwindows {
656 loadWindowsHostArchives(ctxt)
657 }
658 if *flagLibGCC != "none" {
659 hostArchive(ctxt, *flagLibGCC)
660 }
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677 isunresolved := symbolsAreUnresolved(ctxt, []string{"__stack_chk_fail_local"})
678 if isunresolved[0] {
679 if p := ctxt.findLibPath("libc_nonshared.a"); p != "none" {
680 hostArchive(ctxt, p)
681 }
682 if p := ctxt.findLibPath("libssp_nonshared.a"); p != "none" {
683 hostArchive(ctxt, p)
684 }
685 }
686 }
687 }
688
689 loadfips(ctxt)
690
691
692 ctxt.Loaded = true
693
694 strictDupMsgCount = ctxt.loader.NStrictDupMsgs()
695 }
696
697
698
699
700
701
702
703
704 func loadWindowsHostArchives(ctxt *Link) {
705 any := true
706 for i := 0; any && i < 2; i++ {
707
708
709 isunresolved := symbolsAreUnresolved(ctxt, []string{"atexit"})
710 if isunresolved[0] {
711 if p := ctxt.findLibPath("crt2.o"); p != "none" {
712 hostObject(ctxt, "crt2", p)
713 }
714 }
715 if *flagRace {
716 if p := ctxt.findLibPath("libsynchronization.a"); p != "none" {
717 hostArchive(ctxt, p)
718 }
719 }
720 if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
721 hostArchive(ctxt, p)
722 }
723 if p := ctxt.findLibPath("libmingw32.a"); p != "none" {
724 hostArchive(ctxt, p)
725 }
726
727
728 if p := ctxt.findLibPath("libmsvcrt.a"); p != "none" {
729 hostArchive(ctxt, p)
730 }
731 any = false
732 undefs, froms := ctxt.loader.UndefinedRelocTargets(1)
733 if len(undefs) > 0 {
734 any = true
735 if ctxt.Debugvlog > 1 {
736 ctxt.Logf("loadWindowsHostArchives: remaining unresolved is %s [%d] from %s [%d]\n",
737 ctxt.loader.SymName(undefs[0]), undefs[0],
738 ctxt.loader.SymName(froms[0]), froms[0])
739 }
740 }
741 }
742
743
744
745
746 want := []string{"__CTOR_LIST__", "__DTOR_LIST__"}
747 isunresolved := symbolsAreUnresolved(ctxt, want)
748 for k, w := range want {
749 if isunresolved[k] {
750 sb := ctxt.loader.CreateSymForUpdate(w, 0)
751 sb.SetType(sym.SDATA)
752 sb.AddUint64(ctxt.Arch, 0)
753 sb.SetReachable(true)
754 ctxt.loader.SetAttrSpecial(sb.Sym(), true)
755 }
756 }
757
758
759
760 if err := loadpe.PostProcessImports(); err != nil {
761 Errorf("%v", err)
762 }
763
764
765
766
767
773 }
774
775
776
777 func (ctxt *Link) loadcgodirectives() {
778 l := ctxt.loader
779 hostObjSyms := make(map[loader.Sym]struct{})
780 for _, d := range ctxt.cgodata {
781 setCgoAttr(ctxt, d.file, d.pkg, d.directives, hostObjSyms)
782 }
783 ctxt.cgodata = nil
784
785 if ctxt.LinkMode == LinkInternal {
786
787
788 for symIdx := range hostObjSyms {
789 if l.SymType(symIdx) == sym.SHOSTOBJ {
790
791
792
793
794 su := l.MakeSymbolUpdater(symIdx)
795 if l.SymExtname(symIdx) != "" && l.SymDynimplib(symIdx) != "" && !(l.AttrCgoExportStatic(symIdx) || l.AttrCgoExportDynamic(symIdx)) {
796 su.SetType(sym.SDYNIMPORT)
797 } else {
798 su.SetType(0)
799 }
800 }
801 }
802 }
803 }
804
805
806
807 func (ctxt *Link) linksetup() {
808 switch ctxt.BuildMode {
809 case BuildModeCShared, BuildModePlugin:
810 symIdx := ctxt.loader.LookupOrCreateSym("runtime.islibrary", 0)
811 sb := ctxt.loader.MakeSymbolUpdater(symIdx)
812 sb.SetType(sym.SNOPTRDATA)
813 sb.AddUint8(1)
814 case BuildModeCArchive:
815 symIdx := ctxt.loader.LookupOrCreateSym("runtime.isarchive", 0)
816 sb := ctxt.loader.MakeSymbolUpdater(symIdx)
817 sb.SetType(sym.SNOPTRDATA)
818 sb.AddUint8(1)
819 }
820
821
822 if ctxt.HeadType == objabi.Hwindows {
823 Peinit(ctxt)
824 }
825
826 if ctxt.LinkMode == LinkExternal {
827
828
829 *FlagTextAddr = 0
830 }
831
832
833
834
835
836
837
838
839
840
841
842 if ctxt.BuildMode == BuildModeExe {
843 if havedynamic == 0 && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Hsolaris {
844 *FlagD = true
845 }
846 }
847
848 if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && buildcfg.GOOS != "aix" {
849 toc := ctxt.loader.LookupOrCreateSym(".TOC.", 0)
850 sb := ctxt.loader.MakeSymbolUpdater(toc)
851 sb.SetType(sym.SDYNIMPORT)
852 }
853
854
855
856
857 if buildcfg.GOOS != "android" {
858 tlsg := ctxt.loader.LookupOrCreateSym("runtime.tlsg", 0)
859 sb := ctxt.loader.MakeSymbolUpdater(tlsg)
860
861
862
863 if sb.Type() == 0 {
864 sb.SetType(sym.STLSBSS)
865 sb.SetSize(int64(ctxt.Arch.PtrSize))
866 } else if sb.Type() != sym.SDYNIMPORT {
867 Errorf("runtime declared tlsg variable %v", sb.Type())
868 }
869 ctxt.loader.SetAttrReachable(tlsg, true)
870 ctxt.Tlsg = tlsg
871 }
872
873 var moduledata loader.Sym
874 var mdsb *loader.SymbolBuilder
875 if ctxt.BuildMode == BuildModePlugin {
876 moduledata = ctxt.loader.LookupOrCreateSym("local.pluginmoduledata", 0)
877 mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
878 ctxt.loader.SetAttrLocal(moduledata, true)
879 } else {
880 moduledata = ctxt.loader.LookupOrCreateSym("runtime.firstmoduledata", 0)
881 mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
882 }
883 if mdsb.Type() != 0 && mdsb.Type() != sym.SDYNIMPORT {
884
885
886
887
888
889 mdsb.SetSize(0)
890
891
892
893 if ctxt.Arch.Family == sys.ARM {
894 goarm := ctxt.loader.LookupOrCreateSym("runtime.goarm", 0)
895 sb := ctxt.loader.MakeSymbolUpdater(goarm)
896 sb.SetType(sym.SNOPTRDATA)
897 sb.SetSize(0)
898 sb.AddUint8(uint8(buildcfg.GOARM.Version))
899
900 goarmsoftfp := ctxt.loader.LookupOrCreateSym("runtime.goarmsoftfp", 0)
901 sb2 := ctxt.loader.MakeSymbolUpdater(goarmsoftfp)
902 sb2.SetType(sym.SNOPTRDATA)
903 sb2.SetSize(0)
904 if buildcfg.GOARM.SoftFloat {
905 sb2.AddUint8(1)
906 } else {
907 sb2.AddUint8(0)
908 }
909 }
910
911
912
913
914 memProfile := ctxt.loader.Lookup("runtime.memProfileInternal", abiInternalVer)
915 if memProfile != 0 && !ctxt.loader.AttrReachable(memProfile) && !ctxt.DynlinkingGo() {
916 memProfSym := ctxt.loader.LookupOrCreateSym("runtime.disableMemoryProfiling", 0)
917 sb := ctxt.loader.MakeSymbolUpdater(memProfSym)
918 sb.SetType(sym.SNOPTRDATA)
919 sb.SetSize(0)
920 sb.AddUint8(1)
921 }
922 } else {
923
924
925 moduledata = ctxt.loader.LookupOrCreateSym("local.moduledata", 0)
926 mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
927 ctxt.loader.SetAttrLocal(moduledata, true)
928 }
929 mdsb.SetType(sym.SMODULEDATA)
930 ctxt.loader.SetAttrReachable(moduledata, true)
931 ctxt.Moduledata = moduledata
932
933 if ctxt.Arch == sys.Arch386 && ctxt.HeadType != objabi.Hwindows {
934 if (ctxt.BuildMode == BuildModeCArchive && ctxt.IsELF) || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE || ctxt.DynlinkingGo() {
935 got := ctxt.loader.LookupOrCreateSym("_GLOBAL_OFFSET_TABLE_", 0)
936 sb := ctxt.loader.MakeSymbolUpdater(got)
937 sb.SetType(sym.SDYNIMPORT)
938 ctxt.loader.SetAttrReachable(got, true)
939 }
940 }
941
942
943
944
945
946
947
948 ctxt.Library = postorder(ctxt.Library)
949 intlibs := []bool{}
950 for _, lib := range ctxt.Library {
951 intlibs = append(intlibs, isRuntimeDepPkg(lib.Pkg))
952 }
953 ctxt.Textp = ctxt.loader.AssignTextSymbolOrder(ctxt.Library, intlibs, ctxt.Textp)
954 }
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969 func (ctxt *Link) mangleTypeSym() {
970 if ctxt.BuildMode != BuildModeShared && !ctxt.linkShared && ctxt.BuildMode != BuildModePlugin && !ctxt.CanUsePlugins() {
971 return
972 }
973
974 ldr := ctxt.loader
975 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
976 if !ldr.AttrReachable(s) && !ctxt.linkShared {
977
978
979
980
981
982 continue
983 }
984 name := ldr.SymName(s)
985 newName := typeSymbolMangle(name)
986 if newName != name {
987 ldr.SetSymExtname(s, newName)
988
989
990
991
992
993
994 dup := ldr.Lookup(newName, ldr.SymVersion(s))
995 if dup != 0 {
996 st := ldr.SymType(s)
997 dt := ldr.SymType(dup)
998 if st == sym.Sxxx && dt != sym.Sxxx {
999 ldr.CopySym(dup, s)
1000 }
1001 }
1002 }
1003 }
1004 }
1005
1006
1007
1008
1009
1010
1011
1012 func typeSymbolMangle(name string) string {
1013 isType := strings.HasPrefix(name, "type:")
1014 if !isType && !strings.Contains(name, "@") {
1015
1016 return name
1017 }
1018 if strings.HasPrefix(name, "type:runtime.") {
1019 return name
1020 }
1021 if strings.HasPrefix(name, "go:string.") {
1022
1023
1024 return name
1025 }
1026 if len(name) <= 14 && !strings.Contains(name, "@") {
1027 return name
1028 }
1029 if isType {
1030 hb := hash.Sum32([]byte(name[5:]))
1031 prefix := "type:"
1032 if name[5] == '.' {
1033 prefix = "type:."
1034 }
1035 return prefix + base64.StdEncoding.EncodeToString(hb[:6])
1036 }
1037
1038 i := strings.IndexByte(name, '[')
1039 j := strings.LastIndexByte(name, ']')
1040 if j == -1 || j <= i {
1041 j = len(name)
1042 }
1043 hb := hash.Sum32([]byte(name[i+1 : j]))
1044 return name[:i+1] + base64.StdEncoding.EncodeToString(hb[:6]) + name[j:]
1045 }
1046
1047
1051 func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 {
1052 if off&1 != 0 {
1053 off++
1054 }
1055 bp.MustSeek(off, 0)
1056 var buf [SAR_HDR]byte
1057 if n, err := io.ReadFull(bp, buf[:]); err != nil {
1058 if n == 0 && err != io.EOF {
1059 return -1
1060 }
1061 return 0
1062 }
1063
1064 a.name = artrim(buf[0:16])
1065 a.date = artrim(buf[16:28])
1066 a.uid = artrim(buf[28:34])
1067 a.gid = artrim(buf[34:40])
1068 a.mode = artrim(buf[40:48])
1069 a.size = artrim(buf[48:58])
1070 a.fmag = artrim(buf[58:60])
1071
1072 arsize := atolwhex(a.size)
1073 if arsize&1 != 0 {
1074 arsize++
1075 }
1076 return arsize + SAR_HDR
1077 }
1078
1079 func loadobjfile(ctxt *Link, lib *sym.Library) {
1080 pkg := objabi.PathToPrefix(lib.Pkg)
1081
1082 if ctxt.Debugvlog > 1 {
1083 ctxt.Logf("ldobj: %s (%s)\n", lib.File, pkg)
1084 }
1085 f, err := bio.Open(lib.File)
1086 if err != nil {
1087 Exitf("cannot open file %s: %v", lib.File, err)
1088 }
1089 defer f.Close()
1090 defer func() {
1091 if pkg == "main" && !lib.Main {
1092 Exitf("%s: not package main", lib.File)
1093 }
1094 }()
1095
1096 for i := 0; i < len(ARMAG); i++ {
1097 if c, err := f.ReadByte(); err == nil && c == ARMAG[i] {
1098 continue
1099 }
1100
1101
1102 l := f.MustSeek(0, 2)
1103 f.MustSeek(0, 0)
1104 ldobj(ctxt, f, lib, l, lib.File, lib.File)
1105 return
1106 }
1107
1108
1120 var arhdr ArHdr
1121 off := f.Offset()
1122 for {
1123 l := nextar(f, off, &arhdr)
1124 if l == 0 {
1125 break
1126 }
1127 if l < 0 {
1128 Exitf("%s: malformed archive", lib.File)
1129 }
1130 off += l
1131
1132
1133
1134
1135
1136 if arhdr.name == pkgdef {
1137 continue
1138 }
1139
1140 if arhdr.name == "dynimportfail" {
1141 dynimportfail = append(dynimportfail, lib.Pkg)
1142 }
1143 if arhdr.name == "preferlinkext" {
1144
1145
1146 if ctxt.LinkMode == LinkAuto {
1147 preferlinkext = append(preferlinkext, lib.Pkg)
1148 }
1149 }
1150
1151
1152
1153
1154 if len(arhdr.name) < 16 {
1155 if ext := filepath.Ext(arhdr.name); ext != ".o" && ext != ".syso" {
1156 continue
1157 }
1158 }
1159
1160 pname := fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
1161 l = atolwhex(arhdr.size)
1162 ldobj(ctxt, f, lib, l, pname, lib.File)
1163 }
1164 }
1165
1166 type Hostobj struct {
1167 ld func(*Link, *bio.Reader, string, int64, string)
1168 pkg string
1169 pn string
1170 file string
1171 off int64
1172 length int64
1173 }
1174
1175 var hostobj []Hostobj
1176
1177
1178
1179 var internalpkg = []string{
1180 "crypto/internal/boring",
1181 "crypto/internal/boring/syso",
1182 "crypto/x509",
1183 "net",
1184 "os/user",
1185 "runtime/cgo",
1186 "runtime/race",
1187 "runtime/race/internal/amd64v1",
1188 "runtime/race/internal/amd64v3",
1189 "runtime/msan",
1190 "runtime/asan",
1191 }
1192
1193 func ldhostobj(ld func(*Link, *bio.Reader, string, int64, string), headType objabi.HeadType, f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj {
1194 isinternal := false
1195 for _, intpkg := range internalpkg {
1196 if pkg == intpkg {
1197 isinternal = true
1198 break
1199 }
1200 }
1201
1202
1203
1204
1205
1206
1207
1208 if headType == objabi.Hdragonfly {
1209 if pkg == "net" || pkg == "os/user" {
1210 isinternal = false
1211 }
1212 }
1213
1214 if !isinternal {
1215 externalobj = true
1216 }
1217
1218 hostobj = append(hostobj, Hostobj{})
1219 h := &hostobj[len(hostobj)-1]
1220 h.ld = ld
1221 h.pkg = pkg
1222 h.pn = pn
1223 h.file = file
1224 h.off = f.Offset()
1225 h.length = length
1226 return h
1227 }
1228
1229 func hostobjs(ctxt *Link) {
1230 if ctxt.LinkMode != LinkInternal {
1231 return
1232 }
1233 var h *Hostobj
1234
1235 for i := 0; i < len(hostobj); i++ {
1236 h = &hostobj[i]
1237 f, err := bio.Open(h.file)
1238 if err != nil {
1239 Exitf("cannot reopen %s: %v", h.pn, err)
1240 }
1241 f.MustSeek(h.off, 0)
1242 if h.ld == nil {
1243 Errorf("%s: unrecognized object file format", h.pn)
1244 continue
1245 }
1246 h.ld(ctxt, f, h.pkg, h.length, h.pn)
1247 if *flagCaptureHostObjs != "" {
1248 captureHostObj(h)
1249 }
1250 f.Close()
1251 }
1252 }
1253
1254 func hostlinksetup(ctxt *Link) {
1255 if ctxt.LinkMode != LinkExternal {
1256 return
1257 }
1258
1259
1260
1261
1262 debug_s = *FlagS
1263 *FlagS = false
1264
1265
1266 if *flagTmpdir == "" {
1267 dir, err := os.MkdirTemp("", "go-link-")
1268 if err != nil {
1269 log.Fatal(err)
1270 }
1271 *flagTmpdir = dir
1272 ownTmpDir = true
1273 AtExit(func() {
1274 os.RemoveAll(*flagTmpdir)
1275 })
1276 }
1277
1278
1279 if err := ctxt.Out.Close(); err != nil {
1280 Exitf("error closing output file")
1281 }
1282 mayberemoveoutfile()
1283
1284 p := filepath.Join(*flagTmpdir, "go.o")
1285 if err := ctxt.Out.Open(p); err != nil {
1286 Exitf("cannot create %s: %v", p, err)
1287 }
1288 }
1289
1290
1291
1292
1293
1294
1295
1296
1297 func cleanTimeStamps(files []string) {
1298 epocht := time.Unix(0, 0)
1299 for _, f := range files {
1300 if err := os.Chtimes(f, epocht, epocht); err != nil {
1301 Exitf("cannot chtimes %s: %v", f, err)
1302 }
1303 }
1304 }
1305
1306
1307
1308 func (ctxt *Link) hostobjCopy() (paths []string) {
1309 var wg sync.WaitGroup
1310 sema := make(chan struct{}, runtime.NumCPU())
1311 for i, h := range hostobj {
1312 h := h
1313 dst := filepath.Join(*flagTmpdir, fmt.Sprintf("%06d.o", i))
1314 paths = append(paths, dst)
1315 if ctxt.Debugvlog != 0 {
1316 ctxt.Logf("host obj copy: %s from pkg %s -> %s\n", h.pn, h.pkg, dst)
1317 }
1318
1319 wg.Add(1)
1320 go func() {
1321 sema <- struct{}{}
1322 defer func() {
1323 <-sema
1324 wg.Done()
1325 }()
1326 f, err := os.Open(h.file)
1327 if err != nil {
1328 Exitf("cannot reopen %s: %v", h.pn, err)
1329 }
1330 defer f.Close()
1331 if _, err := f.Seek(h.off, 0); err != nil {
1332 Exitf("cannot seek %s: %v", h.pn, err)
1333 }
1334
1335 w, err := os.Create(dst)
1336 if err != nil {
1337 Exitf("cannot create %s: %v", dst, err)
1338 }
1339 if _, err := io.CopyN(w, f, h.length); err != nil {
1340 Exitf("cannot write %s: %v", dst, err)
1341 }
1342 if err := w.Close(); err != nil {
1343 Exitf("cannot close %s: %v", dst, err)
1344 }
1345 }()
1346 }
1347 wg.Wait()
1348 return paths
1349 }
1350
1351
1352
1353
1354
1355 func writeGDBLinkerScript() string {
1356 name := "fix_debug_gdb_scripts.ld"
1357 path := filepath.Join(*flagTmpdir, name)
1358 src := `SECTIONS
1359 {
1360 .debug_gdb_scripts BLOCK(__section_alignment__) (NOLOAD) :
1361 {
1362 *(.debug_gdb_scripts)
1363 }
1364 }
1365 INSERT AFTER .debug_types;
1366 `
1367 err := os.WriteFile(path, []byte(src), 0666)
1368 if err != nil {
1369 Errorf("WriteFile %s failed: %v", name, err)
1370 }
1371 return path
1372 }
1373
1374 type machoUpdateFunc func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error
1375
1376
1377 func (ctxt *Link) archive() {
1378 if ctxt.BuildMode != BuildModeCArchive {
1379 return
1380 }
1381
1382 exitIfErrors()
1383
1384 if *flagExtar == "" {
1385 const printProgName = "--print-prog-name=ar"
1386 cc := ctxt.extld()
1387 *flagExtar = "ar"
1388 if linkerFlagSupported(ctxt.Arch, cc[0], "", printProgName) {
1389 *flagExtar = ctxt.findExtLinkTool("ar")
1390 }
1391 }
1392
1393 mayberemoveoutfile()
1394
1395
1396
1397 if err := ctxt.Out.Close(); err != nil {
1398 Exitf("error closing %v", *flagOutfile)
1399 }
1400
1401 argv := []string{*flagExtar, "-q", "-c", "-s"}
1402 if ctxt.HeadType == objabi.Haix {
1403 argv = append(argv, "-X64")
1404 }
1405 godotopath := filepath.Join(*flagTmpdir, "go.o")
1406 cleanTimeStamps([]string{godotopath})
1407 hostObjCopyPaths := ctxt.hostobjCopy()
1408 cleanTimeStamps(hostObjCopyPaths)
1409
1410 argv = append(argv, *flagOutfile)
1411 argv = append(argv, godotopath)
1412 argv = append(argv, hostObjCopyPaths...)
1413
1414 if ctxt.Debugvlog != 0 {
1415 ctxt.Logf("archive: %s\n", strings.Join(argv, " "))
1416 }
1417
1418
1419
1420
1421
1422
1423 if syscallExecSupported && !ownTmpDir {
1424 runAtExitFuncs()
1425 ctxt.execArchive(argv)
1426 panic("should not get here")
1427 }
1428
1429
1430 if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
1431 Exitf("running %s failed: %v\n%s", argv[0], err, out)
1432 }
1433 }
1434
1435 func (ctxt *Link) hostlink() {
1436 if ctxt.LinkMode != LinkExternal || nerrors > 0 {
1437 return
1438 }
1439 if ctxt.BuildMode == BuildModeCArchive {
1440 return
1441 }
1442
1443 var argv []string
1444 argv = append(argv, ctxt.extld()...)
1445 argv = append(argv, hostlinkArchArgs(ctxt.Arch)...)
1446
1447 if *FlagS || debug_s {
1448 if ctxt.HeadType == objabi.Hdarwin {
1449
1450
1451
1452 } else {
1453 argv = append(argv, "-s")
1454 }
1455 } else if *FlagW {
1456 if !ctxt.IsAIX() && !ctxt.IsSolaris() {
1457 argv = append(argv, "-Wl,-S")
1458 }
1459 }
1460
1461
1462
1463 combineDwarf := ctxt.IsDarwin() && !*FlagW && machoPlatform == PLATFORM_MACOS
1464
1465 var isMSVC, isLLD bool
1466 wlPrefix := "-Wl,--"
1467
1468 switch ctxt.HeadType {
1469 case objabi.Hdarwin:
1470 if combineDwarf {
1471
1472
1473 argv = append(argv, "-Wl,-headerpad,1144")
1474 }
1475 if ctxt.DynlinkingGo() && buildcfg.GOOS != "ios" {
1476
1477
1478
1479
1480
1481 argv = append(argv, "-Wl,-flat_namespace", "-Wl,-bind_at_load")
1482 if combineDwarf && linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,-no_fixup_chains") {
1483
1484
1485
1486
1487
1488 argv = append(argv, "-Wl,-no_fixup_chains")
1489 }
1490 }
1491 if !combineDwarf {
1492 argv = append(argv, "-Wl,-S")
1493 if debug_s {
1494
1495
1496
1497 argv = append(argv, "-Wl,-x")
1498 }
1499 }
1500 if *flagRace {
1501
1502
1503
1504 argv = append(argv, "-Wl,-U,__dyld_get_dyld_header")
1505 }
1506 if *flagHostBuildid == "none" {
1507 argv = append(argv, "-Wl,-no_uuid")
1508 }
1509 case objabi.Hopenbsd:
1510 argv = append(argv, "-pthread")
1511 if ctxt.BuildMode != BuildModePIE {
1512 argv = append(argv, "-Wl,-nopie")
1513 }
1514 if linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,-z,nobtcfi") {
1515
1516
1517 argv = append(argv, "-Wl,-z,nobtcfi")
1518 }
1519 if ctxt.Arch.InFamily(sys.ARM64) {
1520
1521
1522
1523 argv = append(argv, "-Wl,--no-execute-only")
1524 }
1525 case objabi.Hwindows:
1526 isMSVC = ctxt.isMSVC()
1527 isLLD = ctxt.isLLD()
1528 if isMSVC {
1529
1530
1531
1532
1533 wlPrefix = "-Wl,-"
1534 }
1535
1536 if windowsgui {
1537 argv = append(argv, "-mwindows")
1538 } else {
1539 argv = append(argv, "-mconsole")
1540 }
1541
1542
1543
1544 argv = append(argv, wlPrefix+"tsaware")
1545
1546
1547 argv = append(argv, wlPrefix+"nxcompat")
1548
1549 if !isMSVC {
1550 peMajorVersion := PeMinimumTargetMajorVersion
1551 peMinorVersion := PeMinimumTargetMinorVersion
1552 if peMajorVersion >= 10 && !isLLD &&
1553 !peHasLoadConfigDirectorySupport(ctxt.Arch, argv[0]) {
1554
1555
1556
1557
1558
1559 peMajorVersion = 6
1560 peMinorVersion = 1
1561 }
1562 argv = append(argv, fmt.Sprintf("-Wl,--major-os-version=%d", peMajorVersion))
1563 argv = append(argv, fmt.Sprintf("-Wl,--minor-os-version=%d", peMinorVersion))
1564 argv = append(argv, fmt.Sprintf("-Wl,--major-subsystem-version=%d", peMajorVersion))
1565 argv = append(argv, fmt.Sprintf("-Wl,--minor-subsystem-version=%d", peMinorVersion))
1566 }
1567 case objabi.Haix:
1568 argv = append(argv, "-pthread")
1569
1570
1571 argv = append(argv, "-Wl,-bnoobjreorder")
1572
1573
1574 argv = append(argv, "-mcmodel=large")
1575 argv = append(argv, "-Wl,-bbigtoc")
1576 }
1577
1578
1579
1580
1581 if ctxt.IsPPC64() && ctxt.IsElf() && buildcfg.GOPPC64 >= 10 {
1582 if !linkerFlagSupported(ctxt.Arch, argv[0], "", "-mcpu=power10") {
1583 Exitf("The external toolchain does not support -mcpu=power10. " +
1584 " This is required to externally link GOPPC64 >= power10")
1585 }
1586 }
1587
1588
1589 addASLRargs := func(argv []string, val bool) []string {
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605 var dbopt string
1606 var heopt string
1607 dbon := wlPrefix + "dynamicbase"
1608 heon := wlPrefix + "high-entropy-va"
1609 dboff := wlPrefix + "disable-dynamicbase"
1610 heoff := wlPrefix + "disable-high-entropy-va"
1611 if isMSVC {
1612 heon = wlPrefix + "highentropyva"
1613 heoff = wlPrefix + "highentropyva:no"
1614 dboff = wlPrefix + "dynamicbase:no"
1615 }
1616 if val {
1617 dbopt = dbon
1618 heopt = heon
1619 } else {
1620
1621 newer := linkerFlagSupported(ctxt.Arch, argv[0], "", dboff)
1622 if newer {
1623
1624 dbopt = dboff
1625 heopt = heoff
1626 } else {
1627
1628
1629 dbopt = ""
1630 heopt = ""
1631 }
1632 }
1633 if dbopt != "" {
1634 argv = append(argv, dbopt)
1635 }
1636
1637 if ctxt.Arch.PtrSize >= 8 && heopt != "" {
1638 argv = append(argv, heopt)
1639 }
1640 return argv
1641 }
1642
1643 switch ctxt.BuildMode {
1644 case BuildModeExe:
1645 if ctxt.HeadType == objabi.Hdarwin {
1646 if machoPlatform == PLATFORM_MACOS && ctxt.IsAMD64() {
1647 argv = append(argv, "-Wl,-no_pie")
1648 }
1649 }
1650 if *flagRace && ctxt.HeadType == objabi.Hwindows {
1651
1652
1653
1654
1655 argv = addASLRargs(argv, false)
1656 }
1657 case BuildModePIE:
1658 switch ctxt.HeadType {
1659 case objabi.Hdarwin, objabi.Haix:
1660 case objabi.Hwindows:
1661 if *flagAslr && *flagRace {
1662
1663
1664
1665 *flagAslr = false
1666 }
1667 argv = addASLRargs(argv, *flagAslr)
1668 default:
1669
1670 if ctxt.UseRelro() {
1671 argv = append(argv, "-Wl,-z,relro")
1672 }
1673 argv = append(argv, "-pie")
1674 }
1675 case BuildModeCShared:
1676 if ctxt.HeadType == objabi.Hdarwin {
1677 argv = append(argv, "-dynamiclib")
1678 } else {
1679 if ctxt.UseRelro() {
1680 argv = append(argv, "-Wl,-z,relro")
1681 }
1682 argv = append(argv, "-shared")
1683 if ctxt.HeadType == objabi.Hwindows {
1684 argv = addASLRargs(argv, *flagAslr)
1685 } else {
1686
1687
1688 argv = append(argv, "-Wl,-z,nodelete")
1689
1690 argv = append(argv, "-Wl,-Bsymbolic")
1691 }
1692 }
1693 case BuildModeShared:
1694 if ctxt.UseRelro() {
1695 argv = append(argv, "-Wl,-z,relro")
1696 }
1697 argv = append(argv, "-shared")
1698 case BuildModePlugin:
1699 if ctxt.HeadType == objabi.Hdarwin {
1700 argv = append(argv, "-dynamiclib")
1701 } else {
1702 if ctxt.UseRelro() {
1703 argv = append(argv, "-Wl,-z,relro")
1704 }
1705 argv = append(argv, "-shared")
1706 }
1707 }
1708
1709 var altLinker string
1710 if ctxt.IsELF && (ctxt.DynlinkingGo() || *flagBindNow) {
1711
1712
1713
1714
1715
1716 argv = append(argv, "-Wl,-z,now")
1717 }
1718
1719 if ctxt.IsELF && ctxt.DynlinkingGo() {
1720
1721
1722
1723 argv = append(argv, "-Wl,-z,nocopyreloc")
1724
1725 if buildcfg.GOOS == "android" {
1726
1727 altLinker = "lld"
1728 }
1729
1730 if ctxt.Arch.InFamily(sys.ARM64) && buildcfg.GOOS == "linux" {
1731
1732
1733
1734
1735
1736
1737
1738 useGold := false
1739 name, args := flagExtld[0], flagExtld[1:]
1740 args = append(args, "-Wl,--version")
1741 cmd := exec.Command(name, args...)
1742 if out, err := cmd.CombinedOutput(); err == nil {
1743
1744 for line := range strings.Lines(string(out)) {
1745 if !strings.HasPrefix(line, "GNU ld ") {
1746 continue
1747 }
1748 fields := strings.Fields(line[len("GNU ld "):])
1749 var major, minor int
1750 if ret, err := fmt.Sscanf(fields[len(fields)-1], "%d.%d", &major, &minor); ret == 2 && err == nil {
1751 if major == 2 && minor <= 35 {
1752 useGold = true
1753 }
1754 break
1755 }
1756 }
1757 }
1758
1759 if useGold {
1760
1761 altLinker = "gold"
1762
1763
1764
1765
1766 args = flagExtld[1:]
1767 args = append(args, "-fuse-ld=gold", "-Wl,--version")
1768 cmd = exec.Command(name, args...)
1769 if out, err := cmd.CombinedOutput(); err == nil {
1770 if !bytes.Contains(out, []byte("GNU gold")) {
1771 log.Fatalf("ARM64 external linker must be ld>=2.36 or gold (issue #15696, 22040), but is not: %s", out)
1772 }
1773 }
1774 }
1775 }
1776 }
1777 if ctxt.Arch.Family == sys.ARM64 && buildcfg.GOOS == "freebsd" {
1778
1779 altLinker = "bfd"
1780
1781
1782 name, args := flagExtld[0], flagExtld[1:]
1783 args = append(args, "-fuse-ld=bfd", "-Wl,--version")
1784 cmd := exec.Command(name, args...)
1785 if out, err := cmd.CombinedOutput(); err == nil {
1786 if !bytes.Contains(out, []byte("GNU ld")) {
1787 log.Fatalf("ARM64 external linker must be ld.bfd (issue #35197), please install devel/binutils")
1788 }
1789 }
1790 }
1791 if altLinker != "" {
1792 argv = append(argv, "-fuse-ld="+altLinker)
1793 }
1794
1795 if ctxt.IsELF && linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,--build-id=0x1234567890abcdef") {
1796 if len(buildinfo) > 0 {
1797 argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
1798 } else if *flagHostBuildid == "none" {
1799 argv = append(argv, "-Wl,--build-id=none")
1800 }
1801 }
1802
1803
1804
1805
1806
1807
1808
1809 outopt := *flagOutfile
1810 if buildcfg.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
1811 outopt += "."
1812 }
1813 argv = append(argv, "-o")
1814 argv = append(argv, outopt)
1815
1816 if rpath.val != "" {
1817 argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
1818 }
1819
1820 if *flagInterpreter != "" {
1821
1822
1823
1824
1825 argv = append(argv, fmt.Sprintf("-Wl,--dynamic-linker,%s", *flagInterpreter))
1826 }
1827
1828
1829 switch {
1830 case ctxt.IsELF:
1831 if ctxt.DynlinkingGo() || ctxt.BuildMode == BuildModeCShared || !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "-Wl,--export-dynamic-symbol=main") {
1832 argv = append(argv, "-rdynamic")
1833 } else {
1834 var exports []string
1835 ctxt.loader.ForAllCgoExportDynamic(func(s loader.Sym) {
1836 exports = append(exports, "-Wl,--export-dynamic-symbol="+ctxt.loader.SymExtname(s))
1837 })
1838 sort.Strings(exports)
1839 argv = append(argv, exports...)
1840 }
1841 case ctxt.IsAIX():
1842 fileName := xcoffCreateExportFile(ctxt)
1843 argv = append(argv, "-Wl,-bE:"+fileName)
1844 case ctxt.IsWindows() && !slices.Contains(flagExtldflags, wlPrefix+"export-all-symbols"):
1845 fileName := peCreateExportFile(ctxt, filepath.Base(outopt))
1846 prefix := ""
1847 if isMSVC {
1848 prefix = "-Wl,-def:"
1849 }
1850 argv = append(argv, prefix+fileName)
1851 }
1852
1853 const unusedArguments = "-Qunused-arguments"
1854 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, unusedArguments) {
1855 argv = append(argv, unusedArguments)
1856 }
1857
1858 if ctxt.IsWindows() {
1859
1860
1861
1862
1863 const noTimeStamp = "-Wl,--no-insert-timestamp"
1864 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, noTimeStamp) {
1865 argv = append(argv, noTimeStamp)
1866 }
1867 }
1868
1869 const compressDWARF = "-Wl,--compress-debug-sections=zlib"
1870 if ctxt.compressDWARF && linkerFlagSupported(ctxt.Arch, argv[0], altLinker, compressDWARF) {
1871 argv = append(argv, compressDWARF)
1872 }
1873
1874 hostObjCopyPaths := ctxt.hostobjCopy()
1875 cleanTimeStamps(hostObjCopyPaths)
1876 godotopath := filepath.Join(*flagTmpdir, "go.o")
1877 cleanTimeStamps([]string{godotopath})
1878
1879 argv = append(argv, godotopath)
1880 argv = append(argv, hostObjCopyPaths...)
1881 if ctxt.HeadType == objabi.Haix {
1882
1883
1884 argv = append(argv, "-nostartfiles")
1885 argv = append(argv, "/lib/crt0_64.o")
1886
1887 extld := ctxt.extld()
1888 name, args := extld[0], extld[1:]
1889
1890 getPathFile := func(file string) string {
1891 args := append(args, "-maix64", "--print-file-name="+file)
1892 out, err := exec.Command(name, args...).CombinedOutput()
1893 if err != nil {
1894 log.Fatalf("running %s failed: %v\n%s", extld, err, out)
1895 }
1896 return strings.Trim(string(out), "\n")
1897 }
1898
1899
1900
1901 crtcxa := getPathFile("crtcxa_64.o")
1902 if !filepath.IsAbs(crtcxa) {
1903 crtcxa = getPathFile("crtcxa.o")
1904 }
1905 crtdbase := getPathFile("crtdbase_64.o")
1906 if !filepath.IsAbs(crtdbase) {
1907 crtdbase = getPathFile("crtdbase.o")
1908 }
1909 argv = append(argv, crtcxa)
1910 argv = append(argv, crtdbase)
1911 }
1912
1913 if ctxt.linkShared {
1914 seenDirs := make(map[string]bool)
1915 seenLibs := make(map[string]bool)
1916 addshlib := func(path string) {
1917 dir, base := filepath.Split(path)
1918 if !seenDirs[dir] {
1919 argv = append(argv, "-L"+dir)
1920 if !rpath.set {
1921 argv = append(argv, "-Wl,-rpath="+dir)
1922 }
1923 seenDirs[dir] = true
1924 }
1925 base = strings.TrimSuffix(base, ".so")
1926 base = strings.TrimPrefix(base, "lib")
1927 if !seenLibs[base] {
1928 argv = append(argv, "-l"+base)
1929 seenLibs[base] = true
1930 }
1931 }
1932 for _, shlib := range ctxt.Shlibs {
1933 addshlib(shlib.Path)
1934 for _, dep := range shlib.Deps {
1935 if dep == "" {
1936 continue
1937 }
1938 libpath := findshlib(ctxt, dep)
1939 if libpath != "" {
1940 addshlib(libpath)
1941 }
1942 }
1943 }
1944 }
1945
1946
1947
1948
1949
1950
1951
1952
1953 checkStatic := func(arg string) {
1954 if ctxt.IsELF && arg == "-static" {
1955 for i := range argv {
1956 if argv[i] == "-rdynamic" || strings.HasPrefix(argv[i], "-Wl,--dynamic-linker,") {
1957 argv[i] = "-static"
1958 }
1959 }
1960 }
1961 }
1962
1963 for _, p := range ldflag {
1964 argv = append(argv, p)
1965 checkStatic(p)
1966 }
1967
1968
1969
1970
1971
1972
1973
1974
1975 if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared && !(ctxt.IsDarwin() && ctxt.IsARM64()) {
1976
1977 for _, nopie := range []string{"-no-pie", "-nopie"} {
1978 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, nopie) {
1979 argv = append(argv, nopie)
1980 break
1981 }
1982 }
1983 }
1984
1985 for _, p := range flagExtldflags {
1986 argv = append(argv, p)
1987 checkStatic(p)
1988 }
1989 if ctxt.HeadType == objabi.Hwindows {
1990
1991
1992 if !isLLD {
1993 p := writeGDBLinkerScript()
1994 argv = append(argv, "-Wl,-T,"+p)
1995 }
1996 if *flagRace {
1997
1998
1999
2000
2001 if isMSVC || ctxt.findLibPath("libsynchronization.a") != "libsynchronization.a" {
2002 argv = append(argv, "-lsynchronization")
2003 }
2004 }
2005 if !isMSVC {
2006
2007
2008 argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
2009 }
2010 argv = append(argv, peimporteddlls()...)
2011 }
2012
2013 argv = ctxt.passLongArgsInResponseFile(argv, altLinker)
2014
2015 if ctxt.Debugvlog != 0 {
2016 ctxt.Logf("host link:")
2017 for _, v := range argv {
2018 ctxt.Logf(" %q", v)
2019 }
2020 ctxt.Logf("\n")
2021 }
2022
2023 cmd := exec.Command(argv[0], argv[1:]...)
2024 out, err := cmd.CombinedOutput()
2025 if err != nil {
2026 Exitf("running %s failed: %v\n%s\n%s", argv[0], err, cmd, out)
2027 }
2028
2029
2030
2031 var save [][]byte
2032 var skipLines int
2033 for _, line := range bytes.SplitAfter(out, []byte("\n")) {
2034
2035 if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
2036 continue
2037 }
2038
2039 if skipLines > 0 {
2040 skipLines--
2041 continue
2042 }
2043
2044
2045 if bytes.Contains(line, []byte("ld: 0711-783")) {
2046 skipLines = 2
2047 continue
2048 }
2049
2050 save = append(save, line)
2051 }
2052 out = bytes.Join(save, nil)
2053
2054 if len(out) > 0 {
2055
2056
2057 if ctxt.IsDarwin() && ctxt.IsAMD64() {
2058 const noPieWarning = "ld: warning: -no_pie is deprecated when targeting new OS versions\n"
2059 if i := bytes.Index(out, []byte(noPieWarning)); i >= 0 {
2060
2061 out = append(out[:i], out[i+len(noPieWarning):]...)
2062 }
2063 }
2064 if ctxt.IsDarwin() {
2065 const bindAtLoadWarning = "ld: warning: -bind_at_load is deprecated on macOS\n"
2066 if i := bytes.Index(out, []byte(bindAtLoadWarning)); i >= 0 {
2067
2068
2069
2070
2071 out = append(out[:i], out[i+len(bindAtLoadWarning):]...)
2072 }
2073 }
2074 ctxt.Logf("%s", out)
2075 }
2076
2077
2078
2079 updateMachoOutFile := func(op string, updateFunc machoUpdateFunc) {
2080
2081 rewrittenOutput := *flagOutfile + "~"
2082 exef, err := os.Open(*flagOutfile)
2083 if err != nil {
2084 Exitf("%s: %s failed: %v", os.Args[0], op, err)
2085 }
2086 defer exef.Close()
2087 exem, err := macho.NewFile(exef)
2088 if err != nil {
2089 Exitf("%s: parsing Mach-O header failed: %v", os.Args[0], err)
2090 }
2091 if err := updateFunc(ctxt, exef, exem, rewrittenOutput); err != nil {
2092 Exitf("%s: %s failed: %v", os.Args[0], op, err)
2093 }
2094 os.Remove(*flagOutfile)
2095 if err := os.Rename(rewrittenOutput, *flagOutfile); err != nil {
2096 Exitf("%s: %v", os.Args[0], err)
2097 }
2098 }
2099
2100 uuidUpdated := false
2101 if combineDwarf {
2102
2103 dsymutilCmd := ctxt.findExtLinkTool("dsymutil")
2104 stripCmd := ctxt.findExtLinkTool("strip")
2105
2106 dsym := filepath.Join(*flagTmpdir, "go.dwarf")
2107 cmd := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym)
2108
2109
2110
2111
2112
2113 dsymDir := filepath.Join(*flagTmpdir, "dsymutil")
2114 err := os.MkdirAll(dsymDir, 0777)
2115 if err != nil {
2116 Exitf("fail to create temp dir: %v", err)
2117 }
2118 cmd.Env = append(os.Environ(), "DSYMUTIL_REPRODUCER_PATH="+dsymDir)
2119 if ctxt.Debugvlog != 0 {
2120 ctxt.Logf("host link dsymutil:")
2121 for _, v := range cmd.Args {
2122 ctxt.Logf(" %q", v)
2123 }
2124 ctxt.Logf("\n")
2125 }
2126 if out, err := cmd.CombinedOutput(); err != nil {
2127 Exitf("%s: running dsymutil failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
2128 }
2129
2130
2131 var stripArgs = []string{"-S"}
2132 if debug_s {
2133
2134
2135
2136 stripArgs = append(stripArgs, "-x")
2137 }
2138 stripArgs = append(stripArgs, *flagOutfile)
2139 if ctxt.Debugvlog != 0 {
2140 ctxt.Logf("host link strip: %q", stripCmd)
2141 for _, v := range stripArgs {
2142 ctxt.Logf(" %q", v)
2143 }
2144 ctxt.Logf("\n")
2145 }
2146 cmd = exec.Command(stripCmd, stripArgs...)
2147 if out, err := cmd.CombinedOutput(); err != nil {
2148 Exitf("%s: running strip failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
2149 }
2150
2151 if _, err := os.Stat(dsym); err == nil {
2152 updateMachoOutFile("combining dwarf",
2153 func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
2154 return machoCombineDwarf(ctxt, exef, exem, dsym, outexe)
2155 })
2156 uuidUpdated = true
2157 }
2158 }
2159 if ctxt.IsDarwin() && !uuidUpdated && len(buildinfo) > 0 {
2160 updateMachoOutFile("rewriting uuid",
2161 func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
2162 return machoRewriteUuid(ctxt, exef, exem, outexe)
2163 })
2164 }
2165 hostlinkfips(ctxt, *flagOutfile, *flagFipso)
2166 if ctxt.NeedCodeSign() {
2167 err := machoCodeSign(ctxt, *flagOutfile)
2168 if err != nil {
2169 Exitf("%s: code signing failed: %v", os.Args[0], err)
2170 }
2171 }
2172 }
2173
2174
2175
2176 func (ctxt *Link) passLongArgsInResponseFile(argv []string, altLinker string) []string {
2177 c := 0
2178 for _, arg := range argv {
2179 c += len(arg)
2180 }
2181
2182 if c < sys.ExecArgLengthLimit {
2183 return argv
2184 }
2185
2186
2187 response := filepath.Join(*flagTmpdir, "response")
2188 if err := os.WriteFile(response, nil, 0644); err != nil {
2189 log.Fatalf("failed while testing response file: %v", err)
2190 }
2191 if !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "@"+response) {
2192 if ctxt.Debugvlog != 0 {
2193 ctxt.Logf("not using response file because linker does not support one")
2194 }
2195 return argv
2196 }
2197
2198 var buf bytes.Buffer
2199 for _, arg := range argv[1:] {
2200
2201 fmt.Fprintf(&buf, "%q\n", arg)
2202 }
2203 if err := os.WriteFile(response, buf.Bytes(), 0644); err != nil {
2204 log.Fatalf("failed while writing response file: %v", err)
2205 }
2206 if ctxt.Debugvlog != 0 {
2207 ctxt.Logf("response file %s contents:\n%s", response, buf.Bytes())
2208 }
2209 return []string{
2210 argv[0],
2211 "@" + response,
2212 }
2213 }
2214
2215 var createTrivialCOnce sync.Once
2216
2217 func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
2218 createTrivialCOnce.Do(func() {
2219 src := filepath.Join(*flagTmpdir, "trivial.c")
2220 if err := os.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
2221 Errorf("WriteFile trivial.c failed: %v", err)
2222 }
2223 })
2224
2225 flags := hostlinkArchArgs(arch)
2226
2227 moreFlags := trimLinkerArgv(append(ldflag, flagExtldflags...))
2228 flags = append(flags, moreFlags...)
2229
2230 if altLinker != "" {
2231 flags = append(flags, "-fuse-ld="+altLinker)
2232 }
2233 trivialPath := filepath.Join(*flagTmpdir, "trivial.c")
2234 outPath := filepath.Join(*flagTmpdir, "a.out")
2235 flags = append(flags, "-o", outPath, flag, trivialPath)
2236
2237 cmd := exec.Command(linker, flags...)
2238 cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
2239 out, err := cmd.CombinedOutput()
2240
2241
2242 return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
2243 }
2244
2245
2246
2247
2248
2249
2250
2251 func peHasLoadConfigDirectorySupport(arch *sys.Arch, linker string) bool {
2252 src := filepath.Join(*flagTmpdir, "loadcfg_test.c")
2253 if err := os.WriteFile(src, []byte(`
2254 #ifdef _WIN64
2255 typedef unsigned long long uintptr;
2256 #else
2257 typedef unsigned long uintptr;
2258 #endif
2259 const uintptr _load_config_used[2] = { sizeof(_load_config_used), 0 };
2260 int main() { return 0; }
2261 `), 0666); err != nil {
2262 return false
2263 }
2264
2265 outPath := filepath.Join(*flagTmpdir, "loadcfg_test.exe")
2266 flags := hostlinkArchArgs(arch)
2267 flags = append(flags, "-o", outPath, src)
2268 cmd := exec.Command(linker, flags...)
2269 cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
2270 if err := cmd.Run(); err != nil {
2271 return false
2272 }
2273
2274 f, err := pe.Open(outPath)
2275 if err != nil {
2276 return false
2277 }
2278 defer f.Close()
2279
2280 switch oh := f.OptionalHeader.(type) {
2281 case *pe.OptionalHeader64:
2282 if int(pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) < len(oh.DataDirectory) {
2283 return oh.DataDirectory[pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress != 0
2284 }
2285 case *pe.OptionalHeader32:
2286 if int(pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) < len(oh.DataDirectory) {
2287 return oh.DataDirectory[pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress != 0
2288 }
2289 }
2290 return false
2291 }
2292
2293
2294
2295 func trimLinkerArgv(argv []string) []string {
2296 flagsWithNextArgSkip := []string{
2297 "-F",
2298 "-l",
2299 "-framework",
2300 "-Wl,-framework",
2301 "-Wl,-rpath",
2302 "-Wl,-undefined",
2303 }
2304 flagsWithNextArgKeep := []string{
2305 "-B",
2306 "-L",
2307 "-arch",
2308 "-isysroot",
2309 "--sysroot",
2310 "-target",
2311 "--target",
2312 "-resource-dir",
2313 "-rtlib",
2314 "--rtlib",
2315 "-stdlib",
2316 "--stdlib",
2317 "-unwindlib",
2318 "--unwindlib",
2319 }
2320 prefixesToKeep := []string{
2321 "-B",
2322 "-L",
2323 "-f",
2324 "-m",
2325 "-p",
2326 "-Wl,",
2327 "-arch",
2328 "-isysroot",
2329 "--sysroot",
2330 "-target",
2331 "--target",
2332 "-resource-dir",
2333 "-rtlib",
2334 "--rtlib",
2335 "-stdlib",
2336 "--stdlib",
2337 "-unwindlib",
2338 "--unwindlib",
2339 "-nostdlib++",
2340 "-nostdlib",
2341 "-nodefaultlibs",
2342 "-nostartfiles",
2343 "-nostdinc++",
2344 "-nostdinc",
2345 "-nobuiltininc",
2346 }
2347
2348 var flags []string
2349 keep := false
2350 skip := false
2351 for _, f := range argv {
2352 if keep {
2353 flags = append(flags, f)
2354 keep = false
2355 } else if skip {
2356 skip = false
2357 } else if f == "" || f[0] != '-' {
2358 } else if slices.Contains(flagsWithNextArgSkip, f) {
2359 skip = true
2360 } else if slices.Contains(flagsWithNextArgKeep, f) {
2361 flags = append(flags, f)
2362 keep = true
2363 } else {
2364 for _, p := range prefixesToKeep {
2365 if strings.HasPrefix(f, p) {
2366 flags = append(flags, f)
2367 break
2368 }
2369 }
2370 }
2371 }
2372 return flags
2373 }
2374
2375
2376
2377 func hostlinkArchArgs(arch *sys.Arch) []string {
2378 switch arch.Family {
2379 case sys.I386:
2380 return []string{"-m32"}
2381 case sys.AMD64:
2382 if buildcfg.GOOS == "darwin" {
2383 return []string{"-arch", "x86_64", "-m64"}
2384 }
2385 return []string{"-m64"}
2386 case sys.S390X:
2387 return []string{"-m64"}
2388 case sys.ARM:
2389 return []string{"-marm"}
2390 case sys.ARM64:
2391 if buildcfg.GOOS == "darwin" {
2392 return []string{"-arch", "arm64"}
2393 }
2394 case sys.Loong64:
2395 return []string{"-mabi=lp64d"}
2396 case sys.MIPS64:
2397 return []string{"-mabi=64"}
2398 case sys.MIPS:
2399 return []string{"-mabi=32"}
2400 case sys.PPC64:
2401 if buildcfg.GOOS == "aix" {
2402 return []string{"-maix64"}
2403 } else {
2404 return []string{"-m64"}
2405 }
2406
2407 }
2408 return nil
2409 }
2410
2411 var wantHdr = objabi.HeaderString()
2412
2413
2414
2415
2416 func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, file string) *Hostobj {
2417 pkg := objabi.PathToPrefix(lib.Pkg)
2418
2419 eof := f.Offset() + length
2420 start := f.Offset()
2421 c1 := bgetc(f)
2422 c2 := bgetc(f)
2423 c3 := bgetc(f)
2424 c4 := bgetc(f)
2425 f.MustSeek(start, 0)
2426
2427 unit := &sym.CompilationUnit{Lib: lib}
2428 lib.Units = append(lib.Units, unit)
2429
2430 magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
2431 if magic == 0x7f454c46 {
2432 ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2433 textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.Flags)
2434 if err != nil {
2435 Errorf("%v", err)
2436 return
2437 }
2438 ehdr.Flags = flags
2439 ctxt.Textp = append(ctxt.Textp, textp...)
2440 }
2441 return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
2442 }
2443
2444 if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
2445 ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2446 textp, err := loadmacho.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2447 if err != nil {
2448 Errorf("%v", err)
2449 return
2450 }
2451 ctxt.Textp = append(ctxt.Textp, textp...)
2452 }
2453 return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
2454 }
2455
2456 switch c1<<8 | c2 {
2457 case 0x4c01,
2458 0x6486,
2459 0xc401,
2460 0x64aa:
2461 ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2462 ls, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2463 if err != nil {
2464 Errorf("%v", err)
2465 return
2466 }
2467 if len(ls.Resources) != 0 {
2468 setpersrc(ctxt, ls.Resources)
2469 }
2470 sehp.pdata = append(sehp.pdata, ls.PData...)
2471 if ls.XData != 0 {
2472 sehp.xdata = append(sehp.xdata, ls.XData)
2473 }
2474 ctxt.Textp = append(ctxt.Textp, ls.Textp...)
2475 }
2476 return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
2477 }
2478
2479 if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
2480 ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2481 textp, err := loadxcoff.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2482 if err != nil {
2483 Errorf("%v", err)
2484 return
2485 }
2486 ctxt.Textp = append(ctxt.Textp, textp...)
2487 }
2488 return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
2489 }
2490
2491 if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' {
2492
2493
2494
2495 unknownObjFormat = true
2496 return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file)
2497 }
2498
2499
2500 line, err := f.ReadString('\n')
2501 if err != nil {
2502 Errorf("truncated object file: %s: %v", pn, err)
2503 return nil
2504 }
2505
2506 if !strings.HasPrefix(line, "go object ") {
2507 if strings.HasSuffix(pn, ".go") {
2508 Exitf("%s: uncompiled .go source file", pn)
2509 return nil
2510 }
2511
2512 if line == ctxt.Arch.Name {
2513
2514 Errorf("%s: stale object file", pn)
2515 return nil
2516 }
2517
2518 Errorf("%s: not an object file: @%d %q", pn, start, line)
2519 return nil
2520 }
2521
2522
2523 if line != wantHdr && !*flagF {
2524 Errorf("%s: linked object header mismatch:\nhave %q\nwant %q\n", pn, line, wantHdr)
2525 }
2526
2527
2528
2529
2530
2531
2532
2533
2534 import0 := f.Offset()
2535
2536 c1 = '\n'
2537 c2 = bgetc(f)
2538 c3 = bgetc(f)
2539 markers := 0
2540 for {
2541 if c1 == '\n' {
2542 if markers%2 == 0 && c2 == '!' && c3 == '\n' {
2543 break
2544 }
2545 if c2 == '$' && c3 == '$' {
2546 markers++
2547 }
2548 }
2549
2550 c1 = c2
2551 c2 = c3
2552 c3 = bgetc(f)
2553 if c3 == -1 {
2554 Errorf("truncated object file: %s", pn)
2555 return nil
2556 }
2557 }
2558
2559 import1 := f.Offset()
2560
2561 f.MustSeek(import0, 0)
2562 ldpkg(ctxt, f, lib, import1-import0-2, pn)
2563 f.MustSeek(import1, 0)
2564
2565 fingerprint := ctxt.loader.Preload(ctxt.IncVersion(), f, lib, unit, eof-f.Offset())
2566 if !fingerprint.IsZero() {
2567
2568
2569
2570
2571
2572 if lib.Fingerprint.IsZero() {
2573 lib.Fingerprint = fingerprint
2574 }
2575 checkFingerprint(lib, fingerprint, lib.Srcref, lib.Fingerprint)
2576 }
2577
2578 addImports(ctxt, lib, pn)
2579 return nil
2580 }
2581
2582
2583
2584
2585
2586 func symbolsAreUnresolved(ctxt *Link, want []string) []bool {
2587 returnAllUndefs := -1
2588 undefs, _ := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
2589 seen := make(map[loader.Sym]struct{})
2590 rval := make([]bool, len(want))
2591 wantm := make(map[string]int)
2592 for k, w := range want {
2593 wantm[w] = k
2594 }
2595 count := 0
2596 for _, s := range undefs {
2597 if _, ok := seen[s]; ok {
2598 continue
2599 }
2600 seen[s] = struct{}{}
2601 if k, ok := wantm[ctxt.loader.SymName(s)]; ok {
2602 rval[k] = true
2603 count++
2604 if count == len(want) {
2605 return rval
2606 }
2607 }
2608 }
2609 return rval
2610 }
2611
2612
2613
2614
2615 func hostObject(ctxt *Link, objname string, path string) {
2616 if ctxt.Debugvlog > 1 {
2617 ctxt.Logf("hostObject(%s)\n", path)
2618 }
2619 objlib := sym.Library{
2620 Pkg: objname,
2621 }
2622 f, err := bio.Open(path)
2623 if err != nil {
2624 Exitf("cannot open host object %q file %s: %v", objname, path, err)
2625 }
2626 defer f.Close()
2627 h := ldobj(ctxt, f, &objlib, 0, path, path)
2628 if h.ld == nil {
2629 Exitf("unrecognized object file format in %s", path)
2630 }
2631 h.file = path
2632 h.length = f.MustSeek(0, 2)
2633 f.MustSeek(h.off, 0)
2634 h.ld(ctxt, f, h.pkg, h.length, h.pn)
2635 if *flagCaptureHostObjs != "" {
2636 captureHostObj(h)
2637 }
2638 }
2639
2640 func checkFingerprint(lib *sym.Library, libfp goobj.FingerprintType, src string, srcfp goobj.FingerprintType) {
2641 if libfp != srcfp {
2642 Exitf("fingerprint mismatch: %s has %x, import from %s expecting %x", lib, libfp, src, srcfp)
2643 }
2644 }
2645
2646 func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
2647 data := make([]byte, sym.Size)
2648 sect := f.Sections[sym.Section]
2649 if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
2650 Errorf("reading %s from non-data section", sym.Name)
2651 }
2652 n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
2653 if uint64(n) != sym.Size {
2654 Errorf("reading contents of %s: %v", sym.Name, err)
2655 }
2656 return data
2657 }
2658
2659 func readwithpad(r io.Reader, sz int32) ([]byte, error) {
2660 data := make([]byte, Rnd(int64(sz), 4))
2661 _, err := io.ReadFull(r, data)
2662 if err != nil {
2663 return nil, err
2664 }
2665 data = data[:sz]
2666 return data, nil
2667 }
2668
2669 func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
2670 for _, sect := range f.Sections {
2671 if sect.Type != elf.SHT_NOTE {
2672 continue
2673 }
2674 r := sect.Open()
2675 for {
2676 var namesize, descsize, noteType int32
2677 err := binary.Read(r, f.ByteOrder, &namesize)
2678 if err != nil {
2679 if err == io.EOF {
2680 break
2681 }
2682 return nil, fmt.Errorf("read namesize failed: %v", err)
2683 }
2684 err = binary.Read(r, f.ByteOrder, &descsize)
2685 if err != nil {
2686 return nil, fmt.Errorf("read descsize failed: %v", err)
2687 }
2688 err = binary.Read(r, f.ByteOrder, ¬eType)
2689 if err != nil {
2690 return nil, fmt.Errorf("read type failed: %v", err)
2691 }
2692 noteName, err := readwithpad(r, namesize)
2693 if err != nil {
2694 return nil, fmt.Errorf("read name failed: %v", err)
2695 }
2696 desc, err := readwithpad(r, descsize)
2697 if err != nil {
2698 return nil, fmt.Errorf("read desc failed: %v", err)
2699 }
2700 if string(name) == string(noteName) && typ == noteType {
2701 return desc, nil
2702 }
2703 }
2704 }
2705 return nil, nil
2706 }
2707
2708 func findshlib(ctxt *Link, shlib string) string {
2709 if filepath.IsAbs(shlib) {
2710 return shlib
2711 }
2712 for _, libdir := range ctxt.Libdir {
2713 libpath := filepath.Join(libdir, shlib)
2714 if _, err := os.Stat(libpath); err == nil {
2715 return libpath
2716 }
2717 }
2718 Errorf("cannot find shared library: %s", shlib)
2719 return ""
2720 }
2721
2722 func ldshlibsyms(ctxt *Link, shlib string) {
2723 var libpath string
2724 if filepath.IsAbs(shlib) {
2725 libpath = shlib
2726 shlib = filepath.Base(shlib)
2727 } else {
2728 libpath = findshlib(ctxt, shlib)
2729 if libpath == "" {
2730 return
2731 }
2732 }
2733 for _, processedlib := range ctxt.Shlibs {
2734 if processedlib.Path == libpath {
2735 return
2736 }
2737 }
2738 if ctxt.Debugvlog > 1 {
2739 ctxt.Logf("ldshlibsyms: found library with name %s at %s\n", shlib, libpath)
2740 }
2741
2742 f, err := elf.Open(libpath)
2743 if err != nil {
2744 Errorf("cannot open shared library: %s", libpath)
2745 return
2746 }
2747
2748
2749
2750
2751 hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
2752 if err != nil {
2753 Errorf("cannot read ABI hash from shared library %s: %v", libpath, err)
2754 return
2755 }
2756
2757 depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
2758 if err != nil {
2759 Errorf("cannot read dep list from shared library %s: %v", libpath, err)
2760 return
2761 }
2762 var deps []string
2763 for _, dep := range strings.Split(string(depsbytes), "\n") {
2764 if dep == "" {
2765 continue
2766 }
2767 if !filepath.IsAbs(dep) {
2768
2769
2770
2771 abs := filepath.Join(filepath.Dir(libpath), dep)
2772 if _, err := os.Stat(abs); err == nil {
2773 dep = abs
2774 }
2775 }
2776 deps = append(deps, dep)
2777 }
2778
2779 syms, err := f.DynamicSymbols()
2780 if err != nil {
2781 Errorf("cannot read symbols from shared library: %s", libpath)
2782 return
2783 }
2784
2785 symAddr := map[string]uint64{}
2786 for _, elfsym := range syms {
2787 if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
2788 continue
2789 }
2790
2791
2792
2793 ver := 0
2794 symname := elfsym.Name
2795 if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && strings.HasPrefix(elfsym.Name, "type:") {
2796 ver = abiInternalVer
2797 } else if buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC {
2798
2799 if strings.HasSuffix(elfsym.Name, ".abiinternal") {
2800 ver = sym.SymVerABIInternal
2801 symname = strings.TrimSuffix(elfsym.Name, ".abiinternal")
2802 } else if strings.HasSuffix(elfsym.Name, ".abi0") {
2803 ver = 0
2804 symname = strings.TrimSuffix(elfsym.Name, ".abi0")
2805 }
2806 }
2807
2808 l := ctxt.loader
2809 s := l.LookupOrCreateSym(symname, ver)
2810
2811
2812
2813
2814
2815 if l.SymType(s) != 0 && l.SymType(s) != sym.SDYNIMPORT {
2816 continue
2817 }
2818 su := l.MakeSymbolUpdater(s)
2819 su.SetType(sym.SDYNIMPORT)
2820 l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
2821 su.SetSize(int64(elfsym.Size))
2822 if elfsym.Section != elf.SHN_UNDEF {
2823
2824 l.SetSymPkg(s, libpath)
2825
2826
2827
2828 sname := l.SymName(s)
2829 if strings.HasPrefix(sname, "type:") && !strings.HasPrefix(sname, "type:.") {
2830 su.SetData(readelfsymboldata(ctxt, f, &elfsym))
2831 }
2832 }
2833
2834 if symname != elfsym.Name {
2835 l.SetSymExtname(s, elfsym.Name)
2836 }
2837 symAddr[elfsym.Name] = elfsym.Value
2838 }
2839
2840
2841
2842
2843 relocTarget := map[uint64]string{}
2844 addends := false
2845 sect := f.SectionByType(elf.SHT_REL)
2846 if sect == nil {
2847 sect = f.SectionByType(elf.SHT_RELA)
2848 if sect == nil {
2849 log.Fatalf("can't find SHT_REL or SHT_RELA section of %s", shlib)
2850 }
2851 addends = true
2852 }
2853
2854 data, err := sect.Data()
2855 if err != nil {
2856 log.Fatalf("can't read relocation section of %s: %v", shlib, err)
2857 }
2858 bo := f.ByteOrder
2859 for len(data) > 0 {
2860 var off, idx uint64
2861 var addend int64
2862 switch f.Class {
2863 case elf.ELFCLASS64:
2864 off = bo.Uint64(data)
2865 info := bo.Uint64(data[8:])
2866 data = data[16:]
2867 if addends {
2868 addend = int64(bo.Uint64(data))
2869 data = data[8:]
2870 }
2871
2872 idx = info >> 32
2873 typ := info & 0xffff
2874
2875
2876 switch typ {
2877 case uint64(elf.R_X86_64_64):
2878 case uint64(elf.R_AARCH64_ABS64):
2879 case uint64(elf.R_LARCH_64):
2880 case uint64(elf.R_390_64):
2881 case uint64(elf.R_PPC64_ADDR64):
2882 default:
2883 continue
2884 }
2885 case elf.ELFCLASS32:
2886 off = uint64(bo.Uint32(data))
2887 info := bo.Uint32(data[4:])
2888 data = data[8:]
2889 if addends {
2890 addend = int64(int32(bo.Uint32(data)))
2891 data = data[4:]
2892 }
2893
2894 idx = uint64(info >> 8)
2895 typ := info & 0xff
2896
2897 switch typ {
2898 case uint32(elf.R_386_32):
2899 case uint32(elf.R_ARM_ABS32):
2900 default:
2901 continue
2902 }
2903 default:
2904 log.Fatalf("unknown bit size %s", f.Class)
2905 }
2906 if addend != 0 {
2907 continue
2908 }
2909 relocTarget[off] = syms[idx-1].Name
2910 }
2911
2912 ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, symAddr: symAddr, relocTarget: relocTarget})
2913 }
2914
2915 func addsection(ldr *loader.Loader, arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
2916 sect := ldr.NewSection()
2917 sect.Rwx = uint8(rwx)
2918 sect.Name = name
2919 sect.Seg = seg
2920 sect.Align = int32(arch.PtrSize)
2921 seg.Sections = append(seg.Sections, sect)
2922 return sect
2923 }
2924
2925 func usage() {
2926 fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
2927 objabi.Flagprint(os.Stderr)
2928 Exit(2)
2929 }
2930
2931 type SymbolType int8
2932
2933 const (
2934
2935 TextSym SymbolType = 'T'
2936 DataSym SymbolType = 'D'
2937 BSSSym SymbolType = 'B'
2938 UndefinedSym SymbolType = 'U'
2939 TLSSym SymbolType = 't'
2940 FrameSym SymbolType = 'm'
2941 ParamSym SymbolType = 'p'
2942 AutoSym SymbolType = 'a'
2943
2944
2945 DeletedAutoSym = 'x'
2946 )
2947
2948
2949 func (ctxt *Link) defineInternal(p string, t sym.SymKind) loader.Sym {
2950 s := ctxt.loader.CreateSymForUpdate(p, 0)
2951 s.SetType(t)
2952 s.SetSpecial(true)
2953 s.SetLocal(true)
2954 return s.Sym()
2955 }
2956
2957 func (ctxt *Link) xdefine(p string, t sym.SymKind, v int64) loader.Sym {
2958 s := ctxt.defineInternal(p, t)
2959 ctxt.loader.SetSymValue(s, v)
2960 return s
2961 }
2962
2963 func datoff(ldr *loader.Loader, s loader.Sym, addr int64) int64 {
2964 if uint64(addr) >= Segdata.Vaddr {
2965 return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
2966 }
2967 if uint64(addr) >= Segtext.Vaddr {
2968 return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
2969 }
2970 ldr.Errorf(s, "invalid datoff %#x", addr)
2971 return 0
2972 }
2973
2974 func Entryvalue(ctxt *Link) int64 {
2975 a := *flagEntrySymbol
2976 if a[0] >= '0' && a[0] <= '9' {
2977 return atolwhex(a)
2978 }
2979 ldr := ctxt.loader
2980 s := ldr.Lookup(a, 0)
2981 if s == 0 {
2982 Errorf("missing entry symbol %q", a)
2983 return 0
2984 }
2985 st := ldr.SymType(s)
2986 if st == 0 {
2987 return *FlagTextAddr
2988 }
2989 if !ctxt.IsAIX() && !st.IsText() {
2990 ldr.Errorf(s, "entry not text")
2991 }
2992 return ldr.SymValue(s)
2993 }
2994
2995 func (ctxt *Link) callgraph() {
2996 if !*FlagC {
2997 return
2998 }
2999
3000 ldr := ctxt.loader
3001 for _, s := range ctxt.Textp {
3002 relocs := ldr.Relocs(s)
3003 for i := 0; i < relocs.Count(); i++ {
3004 r := relocs.At(i)
3005 rs := r.Sym()
3006 if rs == 0 {
3007 continue
3008 }
3009 if r.Type().IsDirectCall() && ldr.SymType(rs).IsText() {
3010 ctxt.Logf("%s calls %s\n", ldr.SymName(s), ldr.SymName(rs))
3011 }
3012 }
3013 }
3014 }
3015
3016 func Rnd(v int64, r int64) int64 {
3017 if r <= 0 {
3018 return v
3019 }
3020 v += r - 1
3021 c := v % r
3022 if c < 0 {
3023 c += r
3024 }
3025 v -= c
3026 return v
3027 }
3028
3029 func bgetc(r *bio.Reader) int {
3030 c, err := r.ReadByte()
3031 if err != nil {
3032 if err != io.EOF {
3033 log.Fatalf("reading input: %v", err)
3034 }
3035 return -1
3036 }
3037 return int(c)
3038 }
3039
3040 type markKind uint8
3041 const (
3042 _ markKind = iota
3043 visiting
3044 visited
3045 )
3046
3047 func postorder(libs []*sym.Library) []*sym.Library {
3048 order := make([]*sym.Library, 0, len(libs))
3049 mark := make(map[*sym.Library]markKind, len(libs))
3050 for _, lib := range libs {
3051 dfs(lib, mark, &order)
3052 }
3053 return order
3054 }
3055
3056 func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library) {
3057 if mark[lib] == visited {
3058 return
3059 }
3060 if mark[lib] == visiting {
3061 panic("found import cycle while visiting " + lib.Pkg)
3062 }
3063 mark[lib] = visiting
3064 for _, i := range lib.Imports {
3065 dfs(i, mark, order)
3066 }
3067 mark[lib] = visited
3068 *order = append(*order, lib)
3069 }
3070
3071 func ElfSymForReloc(ctxt *Link, s loader.Sym) int32 {
3072
3073
3074 les := ctxt.loader.SymLocalElfSym(s)
3075 if les != 0 {
3076 return les
3077 } else {
3078 return ctxt.loader.SymElfSym(s)
3079 }
3080 }
3081
3082 func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, elfRelocTyp uint32) {
3083 if ldr.SymGot(s) >= 0 {
3084 return
3085 }
3086
3087 Adddynsym(ldr, target, syms, s)
3088 got := ldr.MakeSymbolUpdater(syms.GOT)
3089 ldr.SetGot(s, int32(got.Size()))
3090 got.AddUint(target.Arch, 0)
3091
3092 if target.IsElf() {
3093 if target.Arch.PtrSize == 8 {
3094 rela := ldr.MakeSymbolUpdater(syms.Rela)
3095 rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
3096 rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
3097 rela.AddUint64(target.Arch, 0)
3098 } else {
3099 rel := ldr.MakeSymbolUpdater(syms.Rel)
3100 rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
3101 rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), elfRelocTyp))
3102 }
3103 } else if target.IsDarwin() {
3104 leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
3105 leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
3106 if target.IsPIE() && target.IsInternal() {
3107
3108
3109
3110 MachoAddBind(syms.GOT, int64(ldr.SymGot(s)), s)
3111 }
3112 } else {
3113 ldr.Errorf(s, "addgotsym: unsupported binary format")
3114 }
3115 }
3116
3117 var hostobjcounter int
3118
3119
3120
3121
3122
3123
3124 func captureHostObj(h *Hostobj) {
3125
3126 ofile := fmt.Sprintf("captured-obj-%d.o", hostobjcounter)
3127 ifile := fmt.Sprintf("captured-obj-%d.txt", hostobjcounter)
3128 hostobjcounter++
3129 opath := filepath.Join(*flagCaptureHostObjs, ofile)
3130 ipath := filepath.Join(*flagCaptureHostObjs, ifile)
3131
3132
3133 info := fmt.Sprintf("pkg: %s\npn: %s\nfile: %s\noff: %d\nlen: %d\n",
3134 h.pkg, h.pn, h.file, h.off, h.length)
3135 if err := os.WriteFile(ipath, []byte(info), 0666); err != nil {
3136 log.Fatalf("error writing captured host obj info %s: %v", ipath, err)
3137 }
3138
3139 readObjData := func() []byte {
3140 inf, err := os.Open(h.file)
3141 if err != nil {
3142 log.Fatalf("capturing host obj: open failed on %s: %v", h.pn, err)
3143 }
3144 defer inf.Close()
3145 res := make([]byte, h.length)
3146 if n, err := inf.ReadAt(res, h.off); err != nil || n != int(h.length) {
3147 log.Fatalf("capturing host obj: readat failed on %s: %v", h.pn, err)
3148 }
3149 return res
3150 }
3151
3152
3153 if err := os.WriteFile(opath, readObjData(), 0666); err != nil {
3154 log.Fatalf("error writing captured host object %s: %v", opath, err)
3155 }
3156
3157 fmt.Fprintf(os.Stderr, "link: info: captured host object %s to %s\n",
3158 h.file, opath)
3159 }
3160
3161
3162
3163
3164 func (ctxt *Link) findExtLinkTool(toolname string) string {
3165 var cc []string
3166 cc = append(cc, ctxt.extld()...)
3167 cc = append(cc, hostlinkArchArgs(ctxt.Arch)...)
3168 cc = append(cc, "--print-prog-name", toolname)
3169 out, err := exec.Command(cc[0], cc[1:]...).CombinedOutput()
3170 if err != nil {
3171 Exitf("%s: finding %s failed: %v\n%s", os.Args[0], toolname, err, out)
3172 }
3173 cmdpath := strings.TrimRight(string(out), "\r\n")
3174 return cmdpath
3175 }
3176
3177
3178
3179 func (ctxt *Link) isMSVC() bool {
3180 extld := ctxt.extld()
3181 name, args := extld[0], extld[1:]
3182 args = append(args, trimLinkerArgv(flagExtldflags)...)
3183 args = append(args, "--version")
3184 cmd := exec.Command(name, args...)
3185 if out, err := cmd.CombinedOutput(); err == nil {
3186 if bytes.Contains(out, []byte("-msvc\n")) || bytes.Contains(out, []byte("-msvc\r")) {
3187 return true
3188 }
3189 }
3190 return false
3191 }
3192
3193
3194 func (ctxt *Link) isLLD() bool {
3195 extld := ctxt.extld()
3196 name, args := extld[0], extld[1:]
3197 args = append(args, trimLinkerArgv(flagExtldflags)...)
3198 args = append(args, "-Wl,--version")
3199 cmd := exec.Command(name, args...)
3200 if out, err := cmd.CombinedOutput(); err == nil {
3201 if bytes.Contains(out, []byte("LLD ")) {
3202 return true
3203 }
3204 }
3205 return false
3206 }
3207
View as plain text