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