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