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