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