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