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