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