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