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 }
1483 if !combineDwarf {
1484 argv = append(argv, "-Wl,-S")
1485 if debug_s {
1486
1487
1488
1489 argv = append(argv, "-Wl,-x")
1490 }
1491 }
1492 if *flagRace {
1493
1494
1495
1496 argv = append(argv, "-Wl,-U,__dyld_get_dyld_header")
1497 }
1498 if *flagHostBuildid == "none" {
1499 argv = append(argv, "-Wl,-no_uuid")
1500 }
1501 case objabi.Hopenbsd:
1502 argv = append(argv, "-pthread")
1503 if ctxt.BuildMode != BuildModePIE {
1504 argv = append(argv, "-Wl,-nopie")
1505 }
1506 if linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,-z,nobtcfi") {
1507
1508
1509 argv = append(argv, "-Wl,-z,nobtcfi")
1510 }
1511 if ctxt.Arch.InFamily(sys.ARM64) {
1512
1513
1514
1515 argv = append(argv, "-Wl,--no-execute-only")
1516 }
1517 case objabi.Hwindows:
1518 isMSVC = ctxt.isMSVC()
1519 if !isMSVC {
1520 isLLD = ctxt.isLLD()
1521 }
1522 if isMSVC {
1523
1524
1525
1526
1527 wlPrefix = "-Wl,-"
1528 }
1529
1530 if windowsgui {
1531 argv = append(argv, "-mwindows")
1532 } else {
1533 argv = append(argv, "-mconsole")
1534 }
1535
1536
1537
1538 argv = append(argv, wlPrefix+"tsaware")
1539
1540
1541 argv = append(argv, wlPrefix+"nxcompat")
1542
1543 if !isMSVC {
1544 peMajorVersion := PeMinimumTargetMajorVersion
1545 peMinorVersion := PeMinimumTargetMinorVersion
1546 if peMajorVersion >= 10 && !isLLD &&
1547 !peHasLoadConfigDirectorySupport(ctxt.Arch, argv[0]) {
1548
1549
1550
1551
1552
1553 peMajorVersion = 6
1554 peMinorVersion = 1
1555 }
1556 argv = append(argv, fmt.Sprintf("-Wl,--major-os-version=%d", peMajorVersion))
1557 argv = append(argv, fmt.Sprintf("-Wl,--minor-os-version=%d", peMinorVersion))
1558 argv = append(argv, fmt.Sprintf("-Wl,--major-subsystem-version=%d", peMajorVersion))
1559 argv = append(argv, fmt.Sprintf("-Wl,--minor-subsystem-version=%d", peMinorVersion))
1560 }
1561 case objabi.Haix:
1562 argv = append(argv, "-pthread")
1563
1564
1565 argv = append(argv, "-Wl,-bnoobjreorder")
1566
1567
1568 argv = append(argv, "-mcmodel=large")
1569 argv = append(argv, "-Wl,-bbigtoc")
1570 }
1571
1572
1573
1574
1575 if ctxt.IsPPC64() && ctxt.IsElf() && buildcfg.GOPPC64 >= 10 {
1576 if !linkerFlagSupported(ctxt.Arch, argv[0], "", "-mcpu=power10") {
1577 Exitf("The external toolchain does not support -mcpu=power10. " +
1578 " This is required to externally link GOPPC64 >= power10")
1579 }
1580 }
1581
1582
1583 addASLRargs := func(argv []string, val bool) []string {
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599 var dbopt string
1600 var heopt string
1601 dbon := wlPrefix + "dynamicbase"
1602 heon := wlPrefix + "high-entropy-va"
1603 dboff := wlPrefix + "disable-dynamicbase"
1604 heoff := wlPrefix + "disable-high-entropy-va"
1605 if isMSVC {
1606 heon = wlPrefix + "highentropyva"
1607 heoff = wlPrefix + "highentropyva:no"
1608 dboff = wlPrefix + "dynamicbase:no"
1609 }
1610 if val {
1611 dbopt = dbon
1612 heopt = heon
1613 } else {
1614
1615 newer := linkerFlagSupported(ctxt.Arch, argv[0], "", dboff)
1616 if newer {
1617
1618 dbopt = dboff
1619 heopt = heoff
1620 } else {
1621
1622
1623 dbopt = ""
1624 heopt = ""
1625 }
1626 }
1627 if dbopt != "" {
1628 argv = append(argv, dbopt)
1629 }
1630
1631 if ctxt.Arch.PtrSize >= 8 && heopt != "" {
1632 argv = append(argv, heopt)
1633 }
1634 return argv
1635 }
1636
1637 switch ctxt.BuildMode {
1638 case BuildModeExe:
1639 if ctxt.HeadType == objabi.Hdarwin {
1640 if machoPlatform == PLATFORM_MACOS && ctxt.IsAMD64() {
1641 argv = append(argv, "-Wl,-no_pie")
1642 }
1643 }
1644 if *flagRace && ctxt.HeadType == objabi.Hwindows {
1645
1646
1647
1648
1649 argv = addASLRargs(argv, false)
1650 }
1651 case BuildModePIE:
1652 switch ctxt.HeadType {
1653 case objabi.Hdarwin, objabi.Haix:
1654 case objabi.Hwindows:
1655 if *flagAslr && *flagRace {
1656
1657
1658
1659 *flagAslr = false
1660 }
1661 argv = addASLRargs(argv, *flagAslr)
1662 default:
1663
1664 if ctxt.UseRelro() {
1665 argv = append(argv, "-Wl,-z,relro")
1666 }
1667 argv = append(argv, "-pie")
1668 }
1669 case BuildModeCShared:
1670 if ctxt.HeadType == objabi.Hdarwin {
1671 argv = append(argv, "-dynamiclib")
1672 } else {
1673 if ctxt.UseRelro() {
1674 argv = append(argv, "-Wl,-z,relro")
1675 }
1676 argv = append(argv, "-shared")
1677 if ctxt.HeadType == objabi.Hwindows {
1678 argv = addASLRargs(argv, *flagAslr)
1679 } else {
1680
1681
1682 argv = append(argv, "-Wl,-z,nodelete")
1683
1684 argv = append(argv, "-Wl,-Bsymbolic")
1685 }
1686 }
1687 case BuildModeShared:
1688 if ctxt.UseRelro() {
1689 argv = append(argv, "-Wl,-z,relro")
1690 }
1691 argv = append(argv, "-shared")
1692 case BuildModePlugin:
1693 if ctxt.HeadType == objabi.Hdarwin {
1694 argv = append(argv, "-dynamiclib")
1695 } else {
1696 if ctxt.UseRelro() {
1697 argv = append(argv, "-Wl,-z,relro")
1698 }
1699 argv = append(argv, "-shared")
1700 }
1701 }
1702
1703 var altLinker string
1704 if ctxt.IsELF && (ctxt.DynlinkingGo() || *flagBindNow) {
1705
1706
1707
1708
1709
1710 argv = append(argv, "-Wl,-z,now")
1711 }
1712
1713 if ctxt.IsELF && ctxt.DynlinkingGo() {
1714
1715
1716
1717 argv = append(argv, "-Wl,-z,nocopyreloc")
1718
1719 if buildcfg.GOOS == "android" {
1720
1721 altLinker = "lld"
1722 }
1723
1724 if ctxt.Arch.InFamily(sys.ARM64) && buildcfg.GOOS == "linux" {
1725
1726
1727
1728
1729
1730
1731
1732 useGold := false
1733 name, args := flagExtld[0], flagExtld[1:]
1734 args = append(args, "-Wl,--version")
1735 cmd := exec.Command(name, args...)
1736 if out, err := cmd.CombinedOutput(); err == nil {
1737
1738 for line := range strings.Lines(string(out)) {
1739 if !strings.HasPrefix(line, "GNU ld ") {
1740 continue
1741 }
1742 fields := strings.Fields(line[len("GNU ld "):])
1743 var major, minor int
1744 if ret, err := fmt.Sscanf(fields[len(fields)-1], "%d.%d", &major, &minor); ret == 2 && err == nil {
1745 if major == 2 && minor <= 35 {
1746 useGold = true
1747 }
1748 break
1749 }
1750 }
1751 }
1752
1753 if useGold {
1754
1755 altLinker = "gold"
1756
1757
1758
1759
1760 args = flagExtld[1:]
1761 args = append(args, "-fuse-ld=gold", "-Wl,--version")
1762 cmd = exec.Command(name, args...)
1763 if out, err := cmd.CombinedOutput(); err == nil {
1764 if !bytes.Contains(out, []byte("GNU gold")) {
1765 log.Fatalf("ARM64 external linker must be ld>=2.36 or gold (issue #15696, 22040), but is not: %s", out)
1766 }
1767 }
1768 }
1769 }
1770 }
1771 if ctxt.Arch.Family == sys.ARM64 && buildcfg.GOOS == "freebsd" {
1772
1773 altLinker = "bfd"
1774
1775
1776 name, args := flagExtld[0], flagExtld[1:]
1777 args = append(args, "-fuse-ld=bfd", "-Wl,--version")
1778 cmd := exec.Command(name, args...)
1779 if out, err := cmd.CombinedOutput(); err == nil {
1780 if !bytes.Contains(out, []byte("GNU ld")) {
1781 log.Fatalf("ARM64 external linker must be ld.bfd (issue #35197), please install devel/binutils")
1782 }
1783 }
1784 }
1785 if altLinker != "" {
1786 argv = append(argv, "-fuse-ld="+altLinker)
1787 }
1788
1789 if ctxt.IsELF && linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,--build-id=0x1234567890abcdef") {
1790 if len(buildinfo) > 0 {
1791 argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
1792 } else if *flagHostBuildid == "none" {
1793 argv = append(argv, "-Wl,--build-id=none")
1794 }
1795 }
1796
1797
1798
1799
1800
1801
1802
1803 outopt := *flagOutfile
1804 if buildcfg.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
1805 outopt += "."
1806 }
1807 argv = append(argv, "-o")
1808 argv = append(argv, outopt)
1809
1810 if rpath.val != "" {
1811 argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
1812 }
1813
1814 if *flagInterpreter != "" {
1815
1816
1817
1818
1819 argv = append(argv, fmt.Sprintf("-Wl,--dynamic-linker,%s", *flagInterpreter))
1820 }
1821
1822
1823 switch {
1824 case ctxt.IsELF:
1825 if ctxt.DynlinkingGo() || ctxt.BuildMode == BuildModeCShared || !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "-Wl,--export-dynamic-symbol=main") {
1826 argv = append(argv, "-rdynamic")
1827 } else {
1828 var exports []string
1829 ctxt.loader.ForAllCgoExportDynamic(func(s loader.Sym) {
1830 exports = append(exports, "-Wl,--export-dynamic-symbol="+ctxt.loader.SymExtname(s))
1831 })
1832 sort.Strings(exports)
1833 argv = append(argv, exports...)
1834 }
1835 case ctxt.IsAIX():
1836 fileName := xcoffCreateExportFile(ctxt)
1837 argv = append(argv, "-Wl,-bE:"+fileName)
1838 case ctxt.IsWindows() && !slices.Contains(flagExtldflags, wlPrefix+"export-all-symbols"):
1839 fileName := peCreateExportFile(ctxt, filepath.Base(outopt))
1840 prefix := ""
1841 if isMSVC {
1842 prefix = "-Wl,-def:"
1843 }
1844 argv = append(argv, prefix+fileName)
1845 }
1846
1847 const unusedArguments = "-Qunused-arguments"
1848 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, unusedArguments) {
1849 argv = append(argv, unusedArguments)
1850 }
1851
1852 if ctxt.IsWindows() {
1853
1854
1855
1856
1857 const noTimeStamp = "-Wl,--no-insert-timestamp"
1858 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, noTimeStamp) {
1859 argv = append(argv, noTimeStamp)
1860 }
1861 }
1862
1863 const compressDWARF = "-Wl,--compress-debug-sections=zlib"
1864 if ctxt.compressDWARF && linkerFlagSupported(ctxt.Arch, argv[0], altLinker, compressDWARF) {
1865 argv = append(argv, compressDWARF)
1866 }
1867
1868 hostObjCopyPaths := ctxt.hostobjCopy()
1869 cleanTimeStamps(hostObjCopyPaths)
1870 godotopath := filepath.Join(*flagTmpdir, "go.o")
1871 cleanTimeStamps([]string{godotopath})
1872
1873 argv = append(argv, godotopath)
1874 argv = append(argv, hostObjCopyPaths...)
1875 if ctxt.HeadType == objabi.Haix {
1876
1877
1878 argv = append(argv, "-nostartfiles")
1879 argv = append(argv, "/lib/crt0_64.o")
1880
1881 extld := ctxt.extld()
1882 name, args := extld[0], extld[1:]
1883
1884 getPathFile := func(file string) string {
1885 args := append(args, "-maix64", "--print-file-name="+file)
1886 out, err := exec.Command(name, args...).CombinedOutput()
1887 if err != nil {
1888 log.Fatalf("running %s failed: %v\n%s", extld, err, out)
1889 }
1890 return strings.Trim(string(out), "\n")
1891 }
1892
1893
1894
1895 crtcxa := getPathFile("crtcxa_64.o")
1896 if !filepath.IsAbs(crtcxa) {
1897 crtcxa = getPathFile("crtcxa.o")
1898 }
1899 crtdbase := getPathFile("crtdbase_64.o")
1900 if !filepath.IsAbs(crtdbase) {
1901 crtdbase = getPathFile("crtdbase.o")
1902 }
1903 argv = append(argv, crtcxa)
1904 argv = append(argv, crtdbase)
1905 }
1906
1907 if ctxt.linkShared {
1908 seenDirs := make(map[string]bool)
1909 seenLibs := make(map[string]bool)
1910 addshlib := func(path string) {
1911 dir, base := filepath.Split(path)
1912 if !seenDirs[dir] {
1913 argv = append(argv, "-L"+dir)
1914 if !rpath.set {
1915 argv = append(argv, "-Wl,-rpath="+dir)
1916 }
1917 seenDirs[dir] = true
1918 }
1919 base = strings.TrimSuffix(base, ".so")
1920 base = strings.TrimPrefix(base, "lib")
1921 if !seenLibs[base] {
1922 argv = append(argv, "-l"+base)
1923 seenLibs[base] = true
1924 }
1925 }
1926 for _, shlib := range ctxt.Shlibs {
1927 addshlib(shlib.Path)
1928 for _, dep := range shlib.Deps {
1929 if dep == "" {
1930 continue
1931 }
1932 libpath := findshlib(ctxt, dep)
1933 if libpath != "" {
1934 addshlib(libpath)
1935 }
1936 }
1937 }
1938 }
1939
1940
1941
1942
1943
1944
1945
1946
1947 checkStatic := func(arg string) {
1948 if ctxt.IsELF && arg == "-static" {
1949 for i := range argv {
1950 if argv[i] == "-rdynamic" || strings.HasPrefix(argv[i], "-Wl,--dynamic-linker,") {
1951 argv[i] = "-static"
1952 }
1953 }
1954 }
1955 }
1956
1957 for _, p := range ldflag {
1958 argv = append(argv, p)
1959 checkStatic(p)
1960 }
1961
1962
1963
1964
1965
1966
1967
1968
1969 if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared && !(ctxt.IsDarwin() && ctxt.IsARM64()) {
1970
1971 for _, nopie := range []string{"-no-pie", "-nopie"} {
1972 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, nopie) {
1973 argv = append(argv, nopie)
1974 break
1975 }
1976 }
1977 }
1978
1979 for _, p := range flagExtldflags {
1980 argv = append(argv, p)
1981 checkStatic(p)
1982 }
1983 if ctxt.HeadType == objabi.Hwindows {
1984
1985
1986 if !isLLD {
1987 p := writeGDBLinkerScript()
1988 argv = append(argv, "-Wl,-T,"+p)
1989 }
1990 if *flagRace {
1991
1992
1993
1994
1995 if isMSVC || ctxt.findLibPath("libsynchronization.a") != "libsynchronization.a" {
1996 argv = append(argv, "-lsynchronization")
1997 }
1998 }
1999 if !isMSVC {
2000
2001
2002 argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
2003 }
2004 argv = append(argv, peimporteddlls()...)
2005 }
2006
2007 argv = ctxt.passLongArgsInResponseFile(argv, altLinker)
2008
2009 if ctxt.Debugvlog != 0 {
2010 ctxt.Logf("host link:")
2011 for _, v := range argv {
2012 ctxt.Logf(" %q", v)
2013 }
2014 ctxt.Logf("\n")
2015 }
2016
2017 cmd := exec.Command(argv[0], argv[1:]...)
2018 out, err := cmd.CombinedOutput()
2019 if err != nil {
2020 Exitf("running %s failed: %v\n%s\n%s", argv[0], err, cmd, out)
2021 }
2022
2023
2024
2025 var save [][]byte
2026 var skipLines int
2027 for _, line := range bytes.SplitAfter(out, []byte("\n")) {
2028
2029 if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
2030 continue
2031 }
2032
2033 if skipLines > 0 {
2034 skipLines--
2035 continue
2036 }
2037
2038
2039 if bytes.Contains(line, []byte("ld: 0711-783")) {
2040 skipLines = 2
2041 continue
2042 }
2043
2044 save = append(save, line)
2045 }
2046 out = bytes.Join(save, nil)
2047
2048 if len(out) > 0 {
2049
2050
2051 if ctxt.IsDarwin() && ctxt.IsAMD64() {
2052 const noPieWarning = "ld: warning: -no_pie is deprecated when targeting new OS versions\n"
2053 if i := bytes.Index(out, []byte(noPieWarning)); i >= 0 {
2054
2055 out = append(out[:i], out[i+len(noPieWarning):]...)
2056 }
2057 }
2058 if ctxt.IsDarwin() {
2059 const bindAtLoadWarning = "ld: warning: -bind_at_load is deprecated on macOS\n"
2060 if i := bytes.Index(out, []byte(bindAtLoadWarning)); i >= 0 {
2061
2062
2063
2064
2065 out = append(out[:i], out[i+len(bindAtLoadWarning):]...)
2066 }
2067 }
2068 ctxt.Logf("%s", out)
2069 }
2070
2071
2072
2073 updateMachoOutFile := func(op string, updateFunc machoUpdateFunc) {
2074
2075 rewrittenOutput := *flagOutfile + "~"
2076 exef, err := os.Open(*flagOutfile)
2077 if err != nil {
2078 Exitf("%s: %s failed: %v", os.Args[0], op, err)
2079 }
2080 defer exef.Close()
2081 exem, err := macho.NewFile(exef)
2082 if err != nil {
2083 Exitf("%s: parsing Mach-O header failed: %v", os.Args[0], err)
2084 }
2085 if err := updateFunc(ctxt, exef, exem, rewrittenOutput); err != nil {
2086 Exitf("%s: %s failed: %v", os.Args[0], op, err)
2087 }
2088 os.Remove(*flagOutfile)
2089 if err := os.Rename(rewrittenOutput, *flagOutfile); err != nil {
2090 Exitf("%s: %v", os.Args[0], err)
2091 }
2092 }
2093
2094 uuidUpdated := false
2095 if combineDwarf {
2096
2097 dsymutilCmd := ctxt.findExtLinkTool("dsymutil")
2098 stripCmd := ctxt.findExtLinkTool("strip")
2099
2100 dsym := filepath.Join(*flagTmpdir, "go.dwarf")
2101 cmd := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym)
2102
2103
2104
2105
2106
2107 dsymDir := filepath.Join(*flagTmpdir, "dsymutil")
2108 err := os.MkdirAll(dsymDir, 0777)
2109 if err != nil {
2110 Exitf("fail to create temp dir: %v", err)
2111 }
2112 cmd.Env = append(os.Environ(), "DSYMUTIL_REPRODUCER_PATH="+dsymDir)
2113 if ctxt.Debugvlog != 0 {
2114 ctxt.Logf("host link dsymutil:")
2115 for _, v := range cmd.Args {
2116 ctxt.Logf(" %q", v)
2117 }
2118 ctxt.Logf("\n")
2119 }
2120 if out, err := cmd.CombinedOutput(); err != nil {
2121 Exitf("%s: running dsymutil failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
2122 }
2123
2124
2125 var stripArgs = []string{"-S"}
2126 if debug_s {
2127
2128
2129
2130 stripArgs = append(stripArgs, "-x")
2131 }
2132 stripArgs = append(stripArgs, *flagOutfile)
2133 if ctxt.Debugvlog != 0 {
2134 ctxt.Logf("host link strip: %q", stripCmd)
2135 for _, v := range stripArgs {
2136 ctxt.Logf(" %q", v)
2137 }
2138 ctxt.Logf("\n")
2139 }
2140 cmd = exec.Command(stripCmd, stripArgs...)
2141 if out, err := cmd.CombinedOutput(); err != nil {
2142 Exitf("%s: running strip failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
2143 }
2144
2145 if _, err := os.Stat(dsym); err == nil {
2146 updateMachoOutFile("combining dwarf",
2147 func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
2148 return machoCombineDwarf(ctxt, exef, exem, dsym, outexe)
2149 })
2150 uuidUpdated = true
2151 }
2152 }
2153 if ctxt.IsDarwin() && !uuidUpdated && len(buildinfo) > 0 {
2154 updateMachoOutFile("rewriting uuid",
2155 func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
2156 return machoRewriteUuid(ctxt, exef, exem, outexe)
2157 })
2158 }
2159 hostlinkfips(ctxt, *flagOutfile, *flagFipso)
2160 if ctxt.NeedCodeSign() {
2161 err := machoCodeSign(ctxt, *flagOutfile)
2162 if err != nil {
2163 Exitf("%s: code signing failed: %v", os.Args[0], err)
2164 }
2165 }
2166 }
2167
2168
2169
2170 func (ctxt *Link) passLongArgsInResponseFile(argv []string, altLinker string) []string {
2171 c := 0
2172 for _, arg := range argv {
2173 c += len(arg)
2174 }
2175
2176 if c < sys.ExecArgLengthLimit {
2177 return argv
2178 }
2179
2180
2181 response := filepath.Join(*flagTmpdir, "response")
2182 if err := os.WriteFile(response, nil, 0644); err != nil {
2183 log.Fatalf("failed while testing response file: %v", err)
2184 }
2185 if !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "@"+response) {
2186 if ctxt.Debugvlog != 0 {
2187 ctxt.Logf("not using response file because linker does not support one")
2188 }
2189 return argv
2190 }
2191
2192 var buf bytes.Buffer
2193 for _, arg := range argv[1:] {
2194
2195 fmt.Fprintf(&buf, "%q\n", arg)
2196 }
2197 if err := os.WriteFile(response, buf.Bytes(), 0644); err != nil {
2198 log.Fatalf("failed while writing response file: %v", err)
2199 }
2200 if ctxt.Debugvlog != 0 {
2201 ctxt.Logf("response file %s contents:\n%s", response, buf.Bytes())
2202 }
2203 return []string{
2204 argv[0],
2205 "@" + response,
2206 }
2207 }
2208
2209 var createTrivialCOnce sync.Once
2210
2211 func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
2212 createTrivialCOnce.Do(func() {
2213 src := filepath.Join(*flagTmpdir, "trivial.c")
2214 if err := os.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
2215 Errorf("WriteFile trivial.c failed: %v", err)
2216 }
2217 })
2218
2219 flags := hostlinkArchArgs(arch)
2220
2221 moreFlags := trimLinkerArgv(append(ldflag, flagExtldflags...))
2222 flags = append(flags, moreFlags...)
2223
2224 if altLinker != "" {
2225 flags = append(flags, "-fuse-ld="+altLinker)
2226 }
2227 trivialPath := filepath.Join(*flagTmpdir, "trivial.c")
2228 outPath := filepath.Join(*flagTmpdir, "a.out")
2229 flags = append(flags, "-o", outPath, flag, trivialPath)
2230
2231 cmd := exec.Command(linker, flags...)
2232 cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
2233 out, err := cmd.CombinedOutput()
2234
2235
2236 return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
2237 }
2238
2239
2240
2241
2242
2243
2244
2245 func peHasLoadConfigDirectorySupport(arch *sys.Arch, linker string) bool {
2246 src := filepath.Join(*flagTmpdir, "loadcfg_test.c")
2247 if err := os.WriteFile(src, []byte(`
2248 #ifdef _WIN64
2249 typedef unsigned long long uintptr;
2250 #else
2251 typedef unsigned long uintptr;
2252 #endif
2253 const uintptr _load_config_used[2] = { sizeof(_load_config_used), 0 };
2254 int main() { return 0; }
2255 `), 0666); err != nil {
2256 return false
2257 }
2258
2259 outPath := filepath.Join(*flagTmpdir, "loadcfg_test.exe")
2260 flags := hostlinkArchArgs(arch)
2261 flags = append(flags, "-o", outPath, src)
2262 cmd := exec.Command(linker, flags...)
2263 cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
2264 if err := cmd.Run(); err != nil {
2265 return false
2266 }
2267
2268 f, err := pe.Open(outPath)
2269 if err != nil {
2270 return false
2271 }
2272 defer f.Close()
2273
2274 switch oh := f.OptionalHeader.(type) {
2275 case *pe.OptionalHeader64:
2276 if int(pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) < len(oh.DataDirectory) {
2277 return oh.DataDirectory[pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress != 0
2278 }
2279 case *pe.OptionalHeader32:
2280 if int(pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) < len(oh.DataDirectory) {
2281 return oh.DataDirectory[pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress != 0
2282 }
2283 }
2284 return false
2285 }
2286
2287
2288
2289 func trimLinkerArgv(argv []string) []string {
2290 flagsWithNextArgSkip := []string{
2291 "-F",
2292 "-l",
2293 "-framework",
2294 "-Wl,-framework",
2295 "-Wl,-rpath",
2296 "-Wl,-undefined",
2297 }
2298 flagsWithNextArgKeep := []string{
2299 "-B",
2300 "-L",
2301 "-arch",
2302 "-isysroot",
2303 "--sysroot",
2304 "-target",
2305 "--target",
2306 "-resource-dir",
2307 "-rtlib",
2308 "--rtlib",
2309 "-stdlib",
2310 "--stdlib",
2311 "-unwindlib",
2312 "--unwindlib",
2313 }
2314 prefixesToKeep := []string{
2315 "-B",
2316 "-L",
2317 "-f",
2318 "-m",
2319 "-p",
2320 "-Wl,",
2321 "-arch",
2322 "-isysroot",
2323 "--sysroot",
2324 "-target",
2325 "--target",
2326 "-resource-dir",
2327 "-rtlib",
2328 "--rtlib",
2329 "-stdlib",
2330 "--stdlib",
2331 "-unwindlib",
2332 "--unwindlib",
2333 "-nostdlib++",
2334 "-nostdlib",
2335 "-nodefaultlibs",
2336 "-nostartfiles",
2337 "-nostdinc++",
2338 "-nostdinc",
2339 "-nobuiltininc",
2340 }
2341
2342 var flags []string
2343 keep := false
2344 skip := false
2345 for _, f := range argv {
2346 if keep {
2347 flags = append(flags, f)
2348 keep = false
2349 } else if skip {
2350 skip = false
2351 } else if f == "" || f[0] != '-' {
2352 } else if slices.Contains(flagsWithNextArgSkip, f) {
2353 skip = true
2354 } else if slices.Contains(flagsWithNextArgKeep, f) {
2355 flags = append(flags, f)
2356 keep = true
2357 } else {
2358 for _, p := range prefixesToKeep {
2359 if strings.HasPrefix(f, p) {
2360 flags = append(flags, f)
2361 break
2362 }
2363 }
2364 }
2365 }
2366 return flags
2367 }
2368
2369
2370
2371 func hostlinkArchArgs(arch *sys.Arch) []string {
2372 switch arch.Family {
2373 case sys.I386:
2374 return []string{"-m32"}
2375 case sys.AMD64:
2376 if buildcfg.GOOS == "darwin" {
2377 return []string{"-arch", "x86_64", "-m64"}
2378 }
2379 return []string{"-m64"}
2380 case sys.S390X:
2381 return []string{"-m64"}
2382 case sys.ARM:
2383 return []string{"-marm"}
2384 case sys.ARM64:
2385 if buildcfg.GOOS == "darwin" {
2386 return []string{"-arch", "arm64"}
2387 }
2388 case sys.Loong64:
2389 return []string{"-mabi=lp64d"}
2390 case sys.MIPS64:
2391 return []string{"-mabi=64"}
2392 case sys.MIPS:
2393 return []string{"-mabi=32"}
2394 case sys.PPC64:
2395 if buildcfg.GOOS == "aix" {
2396 return []string{"-maix64"}
2397 } else {
2398 return []string{"-m64"}
2399 }
2400
2401 }
2402 return nil
2403 }
2404
2405 var wantHdr = objabi.HeaderString()
2406
2407
2408
2409
2410 func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, file string) *Hostobj {
2411 pkg := objabi.PathToPrefix(lib.Pkg)
2412
2413 eof := f.Offset() + length
2414 start := f.Offset()
2415 c1 := bgetc(f)
2416 c2 := bgetc(f)
2417 c3 := bgetc(f)
2418 c4 := bgetc(f)
2419 f.MustSeek(start, 0)
2420
2421 unit := &sym.CompilationUnit{Lib: lib}
2422 lib.Units = append(lib.Units, unit)
2423
2424 magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
2425 if magic == 0x7f454c46 {
2426 ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2427 textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.Flags)
2428 if err != nil {
2429 Errorf("%v", err)
2430 return
2431 }
2432 ehdr.Flags = flags
2433 ctxt.Textp = append(ctxt.Textp, textp...)
2434 }
2435 return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
2436 }
2437
2438 if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
2439 ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2440 textp, err := loadmacho.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2441 if err != nil {
2442 Errorf("%v", err)
2443 return
2444 }
2445 ctxt.Textp = append(ctxt.Textp, textp...)
2446 }
2447 return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
2448 }
2449
2450 switch c1<<8 | c2 {
2451 case 0x4c01,
2452 0x6486,
2453 0xc401,
2454 0x64aa:
2455 ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2456 ls, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2457 if err != nil {
2458 Errorf("%v", err)
2459 return
2460 }
2461 if len(ls.Resources) != 0 {
2462 setpersrc(ctxt, ls.Resources)
2463 }
2464 sehp.pdata = append(sehp.pdata, ls.PData...)
2465 if ls.XData != 0 {
2466 sehp.xdata = append(sehp.xdata, ls.XData)
2467 }
2468 ctxt.Textp = append(ctxt.Textp, ls.Textp...)
2469 }
2470 return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
2471 }
2472
2473 if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
2474 ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2475 textp, err := loadxcoff.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2476 if err != nil {
2477 Errorf("%v", err)
2478 return
2479 }
2480 ctxt.Textp = append(ctxt.Textp, textp...)
2481 }
2482 return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
2483 }
2484
2485 if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' {
2486
2487
2488
2489 unknownObjFormat = true
2490 return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file)
2491 }
2492
2493
2494 line, err := f.ReadString('\n')
2495 if err != nil {
2496 Errorf("truncated object file: %s: %v", pn, err)
2497 return nil
2498 }
2499
2500 if !strings.HasPrefix(line, "go object ") {
2501 if strings.HasSuffix(pn, ".go") {
2502 Exitf("%s: uncompiled .go source file", pn)
2503 return nil
2504 }
2505
2506 if line == ctxt.Arch.Name {
2507
2508 Errorf("%s: stale object file", pn)
2509 return nil
2510 }
2511
2512 Errorf("%s: not an object file: @%d %q", pn, start, line)
2513 return nil
2514 }
2515
2516
2517 if line != wantHdr {
2518 Errorf("%s: linked object header mismatch:\nhave %q\nwant %q\n", pn, line, wantHdr)
2519 }
2520
2521
2522
2523
2524
2525
2526
2527
2528 import0 := f.Offset()
2529
2530 c1 = '\n'
2531 c2 = bgetc(f)
2532 c3 = bgetc(f)
2533 markers := 0
2534 for {
2535 if c1 == '\n' {
2536 if markers%2 == 0 && c2 == '!' && c3 == '\n' {
2537 break
2538 }
2539 if c2 == '$' && c3 == '$' {
2540 markers++
2541 }
2542 }
2543
2544 c1 = c2
2545 c2 = c3
2546 c3 = bgetc(f)
2547 if c3 == -1 {
2548 Errorf("truncated object file: %s", pn)
2549 return nil
2550 }
2551 }
2552
2553 import1 := f.Offset()
2554
2555 f.MustSeek(import0, 0)
2556 ldpkg(ctxt, f, lib, import1-import0-2, pn)
2557 f.MustSeek(import1, 0)
2558
2559 fingerprint := ctxt.loader.Preload(ctxt.IncVersion(), f, lib, unit, eof-f.Offset())
2560 if !fingerprint.IsZero() {
2561
2562
2563
2564
2565
2566 if lib.Fingerprint.IsZero() {
2567 lib.Fingerprint = fingerprint
2568 }
2569 checkFingerprint(lib, fingerprint, lib.Srcref, lib.Fingerprint)
2570 }
2571
2572 addImports(ctxt, lib, pn)
2573 return nil
2574 }
2575
2576
2577
2578
2579
2580 func symbolsAreUnresolved(ctxt *Link, want []string) []bool {
2581 returnAllUndefs := -1
2582 undefs, _ := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
2583 seen := make(map[loader.Sym]struct{})
2584 rval := make([]bool, len(want))
2585 wantm := make(map[string]int)
2586 for k, w := range want {
2587 wantm[w] = k
2588 }
2589 count := 0
2590 for _, s := range undefs {
2591 if _, ok := seen[s]; ok {
2592 continue
2593 }
2594 seen[s] = struct{}{}
2595 if k, ok := wantm[ctxt.loader.SymName(s)]; ok {
2596 rval[k] = true
2597 count++
2598 if count == len(want) {
2599 return rval
2600 }
2601 }
2602 }
2603 return rval
2604 }
2605
2606
2607
2608
2609 func hostObject(ctxt *Link, objname string, path string) {
2610 if ctxt.Debugvlog > 1 {
2611 ctxt.Logf("hostObject(%s)\n", path)
2612 }
2613 objlib := sym.Library{
2614 Pkg: objname,
2615 }
2616 f, err := bio.Open(path)
2617 if err != nil {
2618 Exitf("cannot open host object %q file %s: %v", objname, path, err)
2619 }
2620 defer f.Close()
2621 h := ldobj(ctxt, f, &objlib, 0, path, path)
2622 if h.ld == nil {
2623 Exitf("unrecognized object file format in %s", path)
2624 }
2625 h.file = path
2626 h.length = f.MustSeek(0, 2)
2627 f.MustSeek(h.off, 0)
2628 h.ld(ctxt, f, h.pkg, h.length, h.pn)
2629 if *flagCaptureHostObjs != "" {
2630 captureHostObj(h)
2631 }
2632 }
2633
2634 func checkFingerprint(lib *sym.Library, libfp goobj.FingerprintType, src string, srcfp goobj.FingerprintType) {
2635 if libfp != srcfp {
2636 Exitf("fingerprint mismatch: %s has %x, import from %s expecting %x", lib, libfp, src, srcfp)
2637 }
2638 }
2639
2640 func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
2641 data := make([]byte, sym.Size)
2642 sect := f.Sections[sym.Section]
2643 if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
2644 Errorf("reading %s from non-data section", sym.Name)
2645 }
2646 n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
2647 if uint64(n) != sym.Size {
2648 Errorf("reading contents of %s: %v", sym.Name, err)
2649 }
2650 return data
2651 }
2652
2653 func readwithpad(r io.Reader, sz int32) ([]byte, error) {
2654 data := make([]byte, Rnd(int64(sz), 4))
2655 _, err := io.ReadFull(r, data)
2656 if err != nil {
2657 return nil, err
2658 }
2659 data = data[:sz]
2660 return data, nil
2661 }
2662
2663 func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
2664 for _, sect := range f.Sections {
2665 if sect.Type != elf.SHT_NOTE {
2666 continue
2667 }
2668 r := sect.Open()
2669 for {
2670 var namesize, descsize, noteType int32
2671 err := binary.Read(r, f.ByteOrder, &namesize)
2672 if err != nil {
2673 if err == io.EOF {
2674 break
2675 }
2676 return nil, fmt.Errorf("read namesize failed: %v", err)
2677 }
2678 err = binary.Read(r, f.ByteOrder, &descsize)
2679 if err != nil {
2680 return nil, fmt.Errorf("read descsize failed: %v", err)
2681 }
2682 err = binary.Read(r, f.ByteOrder, ¬eType)
2683 if err != nil {
2684 return nil, fmt.Errorf("read type failed: %v", err)
2685 }
2686 noteName, err := readwithpad(r, namesize)
2687 if err != nil {
2688 return nil, fmt.Errorf("read name failed: %v", err)
2689 }
2690 desc, err := readwithpad(r, descsize)
2691 if err != nil {
2692 return nil, fmt.Errorf("read desc failed: %v", err)
2693 }
2694 if string(name) == string(noteName) && typ == noteType {
2695 return desc, nil
2696 }
2697 }
2698 }
2699 return nil, nil
2700 }
2701
2702 func findshlib(ctxt *Link, shlib string) string {
2703 if filepath.IsAbs(shlib) {
2704 return shlib
2705 }
2706 for _, libdir := range ctxt.Libdir {
2707 libpath := filepath.Join(libdir, shlib)
2708 if _, err := os.Stat(libpath); err == nil {
2709 return libpath
2710 }
2711 }
2712 Errorf("cannot find shared library: %s", shlib)
2713 return ""
2714 }
2715
2716 func ldshlibsyms(ctxt *Link, shlib string) {
2717 var libpath string
2718 if filepath.IsAbs(shlib) {
2719 libpath = shlib
2720 shlib = filepath.Base(shlib)
2721 } else {
2722 libpath = findshlib(ctxt, shlib)
2723 if libpath == "" {
2724 return
2725 }
2726 }
2727 for _, processedlib := range ctxt.Shlibs {
2728 if processedlib.Path == libpath {
2729 return
2730 }
2731 }
2732 if ctxt.Debugvlog > 1 {
2733 ctxt.Logf("ldshlibsyms: found library with name %s at %s\n", shlib, libpath)
2734 }
2735
2736 f, err := elf.Open(libpath)
2737 if err != nil {
2738 Errorf("cannot open shared library: %s", libpath)
2739 return
2740 }
2741
2742
2743
2744
2745 hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
2746 if err != nil {
2747 Errorf("cannot read ABI hash from shared library %s: %v", libpath, err)
2748 return
2749 }
2750
2751 depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
2752 if err != nil {
2753 Errorf("cannot read dep list from shared library %s: %v", libpath, err)
2754 return
2755 }
2756 var deps []string
2757 for _, dep := range strings.Split(string(depsbytes), "\n") {
2758 if dep == "" {
2759 continue
2760 }
2761 if !filepath.IsAbs(dep) {
2762
2763
2764
2765 abs := filepath.Join(filepath.Dir(libpath), dep)
2766 if _, err := os.Stat(abs); err == nil {
2767 dep = abs
2768 }
2769 }
2770 deps = append(deps, dep)
2771 }
2772
2773 syms, err := f.DynamicSymbols()
2774 if err != nil {
2775 Errorf("cannot read symbols from shared library: %s", libpath)
2776 return
2777 }
2778
2779 symAddr := map[string]uint64{}
2780 for _, elfsym := range syms {
2781 if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
2782 continue
2783 }
2784
2785
2786
2787 ver := 0
2788 symname := elfsym.Name
2789 if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && strings.HasPrefix(elfsym.Name, "type:") {
2790 ver = abiInternalVer
2791 } else if buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC {
2792
2793 if strings.HasSuffix(elfsym.Name, ".abiinternal") {
2794 ver = sym.SymVerABIInternal
2795 symname = strings.TrimSuffix(elfsym.Name, ".abiinternal")
2796 } else if strings.HasSuffix(elfsym.Name, ".abi0") {
2797 ver = 0
2798 symname = strings.TrimSuffix(elfsym.Name, ".abi0")
2799 }
2800 }
2801
2802 l := ctxt.loader
2803 s := l.LookupOrCreateSym(symname, ver)
2804
2805
2806
2807
2808
2809 if l.SymType(s) != 0 && l.SymType(s) != sym.SDYNIMPORT {
2810 continue
2811 }
2812 su := l.MakeSymbolUpdater(s)
2813 su.SetType(sym.SDYNIMPORT)
2814 l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
2815 su.SetSize(int64(elfsym.Size))
2816 if elfsym.Section != elf.SHN_UNDEF {
2817
2818 l.SetSymPkg(s, libpath)
2819
2820
2821
2822 sname := l.SymName(s)
2823 if strings.HasPrefix(sname, "type:") && !strings.HasPrefix(sname, "type:.") {
2824 su.SetData(readelfsymboldata(ctxt, f, &elfsym))
2825 }
2826 }
2827
2828 if symname != elfsym.Name {
2829 l.SetSymExtname(s, elfsym.Name)
2830 }
2831 symAddr[elfsym.Name] = elfsym.Value
2832 }
2833
2834
2835
2836
2837 relocTarget := map[uint64]string{}
2838 addends := false
2839 sect := f.SectionByType(elf.SHT_REL)
2840 if sect == nil {
2841 sect = f.SectionByType(elf.SHT_RELA)
2842 if sect == nil {
2843 log.Fatalf("can't find SHT_REL or SHT_RELA section of %s", shlib)
2844 }
2845 addends = true
2846 }
2847
2848 data, err := sect.Data()
2849 if err != nil {
2850 log.Fatalf("can't read relocation section of %s: %v", shlib, err)
2851 }
2852 bo := f.ByteOrder
2853 for len(data) > 0 {
2854 var off, idx uint64
2855 var addend int64
2856 switch f.Class {
2857 case elf.ELFCLASS64:
2858 off = bo.Uint64(data)
2859 info := bo.Uint64(data[8:])
2860 data = data[16:]
2861 if addends {
2862 addend = int64(bo.Uint64(data))
2863 data = data[8:]
2864 }
2865
2866 idx = info >> 32
2867 typ := info & 0xffff
2868
2869
2870 switch typ {
2871 case uint64(elf.R_X86_64_64):
2872 case uint64(elf.R_AARCH64_ABS64):
2873 case uint64(elf.R_LARCH_64):
2874 case uint64(elf.R_390_64):
2875 case uint64(elf.R_PPC64_ADDR64):
2876 default:
2877 continue
2878 }
2879 case elf.ELFCLASS32:
2880 off = uint64(bo.Uint32(data))
2881 info := bo.Uint32(data[4:])
2882 data = data[8:]
2883 if addends {
2884 addend = int64(int32(bo.Uint32(data)))
2885 data = data[4:]
2886 }
2887
2888 idx = uint64(info >> 8)
2889 typ := info & 0xff
2890
2891 switch typ {
2892 case uint32(elf.R_386_32):
2893 case uint32(elf.R_ARM_ABS32):
2894 default:
2895 continue
2896 }
2897 default:
2898 log.Fatalf("unknown bit size %s", f.Class)
2899 }
2900 if addend != 0 {
2901 continue
2902 }
2903 relocTarget[off] = syms[idx-1].Name
2904 }
2905
2906 ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, symAddr: symAddr, relocTarget: relocTarget})
2907 }
2908
2909 func addsection(ldr *loader.Loader, arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
2910 sect := ldr.NewSection()
2911 sect.Rwx = uint8(rwx)
2912 sect.Name = name
2913 sect.Seg = seg
2914 sect.Align = int32(arch.PtrSize)
2915 seg.Sections = append(seg.Sections, sect)
2916 return sect
2917 }
2918
2919 func usage() {
2920 fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
2921 objabi.Flagprint(os.Stderr)
2922 Exit(2)
2923 }
2924
2925 type SymbolType int8
2926
2927 const (
2928
2929 TextSym SymbolType = 'T'
2930 DataSym SymbolType = 'D'
2931 BSSSym SymbolType = 'B'
2932 UndefinedSym SymbolType = 'U'
2933 TLSSym SymbolType = 't'
2934 FrameSym SymbolType = 'm'
2935 ParamSym SymbolType = 'p'
2936 AutoSym SymbolType = 'a'
2937
2938
2939 DeletedAutoSym = 'x'
2940 )
2941
2942
2943 func (ctxt *Link) defineInternal(p string, t sym.SymKind) loader.Sym {
2944 s := ctxt.loader.CreateSymForUpdate(p, 0)
2945 s.SetType(t)
2946 s.SetSpecial(true)
2947 s.SetLocal(true)
2948 return s.Sym()
2949 }
2950
2951 func (ctxt *Link) xdefine(p string, t sym.SymKind, v int64) loader.Sym {
2952 s := ctxt.defineInternal(p, t)
2953 ctxt.loader.SetSymValue(s, v)
2954 return s
2955 }
2956
2957 func datoff(ldr *loader.Loader, s loader.Sym, addr int64) int64 {
2958 if uint64(addr) >= Segdata.Vaddr {
2959 return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
2960 }
2961 if uint64(addr) >= Segtext.Vaddr {
2962 return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
2963 }
2964 ldr.Errorf(s, "invalid datoff %#x", addr)
2965 return 0
2966 }
2967
2968 func Entryvalue(ctxt *Link) int64 {
2969 a := *flagEntrySymbol
2970 if a[0] >= '0' && a[0] <= '9' {
2971 return atolwhex(a)
2972 }
2973 ldr := ctxt.loader
2974 s := ldr.Lookup(a, 0)
2975 if s == 0 {
2976 Errorf("missing entry symbol %q", a)
2977 return 0
2978 }
2979 st := ldr.SymType(s)
2980 if st == 0 {
2981 return *FlagTextAddr
2982 }
2983 if !ctxt.IsAIX() && !st.IsText() {
2984 ldr.Errorf(s, "entry not text")
2985 }
2986 return ldr.SymValue(s)
2987 }
2988
2989 func (ctxt *Link) callgraph() {
2990 if !*FlagC {
2991 return
2992 }
2993
2994 ldr := ctxt.loader
2995 for _, s := range ctxt.Textp {
2996 relocs := ldr.Relocs(s)
2997 for i := 0; i < relocs.Count(); i++ {
2998 r := relocs.At(i)
2999 rs := r.Sym()
3000 if rs == 0 {
3001 continue
3002 }
3003 if r.Type().IsDirectCall() && ldr.SymType(rs).IsText() {
3004 ctxt.Logf("%s calls %s\n", ldr.SymName(s), ldr.SymName(rs))
3005 }
3006 }
3007 }
3008 }
3009
3010 func Rnd(v int64, r int64) int64 {
3011 if r <= 0 {
3012 return v
3013 }
3014 v += r - 1
3015 c := v % r
3016 if c < 0 {
3017 c += r
3018 }
3019 v -= c
3020 return v
3021 }
3022
3023 func bgetc(r *bio.Reader) int {
3024 c, err := r.ReadByte()
3025 if err != nil {
3026 if err != io.EOF {
3027 log.Fatalf("reading input: %v", err)
3028 }
3029 return -1
3030 }
3031 return int(c)
3032 }
3033
3034 type markKind uint8
3035 const (
3036 _ markKind = iota
3037 visiting
3038 visited
3039 )
3040
3041 func postorder(libs []*sym.Library) []*sym.Library {
3042 order := make([]*sym.Library, 0, len(libs))
3043 mark := make(map[*sym.Library]markKind, len(libs))
3044 for _, lib := range libs {
3045 dfs(lib, mark, &order)
3046 }
3047 return order
3048 }
3049
3050 func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library) {
3051 if mark[lib] == visited {
3052 return
3053 }
3054 if mark[lib] == visiting {
3055 panic("found import cycle while visiting " + lib.Pkg)
3056 }
3057 mark[lib] = visiting
3058 for _, i := range lib.Imports {
3059 dfs(i, mark, order)
3060 }
3061 mark[lib] = visited
3062 *order = append(*order, lib)
3063 }
3064
3065 func ElfSymForReloc(ctxt *Link, s loader.Sym) int32 {
3066
3067
3068 les := ctxt.loader.SymLocalElfSym(s)
3069 if les != 0 {
3070 return les
3071 } else {
3072 return ctxt.loader.SymElfSym(s)
3073 }
3074 }
3075
3076 func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, elfRelocTyp uint32) {
3077 if ldr.SymGot(s) >= 0 {
3078 return
3079 }
3080
3081 Adddynsym(ldr, target, syms, s)
3082 got := ldr.MakeSymbolUpdater(syms.GOT)
3083 ldr.SetGot(s, int32(got.Size()))
3084 got.AddUint(target.Arch, 0)
3085
3086 if target.IsElf() {
3087 if target.Arch.PtrSize == 8 {
3088 rela := ldr.MakeSymbolUpdater(syms.Rela)
3089 rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
3090 rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
3091 rela.AddUint64(target.Arch, 0)
3092 } else {
3093 rel := ldr.MakeSymbolUpdater(syms.Rel)
3094 rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
3095 rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), elfRelocTyp))
3096 }
3097 } else if target.IsDarwin() {
3098 leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
3099 leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
3100 if target.IsPIE() && target.IsInternal() {
3101
3102
3103
3104 MachoAddBind(syms.GOT, int64(ldr.SymGot(s)), s)
3105 }
3106 } else {
3107 ldr.Errorf(s, "addgotsym: unsupported binary format")
3108 }
3109 }
3110
3111 var hostobjcounter int
3112
3113
3114
3115
3116
3117
3118 func captureHostObj(h *Hostobj) {
3119
3120 ofile := fmt.Sprintf("captured-obj-%d.o", hostobjcounter)
3121 ifile := fmt.Sprintf("captured-obj-%d.txt", hostobjcounter)
3122 hostobjcounter++
3123 opath := filepath.Join(*flagCaptureHostObjs, ofile)
3124 ipath := filepath.Join(*flagCaptureHostObjs, ifile)
3125
3126
3127 info := fmt.Sprintf("pkg: %s\npn: %s\nfile: %s\noff: %d\nlen: %d\n",
3128 h.pkg, h.pn, h.file, h.off, h.length)
3129 if err := os.WriteFile(ipath, []byte(info), 0666); err != nil {
3130 log.Fatalf("error writing captured host obj info %s: %v", ipath, err)
3131 }
3132
3133 readObjData := func() []byte {
3134 inf, err := os.Open(h.file)
3135 if err != nil {
3136 log.Fatalf("capturing host obj: open failed on %s: %v", h.pn, err)
3137 }
3138 defer inf.Close()
3139 res := make([]byte, h.length)
3140 if n, err := inf.ReadAt(res, h.off); err != nil || n != int(h.length) {
3141 log.Fatalf("capturing host obj: readat failed on %s: %v", h.pn, err)
3142 }
3143 return res
3144 }
3145
3146
3147 if err := os.WriteFile(opath, readObjData(), 0666); err != nil {
3148 log.Fatalf("error writing captured host object %s: %v", opath, err)
3149 }
3150
3151 fmt.Fprintf(os.Stderr, "link: info: captured host object %s to %s\n",
3152 h.file, opath)
3153 }
3154
3155
3156
3157
3158 func (ctxt *Link) findExtLinkTool(toolname string) string {
3159 var cc []string
3160 cc = append(cc, ctxt.extld()...)
3161 cc = append(cc, hostlinkArchArgs(ctxt.Arch)...)
3162 cc = append(cc, "--print-prog-name", toolname)
3163 out, err := exec.Command(cc[0], cc[1:]...).CombinedOutput()
3164 if err != nil {
3165 Exitf("%s: finding %s failed: %v\n%s", os.Args[0], toolname, err, out)
3166 }
3167 cmdpath := strings.TrimRight(string(out), "\r\n")
3168 return cmdpath
3169 }
3170
3171
3172
3173 func (ctxt *Link) isMSVC() bool {
3174 extld := ctxt.extld()
3175 name, args := extld[0], extld[1:]
3176 args = append(args, trimLinkerArgv(flagExtldflags)...)
3177 args = append(args, "--version")
3178 cmd := exec.Command(name, args...)
3179 if out, err := cmd.CombinedOutput(); err == nil {
3180 if bytes.Contains(out, []byte("-msvc\n")) || bytes.Contains(out, []byte("-msvc\r")) {
3181 return true
3182 }
3183 }
3184 return false
3185 }
3186
3187
3188 func (ctxt *Link) isLLD() bool {
3189 extld := ctxt.extld()
3190 name, args := extld[0], extld[1:]
3191 args = append(args, trimLinkerArgv(flagExtldflags)...)
3192 args = append(args, "-Wl,--version")
3193 cmd := exec.Command(name, args...)
3194 if out, err := cmd.CombinedOutput(); err == nil {
3195 if bytes.Contains(out, []byte("LLD ")) {
3196 return true
3197 }
3198 }
3199 return false
3200 }
3201
View as plain text