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 if ctxt.IsWindows() && ctxt.IsExternal() {
873 ctxt.loader.SetAttrNotInSymbolTable(tlsg, false)
874 tlsOffset := ctxt.loader.Lookup("runtime.tls_g", 0)
875 if tlsOffset == 0 {
876 Errorf("missing runtime.tls_g")
877 } else {
878 rel, _ := ctxt.loader.MakeSymbolUpdater(tlsOffset).AddRel(objabi.R_ADDROFF)
879 rel.SetOff(0)
880 rel.SetSiz(4)
881 rel.SetSym(tlsg)
882 }
883 }
884 }
885
886 var moduledata loader.Sym
887 var mdsb *loader.SymbolBuilder
888 if ctxt.BuildMode == BuildModePlugin {
889 moduledata = ctxt.loader.LookupOrCreateSym("local.pluginmoduledata", 0)
890 mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
891 ctxt.loader.SetAttrLocal(moduledata, true)
892 } else {
893 moduledata = ctxt.loader.LookupOrCreateSym("runtime.firstmoduledata", 0)
894 mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
895 }
896 if mdsb.Type() != 0 && mdsb.Type() != sym.SDYNIMPORT {
897
898
899
900
901
902 mdsb.SetSize(0)
903
904
905
906 if ctxt.Arch.Family == sys.ARM {
907 goarm := ctxt.loader.LookupOrCreateSym("runtime.goarm", 0)
908 sb := ctxt.loader.MakeSymbolUpdater(goarm)
909 sb.SetType(sym.SNOPTRDATA)
910 sb.SetSize(0)
911 sb.AddUint8(uint8(buildcfg.GOARM.Version))
912
913 goarmsoftfp := ctxt.loader.LookupOrCreateSym("runtime.goarmsoftfp", 0)
914 sb2 := ctxt.loader.MakeSymbolUpdater(goarmsoftfp)
915 sb2.SetType(sym.SNOPTRDATA)
916 sb2.SetSize(0)
917 if buildcfg.GOARM.SoftFloat {
918 sb2.AddUint8(1)
919 } else {
920 sb2.AddUint8(0)
921 }
922 }
923
924
925
926
927 memProfile := ctxt.loader.Lookup("runtime.memProfileInternal", abiInternalVer)
928 if memProfile != 0 && !ctxt.loader.AttrReachable(memProfile) && !ctxt.DynlinkingGo() {
929 memProfSym := ctxt.loader.LookupOrCreateSym("runtime.disableMemoryProfiling", 0)
930 sb := ctxt.loader.MakeSymbolUpdater(memProfSym)
931 sb.SetType(sym.SNOPTRDATA)
932 sb.SetSize(0)
933 sb.AddUint8(1)
934 }
935 } else {
936
937
938 moduledata = ctxt.loader.LookupOrCreateSym("local.moduledata", 0)
939 mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
940 ctxt.loader.SetAttrLocal(moduledata, true)
941 }
942 mdsb.SetType(sym.SMODULEDATA)
943 ctxt.loader.SetAttrReachable(moduledata, true)
944 ctxt.Moduledata = moduledata
945
946 if ctxt.Arch == sys.Arch386 && ctxt.HeadType != objabi.Hwindows {
947 if (ctxt.BuildMode == BuildModeCArchive && ctxt.IsELF) || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE || ctxt.DynlinkingGo() {
948 got := ctxt.loader.LookupOrCreateSym("_GLOBAL_OFFSET_TABLE_", 0)
949 sb := ctxt.loader.MakeSymbolUpdater(got)
950 sb.SetType(sym.SDYNIMPORT)
951 ctxt.loader.SetAttrReachable(got, true)
952 }
953 }
954
955
956
957
958
959
960
961 ctxt.Library = postorder(ctxt.Library)
962 intlibs := []bool{}
963 for _, lib := range ctxt.Library {
964 intlibs = append(intlibs, isRuntimeDepPkg(lib.Pkg))
965 }
966 ctxt.Textp = ctxt.loader.AssignTextSymbolOrder(ctxt.Library, intlibs, ctxt.Textp)
967 }
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982 func (ctxt *Link) mangleTypeSym() {
983 if ctxt.BuildMode != BuildModeShared && !ctxt.linkShared && ctxt.BuildMode != BuildModePlugin && !ctxt.CanUsePlugins() {
984 return
985 }
986
987 ldr := ctxt.loader
988 for s := loader.Sym(1); s < loader.Sym(ldr.NSym()); s++ {
989 if !ldr.AttrReachable(s) && !ctxt.linkShared {
990
991
992
993
994
995 continue
996 }
997 name := ldr.SymName(s)
998 newName := typeSymbolMangle(name)
999 if newName != name {
1000 ldr.SetSymExtname(s, newName)
1001
1002
1003
1004
1005
1006
1007 dup := ldr.Lookup(newName, ldr.SymVersion(s))
1008 if dup != 0 {
1009 st := ldr.SymType(s)
1010 dt := ldr.SymType(dup)
1011 if st == sym.Sxxx && dt != sym.Sxxx {
1012 ldr.CopySym(dup, s)
1013 }
1014 }
1015 }
1016 }
1017 }
1018
1019
1020
1021
1022
1023
1024
1025 func typeSymbolMangle(name string) string {
1026 isType := strings.HasPrefix(name, "type:")
1027 if !isType && !strings.Contains(name, "@") {
1028
1029 return name
1030 }
1031 if strings.HasPrefix(name, "type:runtime.") {
1032 return name
1033 }
1034 if strings.HasPrefix(name, "go:string.") {
1035
1036
1037 return name
1038 }
1039 if len(name) <= 14 && !strings.Contains(name, "@") {
1040 return name
1041 }
1042 if isType {
1043 hb := hash.Sum32([]byte(name[5:]))
1044 prefix := "type:"
1045 if name[5] == '.' {
1046 prefix = "type:."
1047 }
1048 return prefix + base64.StdEncoding.EncodeToString(hb[:6])
1049 }
1050
1051 i := strings.IndexByte(name, '[')
1052 j := strings.LastIndexByte(name, ']')
1053 if j == -1 || j <= i {
1054 j = len(name)
1055 }
1056 hb := hash.Sum32([]byte(name[i+1 : j]))
1057 return name[:i+1] + base64.StdEncoding.EncodeToString(hb[:6]) + name[j:]
1058 }
1059
1060
1064 func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 {
1065 if off&1 != 0 {
1066 off++
1067 }
1068 bp.MustSeek(off, 0)
1069 var buf [SAR_HDR]byte
1070 if n, err := io.ReadFull(bp, buf[:]); err != nil {
1071 if n == 0 && err != io.EOF {
1072 return -1
1073 }
1074 return 0
1075 }
1076
1077 a.name = artrim(buf[0:16])
1078 a.date = artrim(buf[16:28])
1079 a.uid = artrim(buf[28:34])
1080 a.gid = artrim(buf[34:40])
1081 a.mode = artrim(buf[40:48])
1082 a.size = artrim(buf[48:58])
1083 a.fmag = artrim(buf[58:60])
1084
1085 arsize := atolwhex(a.size)
1086 if arsize&1 != 0 {
1087 arsize++
1088 }
1089 return arsize + SAR_HDR
1090 }
1091
1092 func loadobjfile(ctxt *Link, lib *sym.Library) {
1093 pkg := objabi.PathToPrefix(lib.Pkg)
1094
1095 if ctxt.Debugvlog > 1 {
1096 ctxt.Logf("ldobj: %s (%s)\n", lib.File, pkg)
1097 }
1098 f, err := bio.Open(lib.File)
1099 if err != nil {
1100 Exitf("cannot open file %s: %v", lib.File, err)
1101 }
1102 defer f.Close()
1103 defer func() {
1104 if pkg == "main" && !lib.Main {
1105 Exitf("%s: not package main", lib.File)
1106 }
1107 }()
1108
1109 for i := 0; i < len(ARMAG); i++ {
1110 if c, err := f.ReadByte(); err == nil && c == ARMAG[i] {
1111 continue
1112 }
1113
1114
1115 l := f.MustSeek(0, 2)
1116 f.MustSeek(0, 0)
1117 ldobj(ctxt, f, lib, l, lib.File, lib.File)
1118 return
1119 }
1120
1121
1133 var arhdr ArHdr
1134 off := f.Offset()
1135 for {
1136 l := nextar(f, off, &arhdr)
1137 if l == 0 {
1138 break
1139 }
1140 if l < 0 {
1141 Exitf("%s: malformed archive", lib.File)
1142 }
1143 off += l
1144
1145
1146
1147
1148
1149 if arhdr.name == pkgdef {
1150 continue
1151 }
1152
1153 if arhdr.name == "dynimportfail" {
1154 dynimportfail = append(dynimportfail, lib.Pkg)
1155 }
1156 if arhdr.name == "preferlinkext" {
1157
1158
1159 if ctxt.LinkMode == LinkAuto {
1160 preferlinkext = append(preferlinkext, lib.Pkg)
1161 }
1162 }
1163
1164
1165
1166
1167 if len(arhdr.name) < 16 {
1168 if ext := filepath.Ext(arhdr.name); ext != ".o" && ext != ".syso" {
1169 continue
1170 }
1171 }
1172
1173 pname := fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
1174 l = atolwhex(arhdr.size)
1175 ldobj(ctxt, f, lib, l, pname, lib.File)
1176 }
1177 }
1178
1179 type Hostobj struct {
1180 ld func(*Link, *bio.Reader, string, int64, string)
1181 pkg string
1182 pn string
1183 file string
1184 off int64
1185 length int64
1186 }
1187
1188 var hostobj []Hostobj
1189
1190
1191
1192 var internalpkg = []string{
1193 "crypto/internal/boring",
1194 "crypto/internal/boring/syso",
1195 "crypto/x509",
1196 "net",
1197 "os/user",
1198 "runtime/cgo",
1199 "runtime/race",
1200 "runtime/race/internal/amd64v1",
1201 "runtime/race/internal/amd64v3",
1202 "runtime/msan",
1203 "runtime/asan",
1204 }
1205
1206 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 {
1207 isinternal := false
1208 for _, intpkg := range internalpkg {
1209 if pkg == intpkg {
1210 isinternal = true
1211 break
1212 }
1213 }
1214
1215
1216
1217
1218
1219
1220
1221 if headType == objabi.Hdragonfly {
1222 if pkg == "net" || pkg == "os/user" {
1223 isinternal = false
1224 }
1225 }
1226
1227 if !isinternal {
1228 externalobj = true
1229 }
1230
1231 hostobj = append(hostobj, Hostobj{})
1232 h := &hostobj[len(hostobj)-1]
1233 h.ld = ld
1234 h.pkg = pkg
1235 h.pn = pn
1236 h.file = file
1237 h.off = f.Offset()
1238 h.length = length
1239 return h
1240 }
1241
1242 func hostobjs(ctxt *Link) {
1243 if ctxt.LinkMode != LinkInternal {
1244 return
1245 }
1246 var h *Hostobj
1247
1248 for i := 0; i < len(hostobj); i++ {
1249 h = &hostobj[i]
1250 f, err := bio.Open(h.file)
1251 if err != nil {
1252 Exitf("cannot reopen %s: %v", h.pn, err)
1253 }
1254 f.MustSeek(h.off, 0)
1255 if h.ld == nil {
1256 Errorf("%s: unrecognized object file format", h.pn)
1257 continue
1258 }
1259 h.ld(ctxt, f, h.pkg, h.length, h.pn)
1260 if *flagCaptureHostObjs != "" {
1261 captureHostObj(h)
1262 }
1263 f.Close()
1264 }
1265 }
1266
1267 func hostlinksetup(ctxt *Link) {
1268 if ctxt.LinkMode != LinkExternal {
1269 return
1270 }
1271
1272
1273
1274
1275 debug_s = *FlagS
1276 *FlagS = false
1277
1278
1279 if *flagTmpdir == "" {
1280 dir, err := os.MkdirTemp("", "go-link-")
1281 if err != nil {
1282 log.Fatal(err)
1283 }
1284 *flagTmpdir = dir
1285 ownTmpDir = true
1286 AtExit(func() {
1287 os.RemoveAll(*flagTmpdir)
1288 })
1289 }
1290
1291
1292 if err := ctxt.Out.Close(); err != nil {
1293 Exitf("error closing output file")
1294 }
1295 mayberemoveoutfile()
1296
1297 p := filepath.Join(*flagTmpdir, "go.o")
1298 if err := ctxt.Out.Open(p); err != nil {
1299 Exitf("cannot create %s: %v", p, err)
1300 }
1301 }
1302
1303
1304
1305
1306
1307
1308
1309
1310 func cleanTimeStamps(files []string) {
1311 epocht := time.Unix(0, 0)
1312 for _, f := range files {
1313 if err := os.Chtimes(f, epocht, epocht); err != nil {
1314 Exitf("cannot chtimes %s: %v", f, err)
1315 }
1316 }
1317 }
1318
1319
1320
1321 func (ctxt *Link) hostobjCopy() (paths []string) {
1322 var wg sync.WaitGroup
1323 sema := make(chan struct{}, runtime.NumCPU())
1324 for i, h := range hostobj {
1325 h := h
1326 dst := filepath.Join(*flagTmpdir, fmt.Sprintf("%06d.o", i))
1327 paths = append(paths, dst)
1328 if ctxt.Debugvlog != 0 {
1329 ctxt.Logf("host obj copy: %s from pkg %s -> %s\n", h.pn, h.pkg, dst)
1330 }
1331
1332 wg.Add(1)
1333 go func() {
1334 sema <- struct{}{}
1335 defer func() {
1336 <-sema
1337 wg.Done()
1338 }()
1339 f, err := os.Open(h.file)
1340 if err != nil {
1341 Exitf("cannot reopen %s: %v", h.pn, err)
1342 }
1343 defer f.Close()
1344 if _, err := f.Seek(h.off, 0); err != nil {
1345 Exitf("cannot seek %s: %v", h.pn, err)
1346 }
1347
1348 w, err := os.Create(dst)
1349 if err != nil {
1350 Exitf("cannot create %s: %v", dst, err)
1351 }
1352 if _, err := io.CopyN(w, f, h.length); err != nil {
1353 Exitf("cannot write %s: %v", dst, err)
1354 }
1355 if err := w.Close(); err != nil {
1356 Exitf("cannot close %s: %v", dst, err)
1357 }
1358 }()
1359 }
1360 wg.Wait()
1361 return paths
1362 }
1363
1364
1365
1366
1367
1368 func writeGDBLinkerScript() string {
1369 name := "fix_debug_gdb_scripts.ld"
1370 path := filepath.Join(*flagTmpdir, name)
1371 src := `SECTIONS
1372 {
1373 .debug_gdb_scripts BLOCK(__section_alignment__) (NOLOAD) :
1374 {
1375 *(.debug_gdb_scripts)
1376 }
1377 }
1378 INSERT AFTER .debug_types;
1379 `
1380 err := os.WriteFile(path, []byte(src), 0666)
1381 if err != nil {
1382 Errorf("WriteFile %s failed: %v", name, err)
1383 }
1384 return path
1385 }
1386
1387 type machoUpdateFunc func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error
1388
1389
1390 func (ctxt *Link) archive() {
1391 if ctxt.BuildMode != BuildModeCArchive {
1392 return
1393 }
1394
1395 exitIfErrors()
1396
1397 if *flagExtar == "" {
1398 const printProgName = "--print-prog-name=ar"
1399 cc := ctxt.extld()
1400 *flagExtar = "ar"
1401 if linkerFlagSupported(ctxt.Arch, cc[0], "", printProgName) {
1402 *flagExtar = ctxt.findExtLinkTool("ar")
1403 }
1404 }
1405
1406 mayberemoveoutfile()
1407
1408
1409
1410 if err := ctxt.Out.Close(); err != nil {
1411 Exitf("error closing %v", *flagOutfile)
1412 }
1413
1414 argv := []string{*flagExtar, "-q", "-c", "-s"}
1415 if ctxt.HeadType == objabi.Haix {
1416 argv = append(argv, "-X64")
1417 }
1418 godotopath := filepath.Join(*flagTmpdir, "go.o")
1419 cleanTimeStamps([]string{godotopath})
1420 hostObjCopyPaths := ctxt.hostobjCopy()
1421 cleanTimeStamps(hostObjCopyPaths)
1422
1423 argv = append(argv, *flagOutfile)
1424 argv = append(argv, godotopath)
1425 argv = append(argv, hostObjCopyPaths...)
1426
1427 if ctxt.Debugvlog != 0 {
1428 ctxt.Logf("archive: %s\n", strings.Join(argv, " "))
1429 }
1430
1431
1432
1433
1434
1435
1436 if syscallExecSupported && !ownTmpDir {
1437 runAtExitFuncs()
1438 ctxt.execArchive(argv)
1439 panic("should not get here")
1440 }
1441
1442
1443 if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
1444 Exitf("running %s failed: %v\n%s", argv[0], err, out)
1445 }
1446 }
1447
1448 func (ctxt *Link) hostlink() {
1449 if ctxt.LinkMode != LinkExternal || nerrors > 0 {
1450 return
1451 }
1452 if ctxt.BuildMode == BuildModeCArchive {
1453 return
1454 }
1455
1456 var argv []string
1457 argv = append(argv, ctxt.extld()...)
1458 argv = append(argv, hostlinkArchArgs(ctxt.Arch)...)
1459
1460 if *FlagS || debug_s {
1461 if ctxt.HeadType == objabi.Hdarwin {
1462
1463
1464
1465 } else {
1466 argv = append(argv, "-s")
1467 }
1468 } else if *FlagW {
1469 if !ctxt.IsAIX() && !ctxt.IsSolaris() {
1470 argv = append(argv, "-Wl,-S")
1471 }
1472 }
1473
1474
1475
1476 combineDwarf := ctxt.IsDarwin() && !*FlagW && machoPlatform == PLATFORM_MACOS
1477
1478 var isMSVC, isLLD bool
1479 wlPrefix := "-Wl,--"
1480
1481 switch ctxt.HeadType {
1482 case objabi.Hdarwin:
1483 if combineDwarf {
1484
1485
1486 argv = append(argv, "-Wl,-headerpad,1144")
1487 }
1488 if ctxt.DynlinkingGo() && buildcfg.GOOS != "ios" {
1489
1490
1491
1492
1493
1494 argv = append(argv, "-Wl,-flat_namespace", "-Wl,-bind_at_load")
1495 }
1496 if !combineDwarf {
1497 argv = append(argv, "-Wl,-S")
1498 if debug_s {
1499
1500
1501
1502 argv = append(argv, "-Wl,-x")
1503 }
1504 }
1505 if *flagRace {
1506
1507
1508
1509 argv = append(argv, "-Wl,-U,__dyld_get_dyld_header")
1510 }
1511 if *flagHostBuildid == "none" {
1512 argv = append(argv, "-Wl,-no_uuid")
1513 }
1514 case objabi.Hopenbsd:
1515 argv = append(argv, "-pthread")
1516 if ctxt.BuildMode != BuildModePIE {
1517 argv = append(argv, "-Wl,-nopie")
1518 }
1519 if linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,-z,nobtcfi") {
1520
1521
1522 argv = append(argv, "-Wl,-z,nobtcfi")
1523 }
1524 if ctxt.Arch.InFamily(sys.ARM64) {
1525
1526
1527
1528 argv = append(argv, "-Wl,--no-execute-only")
1529 }
1530 case objabi.Hwindows:
1531 isMSVC = ctxt.isMSVC()
1532 isLLD = ctxt.isLLD()
1533 if isMSVC {
1534
1535
1536
1537
1538 wlPrefix = "-Wl,-"
1539 }
1540
1541 if windowsgui {
1542 argv = append(argv, "-mwindows")
1543 } else {
1544 argv = append(argv, "-mconsole")
1545 }
1546
1547
1548
1549 argv = append(argv, wlPrefix+"tsaware")
1550
1551
1552 argv = append(argv, wlPrefix+"nxcompat")
1553
1554 if !isMSVC {
1555 peMajorVersion := PeMinimumTargetMajorVersion
1556 peMinorVersion := PeMinimumTargetMinorVersion
1557 if peMajorVersion >= 10 && !isLLD &&
1558 !peHasLoadConfigDirectorySupport(ctxt.Arch, argv[0]) {
1559
1560
1561
1562
1563
1564 peMajorVersion = 6
1565 peMinorVersion = 1
1566 }
1567 argv = append(argv, fmt.Sprintf("-Wl,--major-os-version=%d", peMajorVersion))
1568 argv = append(argv, fmt.Sprintf("-Wl,--minor-os-version=%d", peMinorVersion))
1569 argv = append(argv, fmt.Sprintf("-Wl,--major-subsystem-version=%d", peMajorVersion))
1570 argv = append(argv, fmt.Sprintf("-Wl,--minor-subsystem-version=%d", peMinorVersion))
1571 }
1572 case objabi.Haix:
1573 argv = append(argv, "-pthread")
1574
1575
1576 argv = append(argv, "-Wl,-bnoobjreorder")
1577
1578
1579 argv = append(argv, "-mcmodel=large")
1580 argv = append(argv, "-Wl,-bbigtoc")
1581 }
1582
1583
1584
1585
1586 if ctxt.IsPPC64() && ctxt.IsElf() && buildcfg.GOPPC64 >= 10 {
1587 if !linkerFlagSupported(ctxt.Arch, argv[0], "", "-mcpu=power10") {
1588 Exitf("The external toolchain does not support -mcpu=power10. " +
1589 " This is required to externally link GOPPC64 >= power10")
1590 }
1591 }
1592
1593
1594 addASLRargs := func(argv []string, val bool) []string {
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610 var dbopt string
1611 var heopt string
1612 dbon := wlPrefix + "dynamicbase"
1613 heon := wlPrefix + "high-entropy-va"
1614 dboff := wlPrefix + "disable-dynamicbase"
1615 heoff := wlPrefix + "disable-high-entropy-va"
1616 if isMSVC {
1617 heon = wlPrefix + "highentropyva"
1618 heoff = wlPrefix + "highentropyva:no"
1619 dboff = wlPrefix + "dynamicbase:no"
1620 }
1621 if val {
1622 dbopt = dbon
1623 heopt = heon
1624 } else {
1625
1626 newer := linkerFlagSupported(ctxt.Arch, argv[0], "", dboff)
1627 if newer {
1628
1629 dbopt = dboff
1630 heopt = heoff
1631 } else {
1632
1633
1634 dbopt = ""
1635 heopt = ""
1636 }
1637 }
1638 if dbopt != "" {
1639 argv = append(argv, dbopt)
1640 }
1641
1642 if ctxt.Arch.PtrSize >= 8 && heopt != "" {
1643 argv = append(argv, heopt)
1644 }
1645 return argv
1646 }
1647
1648 switch ctxt.BuildMode {
1649 case BuildModeExe:
1650 if ctxt.HeadType == objabi.Hdarwin {
1651 if machoPlatform == PLATFORM_MACOS && ctxt.IsAMD64() {
1652 argv = append(argv, "-Wl,-no_pie")
1653 }
1654 }
1655 if *flagRace && ctxt.HeadType == objabi.Hwindows {
1656
1657
1658
1659
1660 argv = addASLRargs(argv, false)
1661 }
1662 case BuildModePIE:
1663 switch ctxt.HeadType {
1664 case objabi.Hdarwin, objabi.Haix:
1665 case objabi.Hwindows:
1666 if *flagAslr && *flagRace {
1667
1668
1669
1670 *flagAslr = false
1671 }
1672 argv = addASLRargs(argv, *flagAslr)
1673 default:
1674
1675 if ctxt.UseRelro() {
1676 argv = append(argv, "-Wl,-z,relro")
1677 }
1678 argv = append(argv, "-pie")
1679 }
1680 case BuildModeCShared:
1681 if ctxt.HeadType == objabi.Hdarwin {
1682 argv = append(argv, "-dynamiclib")
1683 } else {
1684 if ctxt.UseRelro() {
1685 argv = append(argv, "-Wl,-z,relro")
1686 }
1687 argv = append(argv, "-shared")
1688 if ctxt.HeadType == objabi.Hwindows {
1689 argv = addASLRargs(argv, *flagAslr)
1690 } else {
1691
1692
1693 argv = append(argv, "-Wl,-z,nodelete")
1694
1695 argv = append(argv, "-Wl,-Bsymbolic")
1696 }
1697 }
1698 case BuildModeShared:
1699 if ctxt.UseRelro() {
1700 argv = append(argv, "-Wl,-z,relro")
1701 }
1702 argv = append(argv, "-shared")
1703 case BuildModePlugin:
1704 if ctxt.HeadType == objabi.Hdarwin {
1705 argv = append(argv, "-dynamiclib")
1706 } else {
1707 if ctxt.UseRelro() {
1708 argv = append(argv, "-Wl,-z,relro")
1709 }
1710 argv = append(argv, "-shared")
1711 }
1712 }
1713
1714 var altLinker string
1715 if ctxt.IsELF && (ctxt.DynlinkingGo() || *flagBindNow) {
1716
1717
1718
1719
1720
1721 argv = append(argv, "-Wl,-z,now")
1722 }
1723
1724 if ctxt.IsELF && ctxt.DynlinkingGo() {
1725
1726
1727
1728 argv = append(argv, "-Wl,-z,nocopyreloc")
1729
1730 if buildcfg.GOOS == "android" {
1731
1732 altLinker = "lld"
1733 }
1734
1735 if ctxt.Arch.InFamily(sys.ARM64) && buildcfg.GOOS == "linux" {
1736
1737
1738
1739
1740
1741
1742
1743 useGold := false
1744 name, args := flagExtld[0], flagExtld[1:]
1745 args = append(args, "-Wl,--version")
1746 cmd := exec.Command(name, args...)
1747 if out, err := cmd.CombinedOutput(); err == nil {
1748
1749 for line := range strings.Lines(string(out)) {
1750 if !strings.HasPrefix(line, "GNU ld ") {
1751 continue
1752 }
1753 fields := strings.Fields(line[len("GNU ld "):])
1754 var major, minor int
1755 if ret, err := fmt.Sscanf(fields[len(fields)-1], "%d.%d", &major, &minor); ret == 2 && err == nil {
1756 if major == 2 && minor <= 35 {
1757 useGold = true
1758 }
1759 break
1760 }
1761 }
1762 }
1763
1764 if useGold {
1765
1766 altLinker = "gold"
1767
1768
1769
1770
1771 args = flagExtld[1:]
1772 args = append(args, "-fuse-ld=gold", "-Wl,--version")
1773 cmd = exec.Command(name, args...)
1774 if out, err := cmd.CombinedOutput(); err == nil {
1775 if !bytes.Contains(out, []byte("GNU gold")) {
1776 log.Fatalf("ARM64 external linker must be ld>=2.36 or gold (issue #15696, 22040), but is not: %s", out)
1777 }
1778 }
1779 }
1780 }
1781 }
1782 if ctxt.Arch.Family == sys.ARM64 && buildcfg.GOOS == "freebsd" {
1783
1784 altLinker = "bfd"
1785
1786
1787 name, args := flagExtld[0], flagExtld[1:]
1788 args = append(args, "-fuse-ld=bfd", "-Wl,--version")
1789 cmd := exec.Command(name, args...)
1790 if out, err := cmd.CombinedOutput(); err == nil {
1791 if !bytes.Contains(out, []byte("GNU ld")) {
1792 log.Fatalf("ARM64 external linker must be ld.bfd (issue #35197), please install devel/binutils")
1793 }
1794 }
1795 }
1796 if altLinker != "" {
1797 argv = append(argv, "-fuse-ld="+altLinker)
1798 }
1799
1800 if ctxt.IsELF && linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,--build-id=0x1234567890abcdef") {
1801 if len(buildinfo) > 0 {
1802 argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
1803 } else if *flagHostBuildid == "none" {
1804 argv = append(argv, "-Wl,--build-id=none")
1805 }
1806 }
1807
1808
1809
1810
1811
1812
1813
1814 outopt := *flagOutfile
1815 if buildcfg.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
1816 outopt += "."
1817 }
1818 argv = append(argv, "-o")
1819 argv = append(argv, outopt)
1820
1821 if rpath.val != "" {
1822 argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
1823 }
1824
1825 if *flagInterpreter != "" {
1826
1827
1828
1829
1830 argv = append(argv, fmt.Sprintf("-Wl,--dynamic-linker,%s", *flagInterpreter))
1831 }
1832
1833
1834 switch {
1835 case ctxt.IsELF:
1836 if ctxt.DynlinkingGo() || ctxt.BuildMode == BuildModeCShared || !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "-Wl,--export-dynamic-symbol=main") {
1837 argv = append(argv, "-rdynamic")
1838 } else {
1839 var exports []string
1840 ctxt.loader.ForAllCgoExportDynamic(func(s loader.Sym) {
1841 exports = append(exports, "-Wl,--export-dynamic-symbol="+ctxt.loader.SymExtname(s))
1842 })
1843 sort.Strings(exports)
1844 argv = append(argv, exports...)
1845 }
1846 case ctxt.IsAIX():
1847 fileName := xcoffCreateExportFile(ctxt)
1848 argv = append(argv, "-Wl,-bE:"+fileName)
1849 case ctxt.IsWindows() && !slices.Contains(flagExtldflags, wlPrefix+"export-all-symbols"):
1850 fileName := peCreateExportFile(ctxt, filepath.Base(outopt))
1851 prefix := ""
1852 if isMSVC {
1853 prefix = "-Wl,-def:"
1854 }
1855 argv = append(argv, prefix+fileName)
1856 }
1857
1858 const unusedArguments = "-Qunused-arguments"
1859 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, unusedArguments) {
1860 argv = append(argv, unusedArguments)
1861 }
1862
1863 if ctxt.IsWindows() {
1864
1865
1866
1867
1868 const noTimeStamp = "-Wl,--no-insert-timestamp"
1869 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, noTimeStamp) {
1870 argv = append(argv, noTimeStamp)
1871 }
1872 }
1873
1874 const compressDWARF = "-Wl,--compress-debug-sections=zlib"
1875 if ctxt.compressDWARF && linkerFlagSupported(ctxt.Arch, argv[0], altLinker, compressDWARF) {
1876 argv = append(argv, compressDWARF)
1877 }
1878
1879 hostObjCopyPaths := ctxt.hostobjCopy()
1880 cleanTimeStamps(hostObjCopyPaths)
1881 godotopath := filepath.Join(*flagTmpdir, "go.o")
1882 cleanTimeStamps([]string{godotopath})
1883
1884 argv = append(argv, godotopath)
1885 argv = append(argv, hostObjCopyPaths...)
1886 if ctxt.HeadType == objabi.Haix {
1887
1888
1889 argv = append(argv, "-nostartfiles")
1890
1891 extld := ctxt.extld()
1892 name, args := extld[0], extld[1:]
1893
1894 getPathFile := func(file string) string {
1895 args := append(args, "-maix64", "--print-file-name="+file)
1896 out, err := exec.Command(name, args...).CombinedOutput()
1897 if err != nil {
1898 log.Fatalf("running %s failed: %v\n%s", extld, err, out)
1899 }
1900 return strings.Trim(string(out), "\n")
1901 }
1902 argv = append(argv, getPathFile("crt0_64.o"))
1903
1904
1905
1906 crtcxa := getPathFile("crtcxa_64.o")
1907 if !filepath.IsAbs(crtcxa) {
1908 crtcxa = getPathFile("crtcxa.o")
1909 }
1910 crtdbase := getPathFile("crtdbase_64.o")
1911 if !filepath.IsAbs(crtdbase) {
1912 crtdbase = getPathFile("crtdbase.o")
1913 }
1914 argv = append(argv, crtcxa)
1915 argv = append(argv, crtdbase)
1916 }
1917
1918 if ctxt.linkShared {
1919 seenDirs := make(map[string]bool)
1920 seenLibs := make(map[string]bool)
1921 addshlib := func(path string) {
1922 dir, base := filepath.Split(path)
1923 if !seenDirs[dir] {
1924 argv = append(argv, "-L"+dir)
1925 if !rpath.set {
1926 argv = append(argv, "-Wl,-rpath="+dir)
1927 }
1928 seenDirs[dir] = true
1929 }
1930 base = strings.TrimSuffix(base, ".so")
1931 base = strings.TrimPrefix(base, "lib")
1932 if !seenLibs[base] {
1933 argv = append(argv, "-l"+base)
1934 seenLibs[base] = true
1935 }
1936 }
1937 for _, shlib := range ctxt.Shlibs {
1938 addshlib(shlib.Path)
1939 for _, dep := range shlib.Deps {
1940 if dep == "" {
1941 continue
1942 }
1943 libpath := findshlib(ctxt, dep)
1944 if libpath != "" {
1945 addshlib(libpath)
1946 }
1947 }
1948 }
1949 }
1950
1951
1952
1953
1954
1955
1956
1957
1958 checkStatic := func(arg string) {
1959 if ctxt.IsELF && arg == "-static" {
1960 for i := range argv {
1961 if argv[i] == "-rdynamic" || strings.HasPrefix(argv[i], "-Wl,--dynamic-linker,") {
1962 argv[i] = "-static"
1963 }
1964 }
1965 }
1966 }
1967
1968 for _, p := range ldflag {
1969 argv = append(argv, p)
1970 checkStatic(p)
1971 }
1972
1973
1974
1975
1976
1977
1978
1979
1980 if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared && !(ctxt.IsDarwin() && ctxt.IsARM64()) {
1981
1982 for _, nopie := range []string{"-no-pie", "-nopie"} {
1983 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, nopie) {
1984 argv = append(argv, nopie)
1985 break
1986 }
1987 }
1988 }
1989
1990 for _, p := range flagExtldflags {
1991 argv = append(argv, p)
1992 checkStatic(p)
1993 }
1994 if ctxt.HeadType == objabi.Hwindows {
1995
1996
1997 if !isLLD {
1998 p := writeGDBLinkerScript()
1999 argv = append(argv, "-Wl,-T,"+p)
2000 }
2001 if *flagRace {
2002
2003
2004
2005
2006 if isMSVC || ctxt.findLibPath("libsynchronization.a") != "libsynchronization.a" {
2007 argv = append(argv, "-lsynchronization")
2008 }
2009 }
2010 if !isMSVC {
2011
2012
2013 argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
2014 }
2015 argv = append(argv, peimporteddlls()...)
2016 }
2017
2018 argv = ctxt.passLongArgsInResponseFile(argv, altLinker)
2019
2020 if ctxt.Debugvlog != 0 {
2021 ctxt.Logf("host link:")
2022 for _, v := range argv {
2023 ctxt.Logf(" %q", v)
2024 }
2025 ctxt.Logf("\n")
2026 }
2027
2028 cmd := exec.Command(argv[0], argv[1:]...)
2029 out, err := cmd.CombinedOutput()
2030 if err != nil {
2031 Exitf("running %s failed: %v\n%s\n%s", argv[0], err, cmd, out)
2032 }
2033
2034
2035
2036 var save [][]byte
2037 var skipLines int
2038 for _, line := range bytes.SplitAfter(out, []byte("\n")) {
2039
2040 if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
2041 continue
2042 }
2043
2044 if skipLines > 0 {
2045 skipLines--
2046 continue
2047 }
2048
2049
2050 if bytes.Contains(line, []byte("ld: 0711-783")) {
2051 skipLines = 2
2052 continue
2053 }
2054
2055 save = append(save, line)
2056 }
2057 out = bytes.Join(save, nil)
2058
2059 if len(out) > 0 {
2060
2061
2062 if ctxt.IsDarwin() && ctxt.IsAMD64() {
2063 const noPieWarning = "ld: warning: -no_pie is deprecated when targeting new OS versions\n"
2064 if i := bytes.Index(out, []byte(noPieWarning)); i >= 0 {
2065
2066 out = append(out[:i], out[i+len(noPieWarning):]...)
2067 }
2068 }
2069 if ctxt.IsDarwin() {
2070 const bindAtLoadWarning = "ld: warning: -bind_at_load is deprecated on macOS\n"
2071 if i := bytes.Index(out, []byte(bindAtLoadWarning)); i >= 0 {
2072
2073
2074
2075
2076 out = append(out[:i], out[i+len(bindAtLoadWarning):]...)
2077 }
2078 }
2079 ctxt.Logf("%s", out)
2080 }
2081
2082
2083
2084 updateMachoOutFile := func(op string, updateFunc machoUpdateFunc) {
2085
2086 rewrittenOutput := *flagOutfile + "~"
2087 exef, err := os.Open(*flagOutfile)
2088 if err != nil {
2089 Exitf("%s: %s failed: %v", os.Args[0], op, err)
2090 }
2091 defer exef.Close()
2092 exem, err := macho.NewFile(exef)
2093 if err != nil {
2094 Exitf("%s: parsing Mach-O header failed: %v", os.Args[0], err)
2095 }
2096 if err := updateFunc(ctxt, exef, exem, rewrittenOutput); err != nil {
2097 Exitf("%s: %s failed: %v", os.Args[0], op, err)
2098 }
2099 os.Remove(*flagOutfile)
2100 if err := os.Rename(rewrittenOutput, *flagOutfile); err != nil {
2101 Exitf("%s: %v", os.Args[0], err)
2102 }
2103 }
2104
2105 uuidUpdated := false
2106 if combineDwarf {
2107
2108 dsymutilCmd := ctxt.findExtLinkTool("dsymutil")
2109 stripCmd := ctxt.findExtLinkTool("strip")
2110
2111 dsym := filepath.Join(*flagTmpdir, "go.dwarf")
2112 cmd := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym)
2113
2114
2115
2116
2117
2118 dsymDir := filepath.Join(*flagTmpdir, "dsymutil")
2119 err := os.MkdirAll(dsymDir, 0777)
2120 if err != nil {
2121 Exitf("fail to create temp dir: %v", err)
2122 }
2123 cmd.Env = append(os.Environ(), "DSYMUTIL_REPRODUCER_PATH="+dsymDir)
2124 if ctxt.Debugvlog != 0 {
2125 ctxt.Logf("host link dsymutil:")
2126 for _, v := range cmd.Args {
2127 ctxt.Logf(" %q", v)
2128 }
2129 ctxt.Logf("\n")
2130 }
2131 if out, err := cmd.CombinedOutput(); err != nil {
2132 Exitf("%s: running dsymutil failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
2133 }
2134
2135
2136 var stripArgs = []string{"-S"}
2137 if debug_s {
2138
2139
2140
2141 stripArgs = append(stripArgs, "-x")
2142 }
2143 stripArgs = append(stripArgs, *flagOutfile)
2144 if ctxt.Debugvlog != 0 {
2145 ctxt.Logf("host link strip: %q", stripCmd)
2146 for _, v := range stripArgs {
2147 ctxt.Logf(" %q", v)
2148 }
2149 ctxt.Logf("\n")
2150 }
2151 cmd = exec.Command(stripCmd, stripArgs...)
2152 if out, err := cmd.CombinedOutput(); err != nil {
2153 Exitf("%s: running strip failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
2154 }
2155
2156 if _, err := os.Stat(dsym); err == nil {
2157 updateMachoOutFile("combining dwarf",
2158 func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
2159 return machoCombineDwarf(ctxt, exef, exem, dsym, outexe)
2160 })
2161 uuidUpdated = true
2162 }
2163 }
2164 if ctxt.IsDarwin() && !uuidUpdated && len(buildinfo) > 0 {
2165 updateMachoOutFile("rewriting uuid",
2166 func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
2167 return machoRewriteUuid(ctxt, exef, exem, outexe)
2168 })
2169 }
2170 hostlinkfips(ctxt, *flagOutfile, *flagFipso)
2171 if ctxt.NeedCodeSign() {
2172 err := machoCodeSign(ctxt, *flagOutfile)
2173 if err != nil {
2174 Exitf("%s: code signing failed: %v", os.Args[0], err)
2175 }
2176 }
2177 }
2178
2179
2180
2181 func (ctxt *Link) passLongArgsInResponseFile(argv []string, altLinker string) []string {
2182 c := 0
2183 for _, arg := range argv {
2184 c += len(arg)
2185 }
2186
2187 if c < sys.ExecArgLengthLimit {
2188 return argv
2189 }
2190
2191
2192 response := filepath.Join(*flagTmpdir, "response")
2193 if err := os.WriteFile(response, nil, 0644); err != nil {
2194 log.Fatalf("failed while testing response file: %v", err)
2195 }
2196 if !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "@"+response) {
2197 if ctxt.Debugvlog != 0 {
2198 ctxt.Logf("not using response file because linker does not support one")
2199 }
2200 return argv
2201 }
2202
2203 var buf bytes.Buffer
2204 for _, arg := range argv[1:] {
2205
2206 fmt.Fprintf(&buf, "%q\n", arg)
2207 }
2208 if err := os.WriteFile(response, buf.Bytes(), 0644); err != nil {
2209 log.Fatalf("failed while writing response file: %v", err)
2210 }
2211 if ctxt.Debugvlog != 0 {
2212 ctxt.Logf("response file %s contents:\n%s", response, buf.Bytes())
2213 }
2214 return []string{
2215 argv[0],
2216 "@" + response,
2217 }
2218 }
2219
2220 var createTrivialCOnce sync.Once
2221
2222 func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
2223 createTrivialCOnce.Do(func() {
2224 src := filepath.Join(*flagTmpdir, "trivial.c")
2225 if err := os.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
2226 Errorf("WriteFile trivial.c failed: %v", err)
2227 }
2228 })
2229
2230 flags := hostlinkArchArgs(arch)
2231
2232 moreFlags := trimLinkerArgv(append(ldflag, flagExtldflags...))
2233 flags = append(flags, moreFlags...)
2234
2235 if altLinker != "" {
2236 flags = append(flags, "-fuse-ld="+altLinker)
2237 }
2238 trivialPath := filepath.Join(*flagTmpdir, "trivial.c")
2239 outPath := filepath.Join(*flagTmpdir, "a.out")
2240 flags = append(flags, "-o", outPath, flag, trivialPath)
2241
2242 cmd := exec.Command(linker, flags...)
2243 cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
2244 out, err := cmd.CombinedOutput()
2245
2246
2247 return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
2248 }
2249
2250
2251
2252
2253
2254
2255
2256 func peHasLoadConfigDirectorySupport(arch *sys.Arch, linker string) bool {
2257 src := filepath.Join(*flagTmpdir, "loadcfg_test.c")
2258 if err := os.WriteFile(src, []byte(`
2259 #ifdef _WIN64
2260 typedef unsigned long long uintptr;
2261 #else
2262 typedef unsigned long uintptr;
2263 #endif
2264 const uintptr _load_config_used[2] = { sizeof(_load_config_used), 0 };
2265 int main() { return 0; }
2266 `), 0666); err != nil {
2267 return false
2268 }
2269
2270 outPath := filepath.Join(*flagTmpdir, "loadcfg_test.exe")
2271 flags := hostlinkArchArgs(arch)
2272 flags = append(flags, "-o", outPath, src)
2273 cmd := exec.Command(linker, flags...)
2274 cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
2275 if err := cmd.Run(); err != nil {
2276 return false
2277 }
2278
2279 f, err := pe.Open(outPath)
2280 if err != nil {
2281 return false
2282 }
2283 defer f.Close()
2284
2285 switch oh := f.OptionalHeader.(type) {
2286 case *pe.OptionalHeader64:
2287 if int(pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) < len(oh.DataDirectory) {
2288 return oh.DataDirectory[pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress != 0
2289 }
2290 case *pe.OptionalHeader32:
2291 if int(pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG) < len(oh.DataDirectory) {
2292 return oh.DataDirectory[pe.IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress != 0
2293 }
2294 }
2295 return false
2296 }
2297
2298
2299
2300 func trimLinkerArgv(argv []string) []string {
2301 flagsWithNextArgSkip := []string{
2302 "-F",
2303 "-l",
2304 "-framework",
2305 "-Wl,-framework",
2306 "-Wl,-rpath",
2307 "-Wl,-undefined",
2308 }
2309 flagsWithNextArgKeep := []string{
2310 "-B",
2311 "-L",
2312 "-arch",
2313 "-isysroot",
2314 "--sysroot",
2315 "-target",
2316 "--target",
2317 "-resource-dir",
2318 "-rtlib",
2319 "--rtlib",
2320 "-stdlib",
2321 "--stdlib",
2322 "-unwindlib",
2323 "--unwindlib",
2324 }
2325 prefixesToKeep := []string{
2326 "-B",
2327 "-L",
2328 "-f",
2329 "-m",
2330 "-p",
2331 "-Wl,",
2332 "-arch",
2333 "-isysroot",
2334 "--sysroot",
2335 "-target",
2336 "--target",
2337 "-resource-dir",
2338 "-rtlib",
2339 "--rtlib",
2340 "-stdlib",
2341 "--stdlib",
2342 "-unwindlib",
2343 "--unwindlib",
2344 "-nostdlib++",
2345 "-nostdlib",
2346 "-nodefaultlibs",
2347 "-nostartfiles",
2348 "-nostdinc++",
2349 "-nostdinc",
2350 "-nobuiltininc",
2351 }
2352
2353 var flags []string
2354 keep := false
2355 skip := false
2356 for _, f := range argv {
2357 if keep {
2358 flags = append(flags, f)
2359 keep = false
2360 } else if skip {
2361 skip = false
2362 } else if f == "" || f[0] != '-' {
2363 } else if slices.Contains(flagsWithNextArgSkip, f) {
2364 skip = true
2365 } else if slices.Contains(flagsWithNextArgKeep, f) {
2366 flags = append(flags, f)
2367 keep = true
2368 } else {
2369 for _, p := range prefixesToKeep {
2370 if strings.HasPrefix(f, p) {
2371 flags = append(flags, f)
2372 break
2373 }
2374 }
2375 }
2376 }
2377 return flags
2378 }
2379
2380
2381
2382 func hostlinkArchArgs(arch *sys.Arch) []string {
2383 switch arch.Family {
2384 case sys.I386:
2385 return []string{"-m32"}
2386 case sys.AMD64:
2387 if buildcfg.GOOS == "darwin" {
2388 return []string{"-arch", "x86_64", "-m64"}
2389 }
2390 return []string{"-m64"}
2391 case sys.S390X:
2392 return []string{"-m64"}
2393 case sys.ARM:
2394 return []string{"-marm"}
2395 case sys.ARM64:
2396 if buildcfg.GOOS == "darwin" {
2397 return []string{"-arch", "arm64"}
2398 }
2399 case sys.Loong64:
2400 return []string{"-mabi=lp64d"}
2401 case sys.MIPS64:
2402 return []string{"-mabi=64"}
2403 case sys.MIPS:
2404 return []string{"-mabi=32"}
2405 case sys.PPC64:
2406 if buildcfg.GOOS == "aix" {
2407 return []string{"-maix64"}
2408 } else {
2409 return []string{"-m64"}
2410 }
2411
2412 }
2413 return nil
2414 }
2415
2416 var wantHdr = objabi.HeaderString()
2417
2418
2419
2420
2421 func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, file string) *Hostobj {
2422 pkg := objabi.PathToPrefix(lib.Pkg)
2423
2424 eof := f.Offset() + length
2425 start := f.Offset()
2426 c1 := bgetc(f)
2427 c2 := bgetc(f)
2428 c3 := bgetc(f)
2429 c4 := bgetc(f)
2430 f.MustSeek(start, 0)
2431
2432 unit := &sym.CompilationUnit{Lib: lib}
2433 lib.Units = append(lib.Units, unit)
2434
2435 magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
2436 if magic == 0x7f454c46 {
2437 ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2438 textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.Flags)
2439 if err != nil {
2440 Errorf("%v", err)
2441 return
2442 }
2443 ehdr.Flags = flags
2444 ctxt.Textp = append(ctxt.Textp, textp...)
2445 }
2446 return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
2447 }
2448
2449 if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
2450 ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2451 textp, err := loadmacho.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2452 if err != nil {
2453 Errorf("%v", err)
2454 return
2455 }
2456 ctxt.Textp = append(ctxt.Textp, textp...)
2457 }
2458 return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
2459 }
2460
2461 switch c1<<8 | c2 {
2462 case 0x4c01,
2463 0x6486,
2464 0xc401,
2465 0x64aa:
2466 ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2467 ls, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2468 if err != nil {
2469 Errorf("%v", err)
2470 return
2471 }
2472 if len(ls.Resources) != 0 {
2473 setpersrc(ctxt, ls.Resources)
2474 }
2475 sehp.pdata = append(sehp.pdata, ls.PData...)
2476 if ls.XData != 0 {
2477 sehp.xdata = append(sehp.xdata, ls.XData)
2478 }
2479 ctxt.Textp = append(ctxt.Textp, ls.Textp...)
2480 }
2481 return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
2482 }
2483
2484 if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
2485 ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2486 textp, err := loadxcoff.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2487 if err != nil {
2488 Errorf("%v", err)
2489 return
2490 }
2491 ctxt.Textp = append(ctxt.Textp, textp...)
2492 }
2493 return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
2494 }
2495
2496 if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' {
2497
2498
2499
2500 unknownObjFormat = true
2501 return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file)
2502 }
2503
2504
2505 line, err := f.ReadString('\n')
2506 if err != nil {
2507 Errorf("truncated object file: %s: %v", pn, err)
2508 return nil
2509 }
2510
2511 if !strings.HasPrefix(line, "go object ") {
2512 if strings.HasSuffix(pn, ".go") {
2513 Exitf("%s: uncompiled .go source file", pn)
2514 return nil
2515 }
2516
2517 if line == ctxt.Arch.Name {
2518
2519 Errorf("%s: stale object file", pn)
2520 return nil
2521 }
2522
2523 Errorf("%s: not an object file: @%d %q", pn, start, line)
2524 return nil
2525 }
2526
2527
2528 if line != wantHdr && !*flagF {
2529 Errorf("%s: linked object header mismatch:\nhave %q\nwant %q\n", pn, line, wantHdr)
2530 }
2531
2532
2533
2534
2535
2536
2537
2538
2539 import0 := f.Offset()
2540
2541 c1 = '\n'
2542 c2 = bgetc(f)
2543 c3 = bgetc(f)
2544 markers := 0
2545 for {
2546 if c1 == '\n' {
2547 if markers%2 == 0 && c2 == '!' && c3 == '\n' {
2548 break
2549 }
2550 if c2 == '$' && c3 == '$' {
2551 markers++
2552 }
2553 }
2554
2555 c1 = c2
2556 c2 = c3
2557 c3 = bgetc(f)
2558 if c3 == -1 {
2559 Errorf("truncated object file: %s", pn)
2560 return nil
2561 }
2562 }
2563
2564 import1 := f.Offset()
2565
2566 f.MustSeek(import0, 0)
2567 ldpkg(ctxt, f, lib, import1-import0-2, pn)
2568 f.MustSeek(import1, 0)
2569
2570 fingerprint := ctxt.loader.Preload(ctxt.IncVersion(), f, lib, unit, eof-f.Offset())
2571 if !fingerprint.IsZero() {
2572
2573
2574
2575
2576
2577 if lib.Fingerprint.IsZero() {
2578 lib.Fingerprint = fingerprint
2579 }
2580 checkFingerprint(lib, fingerprint, lib.Srcref, lib.Fingerprint)
2581 }
2582
2583 addImports(ctxt, lib, pn)
2584 return nil
2585 }
2586
2587
2588
2589
2590
2591 func symbolsAreUnresolved(ctxt *Link, want []string) []bool {
2592 returnAllUndefs := -1
2593 undefs, _ := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
2594 seen := make(map[loader.Sym]struct{})
2595 rval := make([]bool, len(want))
2596 wantm := make(map[string]int)
2597 for k, w := range want {
2598 wantm[w] = k
2599 }
2600 count := 0
2601 for _, s := range undefs {
2602 if _, ok := seen[s]; ok {
2603 continue
2604 }
2605 seen[s] = struct{}{}
2606 if k, ok := wantm[ctxt.loader.SymName(s)]; ok {
2607 rval[k] = true
2608 count++
2609 if count == len(want) {
2610 return rval
2611 }
2612 }
2613 }
2614 return rval
2615 }
2616
2617
2618
2619
2620 func hostObject(ctxt *Link, objname string, path string) {
2621 if ctxt.Debugvlog > 1 {
2622 ctxt.Logf("hostObject(%s)\n", path)
2623 }
2624 objlib := sym.Library{
2625 Pkg: objname,
2626 }
2627 f, err := bio.Open(path)
2628 if err != nil {
2629 Exitf("cannot open host object %q file %s: %v", objname, path, err)
2630 }
2631 defer f.Close()
2632 h := ldobj(ctxt, f, &objlib, 0, path, path)
2633 if h.ld == nil {
2634 Exitf("unrecognized object file format in %s", path)
2635 }
2636 h.file = path
2637 h.length = f.MustSeek(0, 2)
2638 f.MustSeek(h.off, 0)
2639 h.ld(ctxt, f, h.pkg, h.length, h.pn)
2640 if *flagCaptureHostObjs != "" {
2641 captureHostObj(h)
2642 }
2643 }
2644
2645 func checkFingerprint(lib *sym.Library, libfp goobj.FingerprintType, src string, srcfp goobj.FingerprintType) {
2646 if libfp != srcfp {
2647 Exitf("fingerprint mismatch: %s has %x, import from %s expecting %x", lib, libfp, src, srcfp)
2648 }
2649 }
2650
2651 func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
2652 data := make([]byte, sym.Size)
2653 sect := f.Sections[sym.Section]
2654 if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
2655 Errorf("reading %s from non-data section", sym.Name)
2656 }
2657 n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
2658 if uint64(n) != sym.Size {
2659 Errorf("reading contents of %s: %v", sym.Name, err)
2660 }
2661 return data
2662 }
2663
2664 func readwithpad(r io.Reader, sz int32) ([]byte, error) {
2665 data := make([]byte, Rnd(int64(sz), 4))
2666 _, err := io.ReadFull(r, data)
2667 if err != nil {
2668 return nil, err
2669 }
2670 data = data[:sz]
2671 return data, nil
2672 }
2673
2674 func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
2675 for _, sect := range f.Sections {
2676 if sect.Type != elf.SHT_NOTE {
2677 continue
2678 }
2679 r := sect.Open()
2680 for {
2681 var namesize, descsize, noteType int32
2682 err := binary.Read(r, f.ByteOrder, &namesize)
2683 if err != nil {
2684 if err == io.EOF {
2685 break
2686 }
2687 return nil, fmt.Errorf("read namesize failed: %v", err)
2688 }
2689 err = binary.Read(r, f.ByteOrder, &descsize)
2690 if err != nil {
2691 return nil, fmt.Errorf("read descsize failed: %v", err)
2692 }
2693 err = binary.Read(r, f.ByteOrder, ¬eType)
2694 if err != nil {
2695 return nil, fmt.Errorf("read type failed: %v", err)
2696 }
2697 noteName, err := readwithpad(r, namesize)
2698 if err != nil {
2699 return nil, fmt.Errorf("read name failed: %v", err)
2700 }
2701 desc, err := readwithpad(r, descsize)
2702 if err != nil {
2703 return nil, fmt.Errorf("read desc failed: %v", err)
2704 }
2705 if string(name) == string(noteName) && typ == noteType {
2706 return desc, nil
2707 }
2708 }
2709 }
2710 return nil, nil
2711 }
2712
2713 func findshlib(ctxt *Link, shlib string) string {
2714 if filepath.IsAbs(shlib) {
2715 return shlib
2716 }
2717 for _, libdir := range ctxt.Libdir {
2718 libpath := filepath.Join(libdir, shlib)
2719 if _, err := os.Stat(libpath); err == nil {
2720 return libpath
2721 }
2722 }
2723 Errorf("cannot find shared library: %s", shlib)
2724 return ""
2725 }
2726
2727 func ldshlibsyms(ctxt *Link, shlib string) {
2728 var libpath string
2729 if filepath.IsAbs(shlib) {
2730 libpath = shlib
2731 shlib = filepath.Base(shlib)
2732 } else {
2733 libpath = findshlib(ctxt, shlib)
2734 if libpath == "" {
2735 return
2736 }
2737 }
2738 for _, processedlib := range ctxt.Shlibs {
2739 if processedlib.Path == libpath {
2740 return
2741 }
2742 }
2743 if ctxt.Debugvlog > 1 {
2744 ctxt.Logf("ldshlibsyms: found library with name %s at %s\n", shlib, libpath)
2745 }
2746
2747 f, err := elf.Open(libpath)
2748 if err != nil {
2749 Errorf("cannot open shared library: %s", libpath)
2750 return
2751 }
2752
2753
2754
2755
2756 hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
2757 if err != nil {
2758 Errorf("cannot read ABI hash from shared library %s: %v", libpath, err)
2759 return
2760 }
2761
2762 depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
2763 if err != nil {
2764 Errorf("cannot read dep list from shared library %s: %v", libpath, err)
2765 return
2766 }
2767 var deps []string
2768 for _, dep := range strings.Split(string(depsbytes), "\n") {
2769 if dep == "" {
2770 continue
2771 }
2772 if !filepath.IsAbs(dep) {
2773
2774
2775
2776 abs := filepath.Join(filepath.Dir(libpath), dep)
2777 if _, err := os.Stat(abs); err == nil {
2778 dep = abs
2779 }
2780 }
2781 deps = append(deps, dep)
2782 }
2783
2784 syms, err := f.DynamicSymbols()
2785 if err != nil {
2786 Errorf("cannot read symbols from shared library: %s", libpath)
2787 return
2788 }
2789
2790 symAddr := map[string]uint64{}
2791 for _, elfsym := range syms {
2792 if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
2793 continue
2794 }
2795
2796
2797
2798 ver := 0
2799 symname := elfsym.Name
2800 if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && strings.HasPrefix(elfsym.Name, "type:") {
2801 ver = abiInternalVer
2802 } else if buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC {
2803
2804 if strings.HasSuffix(elfsym.Name, ".abiinternal") {
2805 ver = sym.SymVerABIInternal
2806 symname = strings.TrimSuffix(elfsym.Name, ".abiinternal")
2807 } else if strings.HasSuffix(elfsym.Name, ".abi0") {
2808 ver = 0
2809 symname = strings.TrimSuffix(elfsym.Name, ".abi0")
2810 }
2811 }
2812
2813 l := ctxt.loader
2814 s := l.LookupOrCreateSym(symname, ver)
2815
2816
2817
2818
2819
2820 if l.SymType(s) != 0 && l.SymType(s) != sym.SDYNIMPORT {
2821 continue
2822 }
2823 su := l.MakeSymbolUpdater(s)
2824 su.SetType(sym.SDYNIMPORT)
2825 l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
2826 su.SetSize(int64(elfsym.Size))
2827 if elfsym.Section != elf.SHN_UNDEF {
2828
2829 l.SetSymPkg(s, libpath)
2830
2831
2832
2833 sname := l.SymName(s)
2834 if strings.HasPrefix(sname, "type:") && !strings.HasPrefix(sname, "type:.") {
2835 su.SetData(readelfsymboldata(ctxt, f, &elfsym))
2836 }
2837 }
2838
2839 if symname != elfsym.Name {
2840 l.SetSymExtname(s, elfsym.Name)
2841 }
2842 symAddr[elfsym.Name] = elfsym.Value
2843 }
2844
2845
2846
2847
2848 relocTarget := map[uint64]string{}
2849 addends := false
2850 sect := f.SectionByType(elf.SHT_REL)
2851 if sect == nil {
2852 sect = f.SectionByType(elf.SHT_RELA)
2853 if sect == nil {
2854 log.Fatalf("can't find SHT_REL or SHT_RELA section of %s", shlib)
2855 }
2856 addends = true
2857 }
2858
2859 data, err := sect.Data()
2860 if err != nil {
2861 log.Fatalf("can't read relocation section of %s: %v", shlib, err)
2862 }
2863 bo := f.ByteOrder
2864 for len(data) > 0 {
2865 var off, idx uint64
2866 var addend int64
2867 switch f.Class {
2868 case elf.ELFCLASS64:
2869 off = bo.Uint64(data)
2870 info := bo.Uint64(data[8:])
2871 data = data[16:]
2872 if addends {
2873 addend = int64(bo.Uint64(data))
2874 data = data[8:]
2875 }
2876
2877 idx = info >> 32
2878 typ := info & 0xffff
2879
2880
2881 switch typ {
2882 case uint64(elf.R_X86_64_64):
2883 case uint64(elf.R_AARCH64_ABS64):
2884 case uint64(elf.R_LARCH_64):
2885 case uint64(elf.R_390_64):
2886 case uint64(elf.R_PPC64_ADDR64):
2887 default:
2888 continue
2889 }
2890 case elf.ELFCLASS32:
2891 off = uint64(bo.Uint32(data))
2892 info := bo.Uint32(data[4:])
2893 data = data[8:]
2894 if addends {
2895 addend = int64(int32(bo.Uint32(data)))
2896 data = data[4:]
2897 }
2898
2899 idx = uint64(info >> 8)
2900 typ := info & 0xff
2901
2902 switch typ {
2903 case uint32(elf.R_386_32):
2904 case uint32(elf.R_ARM_ABS32):
2905 default:
2906 continue
2907 }
2908 default:
2909 log.Fatalf("unknown bit size %s", f.Class)
2910 }
2911 if addend != 0 {
2912 continue
2913 }
2914 relocTarget[off] = syms[idx-1].Name
2915 }
2916
2917 ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, symAddr: symAddr, relocTarget: relocTarget})
2918 }
2919
2920 func addsection(ldr *loader.Loader, arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
2921 sect := ldr.NewSection()
2922 sect.Rwx = uint8(rwx)
2923 sect.Name = name
2924 sect.Seg = seg
2925 sect.Align = int32(arch.PtrSize)
2926 seg.Sections = append(seg.Sections, sect)
2927 return sect
2928 }
2929
2930 func usage() {
2931 fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
2932 objabi.Flagprint(os.Stderr)
2933 Exit(2)
2934 }
2935
2936 type SymbolType int8
2937
2938 const (
2939
2940 TextSym SymbolType = 'T'
2941 DataSym SymbolType = 'D'
2942 BSSSym SymbolType = 'B'
2943 UndefinedSym SymbolType = 'U'
2944 TLSSym SymbolType = 't'
2945 FrameSym SymbolType = 'm'
2946 ParamSym SymbolType = 'p'
2947 AutoSym SymbolType = 'a'
2948
2949
2950 DeletedAutoSym = 'x'
2951 )
2952
2953
2954 func (ctxt *Link) defineInternal(p string, t sym.SymKind) loader.Sym {
2955 s := ctxt.loader.CreateSymForUpdate(p, 0)
2956 s.SetType(t)
2957 s.SetSpecial(true)
2958 s.SetLocal(true)
2959 return s.Sym()
2960 }
2961
2962 func (ctxt *Link) xdefine(p string, t sym.SymKind, v int64) loader.Sym {
2963 s := ctxt.defineInternal(p, t)
2964 ctxt.loader.SetSymValue(s, v)
2965 return s
2966 }
2967
2968 func datoff(ldr *loader.Loader, s loader.Sym, addr int64) int64 {
2969 if uint64(addr) >= Segdata.Vaddr {
2970 return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
2971 }
2972 if uint64(addr) >= Segtext.Vaddr {
2973 return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
2974 }
2975 ldr.Errorf(s, "invalid datoff %#x", addr)
2976 return 0
2977 }
2978
2979 func Entryvalue(ctxt *Link) int64 {
2980 a := *flagEntrySymbol
2981 if a[0] >= '0' && a[0] <= '9' {
2982 return atolwhex(a)
2983 }
2984 ldr := ctxt.loader
2985 s := ldr.Lookup(a, 0)
2986 if s == 0 {
2987 Errorf("missing entry symbol %q", a)
2988 return 0
2989 }
2990 st := ldr.SymType(s)
2991 if st == 0 {
2992 return *FlagTextAddr
2993 }
2994 if !ctxt.IsAIX() && !st.IsText() {
2995 ldr.Errorf(s, "entry not text")
2996 }
2997 return ldr.SymValue(s)
2998 }
2999
3000 func (ctxt *Link) callgraph() {
3001 if !*FlagC {
3002 return
3003 }
3004
3005 ldr := ctxt.loader
3006 for _, s := range ctxt.Textp {
3007 relocs := ldr.Relocs(s)
3008 for i := 0; i < relocs.Count(); i++ {
3009 r := relocs.At(i)
3010 rs := r.Sym()
3011 if rs == 0 {
3012 continue
3013 }
3014 if r.Type().IsDirectCall() && ldr.SymType(rs).IsText() {
3015 ctxt.Logf("%s calls %s\n", ldr.SymName(s), ldr.SymName(rs))
3016 }
3017 }
3018 }
3019 }
3020
3021 func Rnd(v int64, r int64) int64 {
3022 if r <= 0 {
3023 return v
3024 }
3025 v += r - 1
3026 c := v % r
3027 if c < 0 {
3028 c += r
3029 }
3030 v -= c
3031 return v
3032 }
3033
3034 func bgetc(r *bio.Reader) int {
3035 c, err := r.ReadByte()
3036 if err != nil {
3037 if err != io.EOF {
3038 log.Fatalf("reading input: %v", err)
3039 }
3040 return -1
3041 }
3042 return int(c)
3043 }
3044
3045 type markKind uint8
3046 const (
3047 _ markKind = iota
3048 visiting
3049 visited
3050 )
3051
3052 func postorder(libs []*sym.Library) []*sym.Library {
3053 order := make([]*sym.Library, 0, len(libs))
3054 mark := make(map[*sym.Library]markKind, len(libs))
3055 for _, lib := range libs {
3056 dfs(lib, mark, &order)
3057 }
3058 return order
3059 }
3060
3061 func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library) {
3062 if mark[lib] == visited {
3063 return
3064 }
3065 if mark[lib] == visiting {
3066 panic("found import cycle while visiting " + lib.Pkg)
3067 }
3068 mark[lib] = visiting
3069 for _, i := range lib.Imports {
3070 dfs(i, mark, order)
3071 }
3072 mark[lib] = visited
3073 *order = append(*order, lib)
3074 }
3075
3076 func ElfSymForReloc(ctxt *Link, s loader.Sym) int32 {
3077
3078
3079 les := ctxt.loader.SymLocalElfSym(s)
3080 if les != 0 {
3081 return les
3082 } else {
3083 return ctxt.loader.SymElfSym(s)
3084 }
3085 }
3086
3087 func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, elfRelocTyp uint32) {
3088 if ldr.SymGot(s) >= 0 {
3089 return
3090 }
3091
3092 Adddynsym(ldr, target, syms, s)
3093 got := ldr.MakeSymbolUpdater(syms.GOT)
3094 ldr.SetGot(s, int32(got.Size()))
3095 got.AddUint(target.Arch, 0)
3096
3097 if target.IsElf() {
3098 if target.Arch.PtrSize == 8 {
3099 rela := ldr.MakeSymbolUpdater(syms.Rela)
3100 rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
3101 rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
3102 rela.AddUint64(target.Arch, 0)
3103 } else {
3104 rel := ldr.MakeSymbolUpdater(syms.Rel)
3105 rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
3106 rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), elfRelocTyp))
3107 }
3108 } else if target.IsDarwin() {
3109 leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
3110 leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
3111 if target.IsPIE() && target.IsInternal() {
3112
3113
3114
3115 MachoAddBind(syms.GOT, int64(ldr.SymGot(s)), s)
3116 }
3117 } else {
3118 ldr.Errorf(s, "addgotsym: unsupported binary format")
3119 }
3120 }
3121
3122 var hostobjcounter int
3123
3124
3125
3126
3127
3128
3129 func captureHostObj(h *Hostobj) {
3130
3131 ofile := fmt.Sprintf("captured-obj-%d.o", hostobjcounter)
3132 ifile := fmt.Sprintf("captured-obj-%d.txt", hostobjcounter)
3133 hostobjcounter++
3134 opath := filepath.Join(*flagCaptureHostObjs, ofile)
3135 ipath := filepath.Join(*flagCaptureHostObjs, ifile)
3136
3137
3138 info := fmt.Sprintf("pkg: %s\npn: %s\nfile: %s\noff: %d\nlen: %d\n",
3139 h.pkg, h.pn, h.file, h.off, h.length)
3140 if err := os.WriteFile(ipath, []byte(info), 0666); err != nil {
3141 log.Fatalf("error writing captured host obj info %s: %v", ipath, err)
3142 }
3143
3144 readObjData := func() []byte {
3145 inf, err := os.Open(h.file)
3146 if err != nil {
3147 log.Fatalf("capturing host obj: open failed on %s: %v", h.pn, err)
3148 }
3149 defer inf.Close()
3150 res := make([]byte, h.length)
3151 if n, err := inf.ReadAt(res, h.off); err != nil || n != int(h.length) {
3152 log.Fatalf("capturing host obj: readat failed on %s: %v", h.pn, err)
3153 }
3154 return res
3155 }
3156
3157
3158 if err := os.WriteFile(opath, readObjData(), 0666); err != nil {
3159 log.Fatalf("error writing captured host object %s: %v", opath, err)
3160 }
3161
3162 fmt.Fprintf(os.Stderr, "link: info: captured host object %s to %s\n",
3163 h.file, opath)
3164 }
3165
3166
3167
3168
3169 func (ctxt *Link) findExtLinkTool(toolname string) string {
3170 var cc []string
3171 cc = append(cc, ctxt.extld()...)
3172 cc = append(cc, hostlinkArchArgs(ctxt.Arch)...)
3173 cc = append(cc, "--print-prog-name", toolname)
3174 out, err := exec.Command(cc[0], cc[1:]...).CombinedOutput()
3175 if err != nil {
3176 Exitf("%s: finding %s failed: %v\n%s", os.Args[0], toolname, err, out)
3177 }
3178 cmdpath := strings.TrimRight(string(out), "\r\n")
3179 return cmdpath
3180 }
3181
3182
3183
3184 func (ctxt *Link) isMSVC() bool {
3185 extld := ctxt.extld()
3186 name, args := extld[0], extld[1:]
3187 args = append(args, trimLinkerArgv(flagExtldflags)...)
3188 args = append(args, "--version")
3189 cmd := exec.Command(name, args...)
3190 if out, err := cmd.CombinedOutput(); err == nil {
3191 if bytes.Contains(out, []byte("-msvc\n")) || bytes.Contains(out, []byte("-msvc\r")) {
3192 return true
3193 }
3194 }
3195 return false
3196 }
3197
3198
3199 func (ctxt *Link) isLLD() bool {
3200 extld := ctxt.extld()
3201 name, args := extld[0], extld[1:]
3202 args = append(args, trimLinkerArgv(flagExtldflags)...)
3203 args = append(args, "-Wl,--version")
3204 cmd := exec.Command(name, args...)
3205 if out, err := cmd.CombinedOutput(); err == nil {
3206 if bytes.Contains(out, []byte("LLD ")) {
3207 return true
3208 }
3209 }
3210 return false
3211 }
3212
View as plain text