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 "internal/platform"
42 "io"
43 "log"
44 "os"
45 "os/exec"
46 "path/filepath"
47 "runtime"
48 "slices"
49 "sort"
50 "strings"
51 "sync"
52 "time"
53
54 "cmd/internal/bio"
55 "cmd/internal/goobj"
56 "cmd/internal/hash"
57 "cmd/internal/objabi"
58 "cmd/internal/sys"
59 "cmd/link/internal/loadelf"
60 "cmd/link/internal/loader"
61 "cmd/link/internal/loadmacho"
62 "cmd/link/internal/loadpe"
63 "cmd/link/internal/loadxcoff"
64 "cmd/link/internal/sym"
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
102 type ArchSyms struct {
103 Rel loader.Sym
104 Rela loader.Sym
105 RelPLT loader.Sym
106 RelaPLT loader.Sym
107
108 LinkEditGOT loader.Sym
109 LinkEditPLT loader.Sym
110
111 TOC loader.Sym
112 DotTOC []loader.Sym
113
114 GOT loader.Sym
115 PLT loader.Sym
116 GOTPLT loader.Sym
117
118 Tlsg loader.Sym
119 Tlsoffset int
120
121 Dynamic loader.Sym
122 DynSym loader.Sym
123 DynStr loader.Sym
124
125 unreachableMethod loader.Sym
126
127
128
129 mainInittasks loader.Sym
130 }
131
132
133 func (ctxt *Link) mkArchSym(name string, ver int, ls *loader.Sym) {
134 *ls = ctxt.loader.LookupOrCreateSym(name, ver)
135 ctxt.loader.SetAttrReachable(*ls, true)
136 }
137
138
139
140 func (ctxt *Link) mkArchSymVec(name string, ver int, ls []loader.Sym) {
141 ls[ver] = ctxt.loader.LookupOrCreateSym(name, ver)
142 ctxt.loader.SetAttrReachable(ls[ver], true)
143 }
144
145
146
147 func (ctxt *Link) setArchSyms() {
148 ctxt.mkArchSym(".got", 0, &ctxt.GOT)
149 ctxt.mkArchSym(".plt", 0, &ctxt.PLT)
150 ctxt.mkArchSym(".got.plt", 0, &ctxt.GOTPLT)
151 ctxt.mkArchSym(".dynamic", 0, &ctxt.Dynamic)
152 ctxt.mkArchSym(".dynsym", 0, &ctxt.DynSym)
153 ctxt.mkArchSym(".dynstr", 0, &ctxt.DynStr)
154 ctxt.mkArchSym("runtime.unreachableMethod", abiInternalVer, &ctxt.unreachableMethod)
155
156 if ctxt.IsPPC64() {
157 ctxt.mkArchSym("TOC", 0, &ctxt.TOC)
158
159 ctxt.DotTOC = make([]loader.Sym, ctxt.MaxVersion()+1)
160 for i := 0; i <= ctxt.MaxVersion(); i++ {
161 if i >= sym.SymVerABICount && i < sym.SymVerStatic {
162 continue
163 }
164 ctxt.mkArchSymVec(".TOC.", i, ctxt.DotTOC)
165 }
166 }
167 if ctxt.IsElf() {
168 ctxt.mkArchSym(".rel", 0, &ctxt.Rel)
169 ctxt.mkArchSym(".rela", 0, &ctxt.Rela)
170 ctxt.mkArchSym(".rel.plt", 0, &ctxt.RelPLT)
171 ctxt.mkArchSym(".rela.plt", 0, &ctxt.RelaPLT)
172 }
173 if ctxt.IsDarwin() {
174 ctxt.mkArchSym(".linkedit.got", 0, &ctxt.LinkEditGOT)
175 ctxt.mkArchSym(".linkedit.plt", 0, &ctxt.LinkEditPLT)
176 }
177 }
178
179 type Arch struct {
180 Funcalign int
181 Maxalign int
182 Minalign int
183 Dwarfregsp int
184 Dwarfreglr int
185
186
187
188
189
190 TrampLimit uint64
191
192
193
194
195
196 CodePad []byte
197
198
199 Plan9Magic uint32
200 Plan9_64Bit bool
201
202 Adddynrel func(*Target, *loader.Loader, *ArchSyms, loader.Sym, loader.Reloc, int) bool
203 Archinit func(*Link)
204
205
206
207
208
209
210
211
212
213
214 Archreloc func(*Target, *loader.Loader, *ArchSyms, loader.Reloc, loader.Sym,
215 int64) (relocatedOffset int64, nExtReloc int, ok bool)
216
217
218
219
220
221
222
223
224 Archrelocvariant func(target *Target, ldr *loader.Loader, rel loader.Reloc,
225 rv sym.RelocVariant, sym loader.Sym, offset int64, data []byte) (relocatedOffset int64)
226
227
228
229 Trampoline func(ctxt *Link, ldr *loader.Loader, ri int, rs, s loader.Sym)
230
231
232
233
234
235
236
237
238 Asmb func(*Link, *loader.Loader)
239 Asmb2 func(*Link, *loader.Loader)
240
241
242
243
244 Extreloc func(*Target, *loader.Loader, loader.Reloc, loader.Sym) (loader.ExtReloc, bool)
245
246 Gentext func(*Link, *loader.Loader)
247 Machoreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
248 MachorelocSize uint32
249 PEreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
250 Xcoffreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
251
252
253
254 GenSymsLate func(*Link, *loader.Loader)
255
256
257
258
259
260
261
262 TLSIEtoLE func(P []byte, off, size int)
263
264
265 AssignAddress func(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, va uint64, isTramp bool) (*sym.Section, int, uint64)
266
267
268 ELF ELFArch
269 }
270
271 var (
272 thearch Arch
273 lcSize int32
274 rpath Rpath
275 spSize int32
276 symSize int32
277 )
278
279
280
281 var abiInternalVer = sym.SymVerABIInternal
282
283
284
285 func (ctxt *Link) DynlinkingGo() bool {
286 if !ctxt.Loaded {
287 panic("DynlinkingGo called before all symbols loaded")
288 }
289 return ctxt.BuildMode == BuildModeShared || ctxt.linkShared || ctxt.BuildMode == BuildModePlugin || ctxt.canUsePlugins
290 }
291
292
293 func (ctxt *Link) CanUsePlugins() bool {
294 if !ctxt.Loaded {
295 panic("CanUsePlugins called before all symbols loaded")
296 }
297 return ctxt.canUsePlugins
298 }
299
300
301 func (ctxt *Link) NeedCodeSign() bool {
302 return ctxt.IsDarwin() && ctxt.IsARM64()
303 }
304
305 var (
306 dynlib []string
307 ldflag []string
308 havedynamic int
309 Funcalign int
310 iscgo bool
311 elfglobalsymndx int
312 interpreter string
313
314 debug_s bool
315 HEADR int32
316
317 nerrors int
318 liveness int64
319
320
321 checkStrictDups int
322 strictDupMsgCount int
323 )
324
325 var (
326 Segtext sym.Segment
327 Segrodata sym.Segment
328 Segrelrodata sym.Segment
329 Segdata sym.Segment
330 Segdwarf sym.Segment
331 Segpdata sym.Segment
332 Segxdata sym.Segment
333
334 Segments = []*sym.Segment{&Segtext, &Segrodata, &Segrelrodata, &Segdata, &Segdwarf, &Segpdata, &Segxdata}
335 )
336
337 const pkgdef = "__.PKGDEF"
338
339 var (
340
341
342
343 externalobj = false
344
345
346
347
348 dynimportfail []string
349
350
351
352
353
354 preferlinkext []string
355
356
357
358 unknownObjFormat = false
359
360 theline string
361 )
362
363 func Lflag(ctxt *Link, arg string) {
364 ctxt.Libdir = append(ctxt.Libdir, arg)
365 }
366
367
373 func mayberemoveoutfile() {
374 if fi, err := os.Lstat(*flagOutfile); err == nil && !fi.Mode().IsRegular() {
375 return
376 }
377 os.Remove(*flagOutfile)
378 }
379
380 func libinit(ctxt *Link) {
381 if *FlagFuncAlign != 0 {
382 Funcalign = *FlagFuncAlign
383 } else {
384 Funcalign = thearch.Funcalign
385 }
386
387
388 suffix := ""
389
390 suffixsep := ""
391 if *flagInstallSuffix != "" {
392 suffixsep = "_"
393 suffix = *flagInstallSuffix
394 } else if *flagRace {
395 suffixsep = "_"
396 suffix = "race"
397 } else if *flagMsan {
398 suffixsep = "_"
399 suffix = "msan"
400 } else if *flagAsan {
401 suffixsep = "_"
402 suffix = "asan"
403 }
404
405 if buildcfg.GOROOT != "" {
406 Lflag(ctxt, filepath.Join(buildcfg.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", buildcfg.GOOS, buildcfg.GOARCH, suffixsep, suffix)))
407 }
408
409 mayberemoveoutfile()
410
411 if err := ctxt.Out.Open(*flagOutfile); err != nil {
412 Exitf("cannot create %s: %v", *flagOutfile, err)
413 }
414
415 if *flagEntrySymbol == "" {
416 switch ctxt.BuildMode {
417 case BuildModeCShared, BuildModeCArchive:
418 *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s_lib", buildcfg.GOARCH, buildcfg.GOOS)
419 case BuildModeExe, BuildModePIE:
420 *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s", buildcfg.GOARCH, buildcfg.GOOS)
421 case BuildModeShared, BuildModePlugin:
422
423 default:
424 Errorf("unknown *flagEntrySymbol for buildmode %v", ctxt.BuildMode)
425 }
426 }
427 }
428
429 func exitIfErrors() {
430 if nerrors != 0 || checkStrictDups > 1 && strictDupMsgCount > 0 {
431 mayberemoveoutfile()
432 Exit(2)
433 }
434
435 }
436
437 func errorexit() {
438 exitIfErrors()
439 Exit(0)
440 }
441
442 func loadinternal(ctxt *Link, name string) *sym.Library {
443 zerofp := goobj.FingerprintType{}
444 if ctxt.linkShared && ctxt.PackageShlib != nil {
445 if shlib := ctxt.PackageShlib[name]; shlib != "" {
446 return addlibpath(ctxt, "internal", "internal", "", name, shlib, zerofp)
447 }
448 }
449 if ctxt.PackageFile != nil {
450 if pname := ctxt.PackageFile[name]; pname != "" {
451 return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
452 }
453 ctxt.Logf("loadinternal: cannot find %s\n", name)
454 return nil
455 }
456
457 for _, libdir := range ctxt.Libdir {
458 if ctxt.linkShared {
459 shlibname := filepath.Join(libdir, name+".shlibname")
460 if ctxt.Debugvlog != 0 {
461 ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
462 }
463 if _, err := os.Stat(shlibname); err == nil {
464 return addlibpath(ctxt, "internal", "internal", "", name, shlibname, zerofp)
465 }
466 }
467 pname := filepath.Join(libdir, name+".a")
468 if ctxt.Debugvlog != 0 {
469 ctxt.Logf("searching for %s.a in %s\n", name, pname)
470 }
471 if _, err := os.Stat(pname); err == nil {
472 return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
473 }
474 }
475
476 if name == "runtime" {
477 Exitf("error: unable to find runtime.a")
478 }
479 ctxt.Logf("warning: unable to find %s.a\n", name)
480 return nil
481 }
482
483
484 func (ctxt *Link) extld() []string {
485 if len(flagExtld) == 0 {
486
487
488
489 switch buildcfg.GOOS {
490 case "darwin", "freebsd", "openbsd":
491 flagExtld = []string{"clang"}
492 default:
493 flagExtld = []string{"gcc"}
494 }
495 }
496 return flagExtld
497 }
498
499
500
501 func (ctxt *Link) findLibPathCmd(cmd, libname string) string {
502 extld := ctxt.extld()
503 name, args := extld[0], extld[1:]
504 args = append(args, hostlinkArchArgs(ctxt.Arch)...)
505 args = append(args, cmd)
506 if ctxt.Debugvlog != 0 {
507 ctxt.Logf("%s %v\n", extld, args)
508 }
509 out, err := exec.Command(name, args...).Output()
510 if err != nil {
511 if ctxt.Debugvlog != 0 {
512 ctxt.Logf("not using a %s file because compiler failed\n%v\n%s\n", libname, err, out)
513 }
514 return "none"
515 }
516 return strings.TrimSpace(string(out))
517 }
518
519
520
521 func (ctxt *Link) findLibPath(libname string) string {
522 return ctxt.findLibPathCmd("--print-file-name="+libname, libname)
523 }
524
525 func (ctxt *Link) loadlib() {
526 var flags uint32
527 if *flagCheckLinkname {
528 flags |= loader.FlagCheckLinkname
529 }
530 switch *FlagStrictDups {
531 case 0:
532
533 case 1, 2:
534 flags |= loader.FlagStrictDups
535 default:
536 log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
537 }
538 ctxt.loader = loader.NewLoader(flags, &ctxt.ErrorReporter.ErrorReporter)
539 ctxt.ErrorReporter.SymName = func(s loader.Sym) string {
540 return ctxt.loader.SymName(s)
541 }
542
543
544 i := 0
545 for ; i < len(ctxt.Library); i++ {
546 lib := ctxt.Library[i]
547 if lib.Shlib == "" {
548 if ctxt.Debugvlog > 1 {
549 ctxt.Logf("autolib: %s (from %s)\n", lib.File, lib.Objref)
550 }
551 loadobjfile(ctxt, lib)
552 }
553 }
554
555
556 if *flagRace {
557 loadinternal(ctxt, "runtime/race")
558 }
559 if *flagMsan {
560 loadinternal(ctxt, "runtime/msan")
561 }
562 if *flagAsan {
563 loadinternal(ctxt, "runtime/asan")
564 }
565 loadinternal(ctxt, "runtime")
566 for ; i < len(ctxt.Library); i++ {
567 lib := ctxt.Library[i]
568 if lib.Shlib == "" {
569 loadobjfile(ctxt, lib)
570 }
571 }
572
573
574
575
576 iscgo = ctxt.LibraryByPkg["runtime/cgo"] != nil
577
578
579
580 ctxt.canUsePlugins = ctxt.LibraryByPkg["plugin"] != nil && iscgo &&
581 platform.BuildModeSupported("gc", "plugin", buildcfg.GOOS, buildcfg.GOARCH)
582
583
584 determineLinkMode(ctxt)
585
586 if ctxt.LinkMode == LinkExternal && !iscgo && !(buildcfg.GOOS == "darwin" && ctxt.BuildMode != BuildModePlugin && ctxt.Arch.Family == sys.AMD64) {
587
588
589
590
591 if lib := loadinternal(ctxt, "runtime/cgo"); lib != nil && lib.Shlib == "" {
592 if ctxt.BuildMode == BuildModeShared || ctxt.linkShared {
593 Exitf("cannot implicitly include runtime/cgo in a shared library")
594 }
595 for ; i < len(ctxt.Library); i++ {
596 lib := ctxt.Library[i]
597 if lib.Shlib == "" {
598 loadobjfile(ctxt, lib)
599 }
600 }
601 }
602 }
603
604
605 ctxt.loader.LoadSyms(ctxt.Arch)
606
607
608 for _, lib := range ctxt.Library {
609 if lib.Shlib != "" {
610 if ctxt.Debugvlog > 1 {
611 ctxt.Logf("autolib: %s (from %s)\n", lib.Shlib, lib.Objref)
612 }
613 ldshlibsyms(ctxt, lib.Shlib)
614 }
615 }
616
617
618 ctxt.loadcgodirectives()
619
620
621 hostobjs(ctxt)
622 hostlinksetup(ctxt)
623
624 if ctxt.LinkMode == LinkInternal && len(hostobj) != 0 {
625
626
627 any := false
628 undefs, froms := ctxt.loader.UndefinedRelocTargets(1)
629 if len(undefs) > 0 {
630 any = true
631 if ctxt.Debugvlog > 1 {
632 ctxt.Logf("loadlib: first unresolved is %s [%d] from %s [%d]\n",
633 ctxt.loader.SymName(undefs[0]), undefs[0],
634 ctxt.loader.SymName(froms[0]), froms[0])
635 }
636 }
637 if any {
638 if *flagLibGCC == "" {
639 *flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc")
640 }
641 if runtime.GOOS == "freebsd" && strings.HasPrefix(filepath.Base(*flagLibGCC), "libclang_rt.builtins") {
642
643
644
645
646 *flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
647 }
648 if runtime.GOOS == "openbsd" && *flagLibGCC == "libgcc.a" {
649
650
651
652 *flagLibGCC = ctxt.findLibPathCmd("--print-file-name=libcompiler_rt.a", "libcompiler_rt")
653 }
654 if ctxt.HeadType == objabi.Hwindows {
655 loadWindowsHostArchives(ctxt)
656 }
657 if *flagLibGCC != "none" {
658 hostArchive(ctxt, *flagLibGCC)
659 }
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676 isunresolved := symbolsAreUnresolved(ctxt, []string{"__stack_chk_fail_local"})
677 if isunresolved[0] {
678 if p := ctxt.findLibPath("libc_nonshared.a"); p != "none" {
679 hostArchive(ctxt, p)
680 }
681 if p := ctxt.findLibPath("libssp_nonshared.a"); p != "none" {
682 hostArchive(ctxt, p)
683 }
684 }
685 }
686 }
687
688 loadfips(ctxt)
689
690
691 ctxt.Loaded = true
692
693 strictDupMsgCount = ctxt.loader.NStrictDupMsgs()
694 }
695
696
697
698
699
700
701
702
703 func loadWindowsHostArchives(ctxt *Link) {
704 any := true
705 for i := 0; any && i < 2; i++ {
706
707
708 isunresolved := symbolsAreUnresolved(ctxt, []string{"atexit"})
709 if isunresolved[0] {
710 if p := ctxt.findLibPath("crt2.o"); p != "none" {
711 hostObject(ctxt, "crt2", p)
712 }
713 }
714 if *flagRace {
715 if p := ctxt.findLibPath("libsynchronization.a"); p != "none" {
716 hostArchive(ctxt, p)
717 }
718 }
719 if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
720 hostArchive(ctxt, p)
721 }
722 if p := ctxt.findLibPath("libmingw32.a"); p != "none" {
723 hostArchive(ctxt, p)
724 }
725
726
727 if p := ctxt.findLibPath("libmsvcrt.a"); p != "none" {
728 hostArchive(ctxt, p)
729 }
730 any = false
731 undefs, froms := ctxt.loader.UndefinedRelocTargets(1)
732 if len(undefs) > 0 {
733 any = true
734 if ctxt.Debugvlog > 1 {
735 ctxt.Logf("loadWindowsHostArchives: remaining unresolved is %s [%d] from %s [%d]\n",
736 ctxt.loader.SymName(undefs[0]), undefs[0],
737 ctxt.loader.SymName(froms[0]), froms[0])
738 }
739 }
740 }
741
742
743
744
745 want := []string{"__CTOR_LIST__", "__DTOR_LIST__"}
746 isunresolved := symbolsAreUnresolved(ctxt, want)
747 for k, w := range want {
748 if isunresolved[k] {
749 sb := ctxt.loader.CreateSymForUpdate(w, 0)
750 sb.SetType(sym.SDATA)
751 sb.AddUint64(ctxt.Arch, 0)
752 sb.SetReachable(true)
753 ctxt.loader.SetAttrSpecial(sb.Sym(), true)
754 }
755 }
756
757
758
759 if err := loadpe.PostProcessImports(); err != nil {
760 Errorf("%v", err)
761 }
762
763
764
765
766
772 }
773
774
775
776 func (ctxt *Link) loadcgodirectives() {
777 l := ctxt.loader
778 hostObjSyms := make(map[loader.Sym]struct{})
779 for _, d := range ctxt.cgodata {
780 setCgoAttr(ctxt, d.file, d.pkg, d.directives, hostObjSyms)
781 }
782 ctxt.cgodata = nil
783
784 if ctxt.LinkMode == LinkInternal {
785
786
787 for symIdx := range hostObjSyms {
788 if l.SymType(symIdx) == sym.SHOSTOBJ {
789
790
791
792
793 su := l.MakeSymbolUpdater(symIdx)
794 if l.SymExtname(symIdx) != "" && l.SymDynimplib(symIdx) != "" && !(l.AttrCgoExportStatic(symIdx) || l.AttrCgoExportDynamic(symIdx)) {
795 su.SetType(sym.SDYNIMPORT)
796 } else {
797 su.SetType(0)
798 }
799 }
800 }
801 }
802 }
803
804
805
806 func (ctxt *Link) linksetup() {
807 switch ctxt.BuildMode {
808 case BuildModeCShared, BuildModePlugin:
809 symIdx := ctxt.loader.LookupOrCreateSym("runtime.islibrary", 0)
810 sb := ctxt.loader.MakeSymbolUpdater(symIdx)
811 sb.SetType(sym.SNOPTRDATA)
812 sb.AddUint8(1)
813 case BuildModeCArchive:
814 symIdx := ctxt.loader.LookupOrCreateSym("runtime.isarchive", 0)
815 sb := ctxt.loader.MakeSymbolUpdater(symIdx)
816 sb.SetType(sym.SNOPTRDATA)
817 sb.AddUint8(1)
818 }
819
820
821 if ctxt.HeadType == objabi.Hwindows {
822 Peinit(ctxt)
823 }
824
825 if ctxt.LinkMode == LinkExternal {
826
827
828 *FlagTextAddr = 0
829 }
830
831
832
833
834
835
836
837
838
839
840
841 if ctxt.BuildMode == BuildModeExe {
842 if havedynamic == 0 && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Hsolaris {
843 *FlagD = true
844 }
845 }
846
847 if ctxt.LinkMode == LinkExternal && ctxt.Arch.Family == sys.PPC64 && buildcfg.GOOS != "aix" {
848 toc := ctxt.loader.LookupOrCreateSym(".TOC.", 0)
849 sb := ctxt.loader.MakeSymbolUpdater(toc)
850 sb.SetType(sym.SDYNIMPORT)
851 }
852
853
854
855
856 if buildcfg.GOOS != "android" {
857 tlsg := ctxt.loader.LookupOrCreateSym("runtime.tlsg", 0)
858 sb := ctxt.loader.MakeSymbolUpdater(tlsg)
859
860
861
862 if sb.Type() == 0 {
863 sb.SetType(sym.STLSBSS)
864 sb.SetSize(int64(ctxt.Arch.PtrSize))
865 } else if sb.Type() != sym.SDYNIMPORT {
866 Errorf("runtime declared tlsg variable %v", sb.Type())
867 }
868 ctxt.loader.SetAttrReachable(tlsg, true)
869 ctxt.Tlsg = tlsg
870 }
871
872 var moduledata loader.Sym
873 var mdsb *loader.SymbolBuilder
874 if ctxt.BuildMode == BuildModePlugin {
875 moduledata = ctxt.loader.LookupOrCreateSym("local.pluginmoduledata", 0)
876 mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
877 ctxt.loader.SetAttrLocal(moduledata, true)
878 } else {
879 moduledata = ctxt.loader.LookupOrCreateSym("runtime.firstmoduledata", 0)
880 mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
881 }
882 if mdsb.Type() != 0 && mdsb.Type() != sym.SDYNIMPORT {
883
884
885
886
887
888 mdsb.SetSize(0)
889
890
891
892 if ctxt.Arch.Family == sys.ARM {
893 goarm := ctxt.loader.LookupOrCreateSym("runtime.goarm", 0)
894 sb := ctxt.loader.MakeSymbolUpdater(goarm)
895 sb.SetType(sym.SNOPTRDATA)
896 sb.SetSize(0)
897 sb.AddUint8(uint8(buildcfg.GOARM.Version))
898
899 goarmsoftfp := ctxt.loader.LookupOrCreateSym("runtime.goarmsoftfp", 0)
900 sb2 := ctxt.loader.MakeSymbolUpdater(goarmsoftfp)
901 sb2.SetType(sym.SNOPTRDATA)
902 sb2.SetSize(0)
903 if buildcfg.GOARM.SoftFloat {
904 sb2.AddUint8(1)
905 } else {
906 sb2.AddUint8(0)
907 }
908 }
909
910
911
912
913 memProfile := ctxt.loader.Lookup("runtime.memProfileInternal", abiInternalVer)
914 if memProfile != 0 && !ctxt.loader.AttrReachable(memProfile) && !ctxt.DynlinkingGo() {
915 memProfSym := ctxt.loader.LookupOrCreateSym("runtime.disableMemoryProfiling", 0)
916 sb := ctxt.loader.MakeSymbolUpdater(memProfSym)
917 sb.SetType(sym.SNOPTRDATA)
918 sb.SetSize(0)
919 sb.AddUint8(1)
920 }
921 } else {
922
923
924 moduledata = ctxt.loader.LookupOrCreateSym("local.moduledata", 0)
925 mdsb = ctxt.loader.MakeSymbolUpdater(moduledata)
926 ctxt.loader.SetAttrLocal(moduledata, true)
927 }
928 mdsb.SetType(sym.SMODULEDATA)
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 *flagRace {
1492
1493
1494
1495 argv = append(argv, "-Wl,-U,__dyld_get_dyld_header")
1496 }
1497 if *flagHostBuildid == "none" {
1498 argv = append(argv, "-Wl,-no_uuid")
1499 }
1500 case objabi.Hopenbsd:
1501 argv = append(argv, "-pthread")
1502 if ctxt.BuildMode != BuildModePIE {
1503 argv = append(argv, "-Wl,-nopie")
1504 }
1505 if linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,-z,nobtcfi") {
1506
1507
1508 argv = append(argv, "-Wl,-z,nobtcfi")
1509 }
1510 if ctxt.Arch.InFamily(sys.ARM64) {
1511
1512
1513
1514 argv = append(argv, "-Wl,--no-execute-only")
1515 }
1516 case objabi.Hwindows:
1517 isMSVC = ctxt.isMSVC()
1518 if isMSVC {
1519
1520
1521
1522
1523 wlPrefix = "-Wl,-"
1524 }
1525
1526 if windowsgui {
1527 argv = append(argv, "-mwindows")
1528 } else {
1529 argv = append(argv, "-mconsole")
1530 }
1531
1532
1533
1534 argv = append(argv, wlPrefix+"tsaware")
1535
1536
1537 argv = append(argv, wlPrefix+"nxcompat")
1538
1539 if !isMSVC {
1540 argv = append(argv, fmt.Sprintf("-Wl,--major-os-version=%d", PeMinimumTargetMajorVersion))
1541 argv = append(argv, fmt.Sprintf("-Wl,--minor-os-version=%d", PeMinimumTargetMinorVersion))
1542 argv = append(argv, fmt.Sprintf("-Wl,--major-subsystem-version=%d", PeMinimumTargetMajorVersion))
1543 argv = append(argv, fmt.Sprintf("-Wl,--minor-subsystem-version=%d", PeMinimumTargetMinorVersion))
1544 }
1545 case objabi.Haix:
1546 argv = append(argv, "-pthread")
1547
1548
1549 argv = append(argv, "-Wl,-bnoobjreorder")
1550
1551
1552 argv = append(argv, "-mcmodel=large")
1553 argv = append(argv, "-Wl,-bbigtoc")
1554 }
1555
1556
1557
1558
1559 if ctxt.IsPPC64() && ctxt.IsElf() && buildcfg.GOPPC64 >= 10 {
1560 if !linkerFlagSupported(ctxt.Arch, argv[0], "", "-mcpu=power10") {
1561 Exitf("The external toolchain does not support -mcpu=power10. " +
1562 " This is required to externally link GOPPC64 >= power10")
1563 }
1564 }
1565
1566
1567 addASLRargs := func(argv []string, val bool) []string {
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583 var dbopt string
1584 var heopt string
1585 dbon := wlPrefix + "dynamicbase"
1586 heon := wlPrefix + "high-entropy-va"
1587 dboff := wlPrefix + "disable-dynamicbase"
1588 heoff := wlPrefix + "disable-high-entropy-va"
1589 if isMSVC {
1590 heon = wlPrefix + "highentropyva"
1591 heoff = wlPrefix + "highentropyva:no"
1592 dboff = wlPrefix + "dynamicbase:no"
1593 }
1594 if val {
1595 dbopt = dbon
1596 heopt = heon
1597 } else {
1598
1599 newer := linkerFlagSupported(ctxt.Arch, argv[0], "", dboff)
1600 if newer {
1601
1602 dbopt = dboff
1603 heopt = heoff
1604 } else {
1605
1606
1607 dbopt = ""
1608 heopt = ""
1609 }
1610 }
1611 if dbopt != "" {
1612 argv = append(argv, dbopt)
1613 }
1614
1615 if ctxt.Arch.PtrSize >= 8 && heopt != "" {
1616 argv = append(argv, heopt)
1617 }
1618 return argv
1619 }
1620
1621 switch ctxt.BuildMode {
1622 case BuildModeExe:
1623 if ctxt.HeadType == objabi.Hdarwin {
1624 if machoPlatform == PLATFORM_MACOS && ctxt.IsAMD64() {
1625 argv = append(argv, "-Wl,-no_pie")
1626 }
1627 }
1628 if *flagRace && ctxt.HeadType == objabi.Hwindows {
1629
1630
1631
1632
1633 argv = addASLRargs(argv, false)
1634 }
1635 case BuildModePIE:
1636 switch ctxt.HeadType {
1637 case objabi.Hdarwin, objabi.Haix:
1638 case objabi.Hwindows:
1639 if *flagAslr && *flagRace {
1640
1641
1642
1643 *flagAslr = false
1644 }
1645 argv = addASLRargs(argv, *flagAslr)
1646 default:
1647
1648 if ctxt.UseRelro() {
1649 argv = append(argv, "-Wl,-z,relro")
1650 }
1651 argv = append(argv, "-pie")
1652 }
1653 case BuildModeCShared:
1654 if ctxt.HeadType == objabi.Hdarwin {
1655 argv = append(argv, "-dynamiclib")
1656 } else {
1657 if ctxt.UseRelro() {
1658 argv = append(argv, "-Wl,-z,relro")
1659 }
1660 argv = append(argv, "-shared")
1661 if ctxt.HeadType == objabi.Hwindows {
1662 argv = addASLRargs(argv, *flagAslr)
1663 } else {
1664
1665
1666 argv = append(argv, "-Wl,-z,nodelete")
1667
1668 argv = append(argv, "-Wl,-Bsymbolic")
1669 }
1670 }
1671 case BuildModeShared:
1672 if ctxt.UseRelro() {
1673 argv = append(argv, "-Wl,-z,relro")
1674 }
1675 argv = append(argv, "-shared")
1676 case BuildModePlugin:
1677 if ctxt.HeadType == objabi.Hdarwin {
1678 argv = append(argv, "-dynamiclib")
1679 } else {
1680 if ctxt.UseRelro() {
1681 argv = append(argv, "-Wl,-z,relro")
1682 }
1683 argv = append(argv, "-shared")
1684 }
1685 }
1686
1687 var altLinker string
1688 if ctxt.IsELF && (ctxt.DynlinkingGo() || *flagBindNow) {
1689
1690
1691
1692
1693
1694 argv = append(argv, "-Wl,-z,now")
1695 }
1696
1697 if ctxt.IsELF && ctxt.DynlinkingGo() {
1698
1699
1700
1701 argv = append(argv, "-Wl,-z,nocopyreloc")
1702
1703 if buildcfg.GOOS == "android" {
1704
1705 altLinker = "lld"
1706 }
1707
1708 if ctxt.Arch.InFamily(sys.ARM64) && buildcfg.GOOS == "linux" {
1709
1710
1711
1712
1713
1714
1715
1716 useGold := false
1717 name, args := flagExtld[0], flagExtld[1:]
1718 args = append(args, "-Wl,--version")
1719 cmd := exec.Command(name, args...)
1720 if out, err := cmd.CombinedOutput(); err == nil {
1721
1722 for line := range strings.Lines(string(out)) {
1723 if !strings.HasPrefix(line, "GNU ld ") {
1724 continue
1725 }
1726 fields := strings.Fields(line[len("GNU ld "):])
1727 var major, minor int
1728 if ret, err := fmt.Sscanf(fields[len(fields)-1], "%d.%d", &major, &minor); ret == 2 && err == nil {
1729 if major == 2 && minor <= 35 {
1730 useGold = true
1731 }
1732 break
1733 }
1734 }
1735 }
1736
1737 if useGold {
1738
1739 altLinker = "gold"
1740
1741
1742
1743
1744 args = flagExtld[1:]
1745 args = append(args, "-fuse-ld=gold", "-Wl,--version")
1746 cmd = exec.Command(name, args...)
1747 if out, err := cmd.CombinedOutput(); err == nil {
1748 if !bytes.Contains(out, []byte("GNU gold")) {
1749 log.Fatalf("ARM64 external linker must be ld>=2.36 or gold (issue #15696, 22040), but is not: %s", out)
1750 }
1751 }
1752 }
1753 }
1754 }
1755 if ctxt.Arch.Family == sys.ARM64 && buildcfg.GOOS == "freebsd" {
1756
1757 altLinker = "bfd"
1758
1759
1760 name, args := flagExtld[0], flagExtld[1:]
1761 args = append(args, "-fuse-ld=bfd", "-Wl,--version")
1762 cmd := exec.Command(name, args...)
1763 if out, err := cmd.CombinedOutput(); err == nil {
1764 if !bytes.Contains(out, []byte("GNU ld")) {
1765 log.Fatalf("ARM64 external linker must be ld.bfd (issue #35197), please install devel/binutils")
1766 }
1767 }
1768 }
1769 if altLinker != "" {
1770 argv = append(argv, "-fuse-ld="+altLinker)
1771 }
1772
1773 if ctxt.IsELF && linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,--build-id=0x1234567890abcdef") {
1774 if len(buildinfo) > 0 {
1775 argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
1776 } else if *flagHostBuildid == "none" {
1777 argv = append(argv, "-Wl,--build-id=none")
1778 }
1779 }
1780
1781
1782
1783
1784
1785
1786
1787 outopt := *flagOutfile
1788 if buildcfg.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
1789 outopt += "."
1790 }
1791 argv = append(argv, "-o")
1792 argv = append(argv, outopt)
1793
1794 if rpath.val != "" {
1795 argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
1796 }
1797
1798 if *flagInterpreter != "" {
1799
1800
1801
1802
1803 argv = append(argv, fmt.Sprintf("-Wl,--dynamic-linker,%s", *flagInterpreter))
1804 }
1805
1806
1807 switch {
1808 case ctxt.IsELF:
1809 if ctxt.DynlinkingGo() || ctxt.BuildMode == BuildModeCShared || !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "-Wl,--export-dynamic-symbol=main") {
1810 argv = append(argv, "-rdynamic")
1811 } else {
1812 var exports []string
1813 ctxt.loader.ForAllCgoExportDynamic(func(s loader.Sym) {
1814 exports = append(exports, "-Wl,--export-dynamic-symbol="+ctxt.loader.SymExtname(s))
1815 })
1816 sort.Strings(exports)
1817 argv = append(argv, exports...)
1818 }
1819 case ctxt.IsAIX():
1820 fileName := xcoffCreateExportFile(ctxt)
1821 argv = append(argv, "-Wl,-bE:"+fileName)
1822 case ctxt.IsWindows() && !slices.Contains(flagExtldflags, wlPrefix+"export-all-symbols"):
1823 fileName := peCreateExportFile(ctxt, filepath.Base(outopt))
1824 prefix := ""
1825 if isMSVC {
1826 prefix = "-Wl,-def:"
1827 }
1828 argv = append(argv, prefix+fileName)
1829 }
1830
1831 const unusedArguments = "-Qunused-arguments"
1832 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, unusedArguments) {
1833 argv = append(argv, unusedArguments)
1834 }
1835
1836 if ctxt.IsWindows() {
1837
1838
1839
1840
1841 const noTimeStamp = "-Wl,--no-insert-timestamp"
1842 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, noTimeStamp) {
1843 argv = append(argv, noTimeStamp)
1844 }
1845 }
1846
1847 const compressDWARF = "-Wl,--compress-debug-sections=zlib"
1848 if ctxt.compressDWARF && linkerFlagSupported(ctxt.Arch, argv[0], altLinker, compressDWARF) {
1849 argv = append(argv, compressDWARF)
1850 }
1851
1852 hostObjCopyPaths := ctxt.hostobjCopy()
1853 cleanTimeStamps(hostObjCopyPaths)
1854 godotopath := filepath.Join(*flagTmpdir, "go.o")
1855 cleanTimeStamps([]string{godotopath})
1856
1857 argv = append(argv, godotopath)
1858 argv = append(argv, hostObjCopyPaths...)
1859 if ctxt.HeadType == objabi.Haix {
1860
1861
1862 argv = append(argv, "-nostartfiles")
1863 argv = append(argv, "/lib/crt0_64.o")
1864
1865 extld := ctxt.extld()
1866 name, args := extld[0], extld[1:]
1867
1868 getPathFile := func(file string) string {
1869 args := append(args, "-maix64", "--print-file-name="+file)
1870 out, err := exec.Command(name, args...).CombinedOutput()
1871 if err != nil {
1872 log.Fatalf("running %s failed: %v\n%s", extld, err, out)
1873 }
1874 return strings.Trim(string(out), "\n")
1875 }
1876
1877
1878
1879 crtcxa := getPathFile("crtcxa_64.o")
1880 if !filepath.IsAbs(crtcxa) {
1881 crtcxa = getPathFile("crtcxa.o")
1882 }
1883 crtdbase := getPathFile("crtdbase_64.o")
1884 if !filepath.IsAbs(crtdbase) {
1885 crtdbase = getPathFile("crtdbase.o")
1886 }
1887 argv = append(argv, crtcxa)
1888 argv = append(argv, crtdbase)
1889 }
1890
1891 if ctxt.linkShared {
1892 seenDirs := make(map[string]bool)
1893 seenLibs := make(map[string]bool)
1894 addshlib := func(path string) {
1895 dir, base := filepath.Split(path)
1896 if !seenDirs[dir] {
1897 argv = append(argv, "-L"+dir)
1898 if !rpath.set {
1899 argv = append(argv, "-Wl,-rpath="+dir)
1900 }
1901 seenDirs[dir] = true
1902 }
1903 base = strings.TrimSuffix(base, ".so")
1904 base = strings.TrimPrefix(base, "lib")
1905 if !seenLibs[base] {
1906 argv = append(argv, "-l"+base)
1907 seenLibs[base] = true
1908 }
1909 }
1910 for _, shlib := range ctxt.Shlibs {
1911 addshlib(shlib.Path)
1912 for _, dep := range shlib.Deps {
1913 if dep == "" {
1914 continue
1915 }
1916 libpath := findshlib(ctxt, dep)
1917 if libpath != "" {
1918 addshlib(libpath)
1919 }
1920 }
1921 }
1922 }
1923
1924
1925
1926
1927
1928
1929
1930
1931 checkStatic := func(arg string) {
1932 if ctxt.IsELF && arg == "-static" {
1933 for i := range argv {
1934 if argv[i] == "-rdynamic" || strings.HasPrefix(argv[i], "-Wl,--dynamic-linker,") {
1935 argv[i] = "-static"
1936 }
1937 }
1938 }
1939 }
1940
1941 for _, p := range ldflag {
1942 argv = append(argv, p)
1943 checkStatic(p)
1944 }
1945
1946
1947
1948
1949
1950
1951
1952
1953 if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared && !(ctxt.IsDarwin() && ctxt.IsARM64()) {
1954
1955 for _, nopie := range []string{"-no-pie", "-nopie"} {
1956 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, nopie) {
1957 argv = append(argv, nopie)
1958 break
1959 }
1960 }
1961 }
1962
1963 for _, p := range flagExtldflags {
1964 argv = append(argv, p)
1965 checkStatic(p)
1966 }
1967 if ctxt.HeadType == objabi.Hwindows {
1968
1969
1970 extld := ctxt.extld()
1971 name, args := extld[0], extld[1:]
1972 args = append(args, trimLinkerArgv(flagExtldflags)...)
1973 args = append(args, "-Wl,--version")
1974 cmd := exec.Command(name, args...)
1975 usingLLD := false
1976 if out, err := cmd.CombinedOutput(); err == nil {
1977 if bytes.Contains(out, []byte("LLD ")) {
1978 usingLLD = true
1979 }
1980 }
1981
1982
1983
1984 if !usingLLD {
1985 p := writeGDBLinkerScript()
1986 argv = append(argv, "-Wl,-T,"+p)
1987 }
1988 if *flagRace {
1989
1990
1991
1992
1993 if isMSVC || ctxt.findLibPath("libsynchronization.a") != "libsynchronization.a" {
1994 argv = append(argv, "-lsynchronization")
1995 }
1996 }
1997 if !isMSVC {
1998
1999
2000 argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
2001 }
2002 argv = append(argv, peimporteddlls()...)
2003 }
2004
2005 argv = ctxt.passLongArgsInResponseFile(argv, altLinker)
2006
2007 if ctxt.Debugvlog != 0 {
2008 ctxt.Logf("host link:")
2009 for _, v := range argv {
2010 ctxt.Logf(" %q", v)
2011 }
2012 ctxt.Logf("\n")
2013 }
2014
2015 cmd := exec.Command(argv[0], argv[1:]...)
2016 out, err := cmd.CombinedOutput()
2017 if err != nil {
2018 Exitf("running %s failed: %v\n%s\n%s", argv[0], err, cmd, out)
2019 }
2020
2021
2022
2023 var save [][]byte
2024 var skipLines int
2025 for _, line := range bytes.SplitAfter(out, []byte("\n")) {
2026
2027 if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
2028 continue
2029 }
2030
2031 if skipLines > 0 {
2032 skipLines--
2033 continue
2034 }
2035
2036
2037 if bytes.Contains(line, []byte("ld: 0711-783")) {
2038 skipLines = 2
2039 continue
2040 }
2041
2042 save = append(save, line)
2043 }
2044 out = bytes.Join(save, nil)
2045
2046 if len(out) > 0 {
2047
2048
2049 if ctxt.IsDarwin() && ctxt.IsAMD64() {
2050 const noPieWarning = "ld: warning: -no_pie is deprecated when targeting new OS versions\n"
2051 if i := bytes.Index(out, []byte(noPieWarning)); i >= 0 {
2052
2053 out = append(out[:i], out[i+len(noPieWarning):]...)
2054 }
2055 }
2056 if ctxt.IsDarwin() {
2057 const bindAtLoadWarning = "ld: warning: -bind_at_load is deprecated on macOS\n"
2058 if i := bytes.Index(out, []byte(bindAtLoadWarning)); i >= 0 {
2059
2060
2061
2062
2063 out = append(out[:i], out[i+len(bindAtLoadWarning):]...)
2064 }
2065 }
2066 ctxt.Logf("%s", out)
2067 }
2068
2069
2070
2071 updateMachoOutFile := func(op string, updateFunc machoUpdateFunc) {
2072
2073 rewrittenOutput := *flagOutfile + "~"
2074 exef, err := os.Open(*flagOutfile)
2075 if err != nil {
2076 Exitf("%s: %s failed: %v", os.Args[0], op, err)
2077 }
2078 defer exef.Close()
2079 exem, err := macho.NewFile(exef)
2080 if err != nil {
2081 Exitf("%s: parsing Mach-O header failed: %v", os.Args[0], err)
2082 }
2083 if err := updateFunc(ctxt, exef, exem, rewrittenOutput); err != nil {
2084 Exitf("%s: %s failed: %v", os.Args[0], op, err)
2085 }
2086 os.Remove(*flagOutfile)
2087 if err := os.Rename(rewrittenOutput, *flagOutfile); err != nil {
2088 Exitf("%s: %v", os.Args[0], err)
2089 }
2090 }
2091
2092 uuidUpdated := false
2093 if combineDwarf {
2094
2095 dsymutilCmd := ctxt.findExtLinkTool("dsymutil")
2096 stripCmd := ctxt.findExtLinkTool("strip")
2097
2098 dsym := filepath.Join(*flagTmpdir, "go.dwarf")
2099 cmd := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym)
2100
2101
2102
2103
2104
2105 dsymDir := filepath.Join(*flagTmpdir, "dsymutil")
2106 err := os.MkdirAll(dsymDir, 0777)
2107 if err != nil {
2108 Exitf("fail to create temp dir: %v", err)
2109 }
2110 cmd.Env = append(os.Environ(), "DSYMUTIL_REPRODUCER_PATH="+dsymDir)
2111 if ctxt.Debugvlog != 0 {
2112 ctxt.Logf("host link dsymutil:")
2113 for _, v := range cmd.Args {
2114 ctxt.Logf(" %q", v)
2115 }
2116 ctxt.Logf("\n")
2117 }
2118 if out, err := cmd.CombinedOutput(); err != nil {
2119 Exitf("%s: running dsymutil failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
2120 }
2121
2122
2123 var stripArgs = []string{"-S"}
2124 if debug_s {
2125
2126
2127
2128 stripArgs = append(stripArgs, "-x")
2129 }
2130 stripArgs = append(stripArgs, *flagOutfile)
2131 if ctxt.Debugvlog != 0 {
2132 ctxt.Logf("host link strip: %q", stripCmd)
2133 for _, v := range stripArgs {
2134 ctxt.Logf(" %q", v)
2135 }
2136 ctxt.Logf("\n")
2137 }
2138 cmd = exec.Command(stripCmd, stripArgs...)
2139 if out, err := cmd.CombinedOutput(); err != nil {
2140 Exitf("%s: running strip failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
2141 }
2142
2143 if _, err := os.Stat(dsym); err == nil {
2144 updateMachoOutFile("combining dwarf",
2145 func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
2146 return machoCombineDwarf(ctxt, exef, exem, dsym, outexe)
2147 })
2148 uuidUpdated = true
2149 }
2150 }
2151 if ctxt.IsDarwin() && !uuidUpdated && len(buildinfo) > 0 {
2152 updateMachoOutFile("rewriting uuid",
2153 func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
2154 return machoRewriteUuid(ctxt, exef, exem, outexe)
2155 })
2156 }
2157 hostlinkfips(ctxt, *flagOutfile, *flagFipso)
2158 if ctxt.NeedCodeSign() {
2159 err := machoCodeSign(ctxt, *flagOutfile)
2160 if err != nil {
2161 Exitf("%s: code signing failed: %v", os.Args[0], err)
2162 }
2163 }
2164 }
2165
2166
2167
2168 func (ctxt *Link) passLongArgsInResponseFile(argv []string, altLinker string) []string {
2169 c := 0
2170 for _, arg := range argv {
2171 c += len(arg)
2172 }
2173
2174 if c < sys.ExecArgLengthLimit {
2175 return argv
2176 }
2177
2178
2179 response := filepath.Join(*flagTmpdir, "response")
2180 if err := os.WriteFile(response, nil, 0644); err != nil {
2181 log.Fatalf("failed while testing response file: %v", err)
2182 }
2183 if !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "@"+response) {
2184 if ctxt.Debugvlog != 0 {
2185 ctxt.Logf("not using response file because linker does not support one")
2186 }
2187 return argv
2188 }
2189
2190 var buf bytes.Buffer
2191 for _, arg := range argv[1:] {
2192
2193 fmt.Fprintf(&buf, "%q\n", arg)
2194 }
2195 if err := os.WriteFile(response, buf.Bytes(), 0644); err != nil {
2196 log.Fatalf("failed while writing response file: %v", err)
2197 }
2198 if ctxt.Debugvlog != 0 {
2199 ctxt.Logf("response file %s contents:\n%s", response, buf.Bytes())
2200 }
2201 return []string{
2202 argv[0],
2203 "@" + response,
2204 }
2205 }
2206
2207 var createTrivialCOnce sync.Once
2208
2209 func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
2210 createTrivialCOnce.Do(func() {
2211 src := filepath.Join(*flagTmpdir, "trivial.c")
2212 if err := os.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
2213 Errorf("WriteFile trivial.c failed: %v", err)
2214 }
2215 })
2216
2217 flags := hostlinkArchArgs(arch)
2218
2219 moreFlags := trimLinkerArgv(append(ldflag, flagExtldflags...))
2220 flags = append(flags, moreFlags...)
2221
2222 if altLinker != "" {
2223 flags = append(flags, "-fuse-ld="+altLinker)
2224 }
2225 trivialPath := filepath.Join(*flagTmpdir, "trivial.c")
2226 outPath := filepath.Join(*flagTmpdir, "a.out")
2227 flags = append(flags, "-o", outPath, flag, trivialPath)
2228
2229 cmd := exec.Command(linker, flags...)
2230 cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
2231 out, err := cmd.CombinedOutput()
2232
2233
2234 return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
2235 }
2236
2237
2238
2239 func trimLinkerArgv(argv []string) []string {
2240 flagsWithNextArgSkip := []string{
2241 "-F",
2242 "-l",
2243 "-framework",
2244 "-Wl,-framework",
2245 "-Wl,-rpath",
2246 "-Wl,-undefined",
2247 }
2248 flagsWithNextArgKeep := []string{
2249 "-B",
2250 "-L",
2251 "-arch",
2252 "-isysroot",
2253 "--sysroot",
2254 "-target",
2255 "--target",
2256 "-resource-dir",
2257 "-rtlib",
2258 "--rtlib",
2259 "-stdlib",
2260 "--stdlib",
2261 "-unwindlib",
2262 "--unwindlib",
2263 }
2264 prefixesToKeep := []string{
2265 "-B",
2266 "-L",
2267 "-f",
2268 "-m",
2269 "-p",
2270 "-Wl,",
2271 "-arch",
2272 "-isysroot",
2273 "--sysroot",
2274 "-target",
2275 "--target",
2276 "-resource-dir",
2277 "-rtlib",
2278 "--rtlib",
2279 "-stdlib",
2280 "--stdlib",
2281 "-unwindlib",
2282 "--unwindlib",
2283 "-nostdlib++",
2284 "-nostdlib",
2285 "-nodefaultlibs",
2286 "-nostartfiles",
2287 "-nostdinc++",
2288 "-nostdinc",
2289 "-nobuiltininc",
2290 }
2291
2292 var flags []string
2293 keep := false
2294 skip := false
2295 for _, f := range argv {
2296 if keep {
2297 flags = append(flags, f)
2298 keep = false
2299 } else if skip {
2300 skip = false
2301 } else if f == "" || f[0] != '-' {
2302 } else if slices.Contains(flagsWithNextArgSkip, f) {
2303 skip = true
2304 } else if slices.Contains(flagsWithNextArgKeep, f) {
2305 flags = append(flags, f)
2306 keep = true
2307 } else {
2308 for _, p := range prefixesToKeep {
2309 if strings.HasPrefix(f, p) {
2310 flags = append(flags, f)
2311 break
2312 }
2313 }
2314 }
2315 }
2316 return flags
2317 }
2318
2319
2320
2321 func hostlinkArchArgs(arch *sys.Arch) []string {
2322 switch arch.Family {
2323 case sys.I386:
2324 return []string{"-m32"}
2325 case sys.AMD64:
2326 if buildcfg.GOOS == "darwin" {
2327 return []string{"-arch", "x86_64", "-m64"}
2328 }
2329 return []string{"-m64"}
2330 case sys.S390X:
2331 return []string{"-m64"}
2332 case sys.ARM:
2333 return []string{"-marm"}
2334 case sys.ARM64:
2335 if buildcfg.GOOS == "darwin" {
2336 return []string{"-arch", "arm64"}
2337 }
2338 case sys.Loong64:
2339 return []string{"-mabi=lp64d"}
2340 case sys.MIPS64:
2341 return []string{"-mabi=64"}
2342 case sys.MIPS:
2343 return []string{"-mabi=32"}
2344 case sys.PPC64:
2345 if buildcfg.GOOS == "aix" {
2346 return []string{"-maix64"}
2347 } else {
2348 return []string{"-m64"}
2349 }
2350
2351 }
2352 return nil
2353 }
2354
2355 var wantHdr = objabi.HeaderString()
2356
2357
2358
2359
2360 func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, file string) *Hostobj {
2361 pkg := objabi.PathToPrefix(lib.Pkg)
2362
2363 eof := f.Offset() + length
2364 start := f.Offset()
2365 c1 := bgetc(f)
2366 c2 := bgetc(f)
2367 c3 := bgetc(f)
2368 c4 := bgetc(f)
2369 f.MustSeek(start, 0)
2370
2371 unit := &sym.CompilationUnit{Lib: lib}
2372 lib.Units = append(lib.Units, unit)
2373
2374 magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
2375 if magic == 0x7f454c46 {
2376 ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2377 textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.Flags)
2378 if err != nil {
2379 Errorf("%v", err)
2380 return
2381 }
2382 ehdr.Flags = flags
2383 ctxt.Textp = append(ctxt.Textp, textp...)
2384 }
2385 return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
2386 }
2387
2388 if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
2389 ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2390 textp, err := loadmacho.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2391 if err != nil {
2392 Errorf("%v", err)
2393 return
2394 }
2395 ctxt.Textp = append(ctxt.Textp, textp...)
2396 }
2397 return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
2398 }
2399
2400 switch c1<<8 | c2 {
2401 case 0x4c01,
2402 0x6486,
2403 0xc401,
2404 0x64aa:
2405 ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2406 ls, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2407 if err != nil {
2408 Errorf("%v", err)
2409 return
2410 }
2411 if len(ls.Resources) != 0 {
2412 setpersrc(ctxt, ls.Resources)
2413 }
2414 sehp.pdata = append(sehp.pdata, ls.PData...)
2415 if ls.XData != 0 {
2416 sehp.xdata = append(sehp.xdata, ls.XData)
2417 }
2418 ctxt.Textp = append(ctxt.Textp, ls.Textp...)
2419 }
2420 return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
2421 }
2422
2423 if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
2424 ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2425 textp, err := loadxcoff.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2426 if err != nil {
2427 Errorf("%v", err)
2428 return
2429 }
2430 ctxt.Textp = append(ctxt.Textp, textp...)
2431 }
2432 return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
2433 }
2434
2435 if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' {
2436
2437
2438
2439 unknownObjFormat = true
2440 return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file)
2441 }
2442
2443
2444 line, err := f.ReadString('\n')
2445 if err != nil {
2446 Errorf("truncated object file: %s: %v", pn, err)
2447 return nil
2448 }
2449
2450 if !strings.HasPrefix(line, "go object ") {
2451 if strings.HasSuffix(pn, ".go") {
2452 Exitf("%s: uncompiled .go source file", pn)
2453 return nil
2454 }
2455
2456 if line == ctxt.Arch.Name {
2457
2458 Errorf("%s: stale object file", pn)
2459 return nil
2460 }
2461
2462 Errorf("%s: not an object file: @%d %q", pn, start, line)
2463 return nil
2464 }
2465
2466
2467 if line != wantHdr {
2468 Errorf("%s: linked object header mismatch:\nhave %q\nwant %q\n", pn, line, wantHdr)
2469 }
2470
2471
2472
2473
2474
2475
2476
2477
2478 import0 := f.Offset()
2479
2480 c1 = '\n'
2481 c2 = bgetc(f)
2482 c3 = bgetc(f)
2483 markers := 0
2484 for {
2485 if c1 == '\n' {
2486 if markers%2 == 0 && c2 == '!' && c3 == '\n' {
2487 break
2488 }
2489 if c2 == '$' && c3 == '$' {
2490 markers++
2491 }
2492 }
2493
2494 c1 = c2
2495 c2 = c3
2496 c3 = bgetc(f)
2497 if c3 == -1 {
2498 Errorf("truncated object file: %s", pn)
2499 return nil
2500 }
2501 }
2502
2503 import1 := f.Offset()
2504
2505 f.MustSeek(import0, 0)
2506 ldpkg(ctxt, f, lib, import1-import0-2, pn)
2507 f.MustSeek(import1, 0)
2508
2509 fingerprint := ctxt.loader.Preload(ctxt.IncVersion(), f, lib, unit, eof-f.Offset())
2510 if !fingerprint.IsZero() {
2511
2512
2513
2514
2515
2516 if lib.Fingerprint.IsZero() {
2517 lib.Fingerprint = fingerprint
2518 }
2519 checkFingerprint(lib, fingerprint, lib.Srcref, lib.Fingerprint)
2520 }
2521
2522 addImports(ctxt, lib, pn)
2523 return nil
2524 }
2525
2526
2527
2528
2529
2530 func symbolsAreUnresolved(ctxt *Link, want []string) []bool {
2531 returnAllUndefs := -1
2532 undefs, _ := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
2533 seen := make(map[loader.Sym]struct{})
2534 rval := make([]bool, len(want))
2535 wantm := make(map[string]int)
2536 for k, w := range want {
2537 wantm[w] = k
2538 }
2539 count := 0
2540 for _, s := range undefs {
2541 if _, ok := seen[s]; ok {
2542 continue
2543 }
2544 seen[s] = struct{}{}
2545 if k, ok := wantm[ctxt.loader.SymName(s)]; ok {
2546 rval[k] = true
2547 count++
2548 if count == len(want) {
2549 return rval
2550 }
2551 }
2552 }
2553 return rval
2554 }
2555
2556
2557
2558
2559 func hostObject(ctxt *Link, objname string, path string) {
2560 if ctxt.Debugvlog > 1 {
2561 ctxt.Logf("hostObject(%s)\n", path)
2562 }
2563 objlib := sym.Library{
2564 Pkg: objname,
2565 }
2566 f, err := bio.Open(path)
2567 if err != nil {
2568 Exitf("cannot open host object %q file %s: %v", objname, path, err)
2569 }
2570 defer f.Close()
2571 h := ldobj(ctxt, f, &objlib, 0, path, path)
2572 if h.ld == nil {
2573 Exitf("unrecognized object file format in %s", path)
2574 }
2575 h.file = path
2576 h.length = f.MustSeek(0, 2)
2577 f.MustSeek(h.off, 0)
2578 h.ld(ctxt, f, h.pkg, h.length, h.pn)
2579 if *flagCaptureHostObjs != "" {
2580 captureHostObj(h)
2581 }
2582 }
2583
2584 func checkFingerprint(lib *sym.Library, libfp goobj.FingerprintType, src string, srcfp goobj.FingerprintType) {
2585 if libfp != srcfp {
2586 Exitf("fingerprint mismatch: %s has %x, import from %s expecting %x", lib, libfp, src, srcfp)
2587 }
2588 }
2589
2590 func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
2591 data := make([]byte, sym.Size)
2592 sect := f.Sections[sym.Section]
2593 if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
2594 Errorf("reading %s from non-data section", sym.Name)
2595 }
2596 n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
2597 if uint64(n) != sym.Size {
2598 Errorf("reading contents of %s: %v", sym.Name, err)
2599 }
2600 return data
2601 }
2602
2603 func readwithpad(r io.Reader, sz int32) ([]byte, error) {
2604 data := make([]byte, Rnd(int64(sz), 4))
2605 _, err := io.ReadFull(r, data)
2606 if err != nil {
2607 return nil, err
2608 }
2609 data = data[:sz]
2610 return data, nil
2611 }
2612
2613 func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
2614 for _, sect := range f.Sections {
2615 if sect.Type != elf.SHT_NOTE {
2616 continue
2617 }
2618 r := sect.Open()
2619 for {
2620 var namesize, descsize, noteType int32
2621 err := binary.Read(r, f.ByteOrder, &namesize)
2622 if err != nil {
2623 if err == io.EOF {
2624 break
2625 }
2626 return nil, fmt.Errorf("read namesize failed: %v", err)
2627 }
2628 err = binary.Read(r, f.ByteOrder, &descsize)
2629 if err != nil {
2630 return nil, fmt.Errorf("read descsize failed: %v", err)
2631 }
2632 err = binary.Read(r, f.ByteOrder, ¬eType)
2633 if err != nil {
2634 return nil, fmt.Errorf("read type failed: %v", err)
2635 }
2636 noteName, err := readwithpad(r, namesize)
2637 if err != nil {
2638 return nil, fmt.Errorf("read name failed: %v", err)
2639 }
2640 desc, err := readwithpad(r, descsize)
2641 if err != nil {
2642 return nil, fmt.Errorf("read desc failed: %v", err)
2643 }
2644 if string(name) == string(noteName) && typ == noteType {
2645 return desc, nil
2646 }
2647 }
2648 }
2649 return nil, nil
2650 }
2651
2652 func findshlib(ctxt *Link, shlib string) string {
2653 if filepath.IsAbs(shlib) {
2654 return shlib
2655 }
2656 for _, libdir := range ctxt.Libdir {
2657 libpath := filepath.Join(libdir, shlib)
2658 if _, err := os.Stat(libpath); err == nil {
2659 return libpath
2660 }
2661 }
2662 Errorf("cannot find shared library: %s", shlib)
2663 return ""
2664 }
2665
2666 func ldshlibsyms(ctxt *Link, shlib string) {
2667 var libpath string
2668 if filepath.IsAbs(shlib) {
2669 libpath = shlib
2670 shlib = filepath.Base(shlib)
2671 } else {
2672 libpath = findshlib(ctxt, shlib)
2673 if libpath == "" {
2674 return
2675 }
2676 }
2677 for _, processedlib := range ctxt.Shlibs {
2678 if processedlib.Path == libpath {
2679 return
2680 }
2681 }
2682 if ctxt.Debugvlog > 1 {
2683 ctxt.Logf("ldshlibsyms: found library with name %s at %s\n", shlib, libpath)
2684 }
2685
2686 f, err := elf.Open(libpath)
2687 if err != nil {
2688 Errorf("cannot open shared library: %s", libpath)
2689 return
2690 }
2691
2692
2693
2694
2695 hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
2696 if err != nil {
2697 Errorf("cannot read ABI hash from shared library %s: %v", libpath, err)
2698 return
2699 }
2700
2701 depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
2702 if err != nil {
2703 Errorf("cannot read dep list from shared library %s: %v", libpath, err)
2704 return
2705 }
2706 var deps []string
2707 for _, dep := range strings.Split(string(depsbytes), "\n") {
2708 if dep == "" {
2709 continue
2710 }
2711 if !filepath.IsAbs(dep) {
2712
2713
2714
2715 abs := filepath.Join(filepath.Dir(libpath), dep)
2716 if _, err := os.Stat(abs); err == nil {
2717 dep = abs
2718 }
2719 }
2720 deps = append(deps, dep)
2721 }
2722
2723 syms, err := f.DynamicSymbols()
2724 if err != nil {
2725 Errorf("cannot read symbols from shared library: %s", libpath)
2726 return
2727 }
2728
2729 symAddr := map[string]uint64{}
2730 for _, elfsym := range syms {
2731 if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
2732 continue
2733 }
2734
2735
2736
2737 ver := 0
2738 symname := elfsym.Name
2739 if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && strings.HasPrefix(elfsym.Name, "type:") {
2740 ver = abiInternalVer
2741 } else if buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC {
2742
2743 if strings.HasSuffix(elfsym.Name, ".abiinternal") {
2744 ver = sym.SymVerABIInternal
2745 symname = strings.TrimSuffix(elfsym.Name, ".abiinternal")
2746 } else if strings.HasSuffix(elfsym.Name, ".abi0") {
2747 ver = 0
2748 symname = strings.TrimSuffix(elfsym.Name, ".abi0")
2749 }
2750 }
2751
2752 l := ctxt.loader
2753 s := l.LookupOrCreateSym(symname, ver)
2754
2755
2756
2757
2758
2759 if l.SymType(s) != 0 && l.SymType(s) != sym.SDYNIMPORT {
2760 continue
2761 }
2762 su := l.MakeSymbolUpdater(s)
2763 su.SetType(sym.SDYNIMPORT)
2764 l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
2765 su.SetSize(int64(elfsym.Size))
2766 if elfsym.Section != elf.SHN_UNDEF {
2767
2768 l.SetSymPkg(s, libpath)
2769
2770
2771
2772 sname := l.SymName(s)
2773 if strings.HasPrefix(sname, "type:") && !strings.HasPrefix(sname, "type:.") {
2774 su.SetData(readelfsymboldata(ctxt, f, &elfsym))
2775 }
2776 }
2777
2778 if symname != elfsym.Name {
2779 l.SetSymExtname(s, elfsym.Name)
2780 }
2781 symAddr[elfsym.Name] = elfsym.Value
2782 }
2783
2784
2785
2786
2787 relocTarget := map[uint64]string{}
2788 addends := false
2789 sect := f.SectionByType(elf.SHT_REL)
2790 if sect == nil {
2791 sect = f.SectionByType(elf.SHT_RELA)
2792 if sect == nil {
2793 log.Fatalf("can't find SHT_REL or SHT_RELA section of %s", shlib)
2794 }
2795 addends = true
2796 }
2797
2798 data, err := sect.Data()
2799 if err != nil {
2800 log.Fatalf("can't read relocation section of %s: %v", shlib, err)
2801 }
2802 bo := f.ByteOrder
2803 for len(data) > 0 {
2804 var off, idx uint64
2805 var addend int64
2806 switch f.Class {
2807 case elf.ELFCLASS64:
2808 off = bo.Uint64(data)
2809 info := bo.Uint64(data[8:])
2810 data = data[16:]
2811 if addends {
2812 addend = int64(bo.Uint64(data))
2813 data = data[8:]
2814 }
2815
2816 idx = info >> 32
2817 typ := info & 0xffff
2818
2819
2820 switch typ {
2821 case uint64(elf.R_X86_64_64):
2822 case uint64(elf.R_AARCH64_ABS64):
2823 case uint64(elf.R_LARCH_64):
2824 case uint64(elf.R_390_64):
2825 case uint64(elf.R_PPC64_ADDR64):
2826 default:
2827 continue
2828 }
2829 case elf.ELFCLASS32:
2830 off = uint64(bo.Uint32(data))
2831 info := bo.Uint32(data[4:])
2832 data = data[8:]
2833 if addends {
2834 addend = int64(int32(bo.Uint32(data)))
2835 data = data[4:]
2836 }
2837
2838 idx = uint64(info >> 8)
2839 typ := info & 0xff
2840
2841 switch typ {
2842 case uint32(elf.R_386_32):
2843 case uint32(elf.R_ARM_ABS32):
2844 default:
2845 continue
2846 }
2847 default:
2848 log.Fatalf("unknown bit size %s", f.Class)
2849 }
2850 if addend != 0 {
2851 continue
2852 }
2853 relocTarget[off] = syms[idx-1].Name
2854 }
2855
2856 ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, symAddr: symAddr, relocTarget: relocTarget})
2857 }
2858
2859 func addsection(ldr *loader.Loader, arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
2860 sect := ldr.NewSection()
2861 sect.Rwx = uint8(rwx)
2862 sect.Name = name
2863 sect.Seg = seg
2864 sect.Align = int32(arch.PtrSize)
2865 seg.Sections = append(seg.Sections, sect)
2866 return sect
2867 }
2868
2869 func usage() {
2870 fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
2871 objabi.Flagprint(os.Stderr)
2872 Exit(2)
2873 }
2874
2875 type SymbolType int8
2876
2877 const (
2878
2879 TextSym SymbolType = 'T'
2880 DataSym SymbolType = 'D'
2881 BSSSym SymbolType = 'B'
2882 UndefinedSym SymbolType = 'U'
2883 TLSSym SymbolType = 't'
2884 FrameSym SymbolType = 'm'
2885 ParamSym SymbolType = 'p'
2886 AutoSym SymbolType = 'a'
2887
2888
2889 DeletedAutoSym = 'x'
2890 )
2891
2892
2893 func (ctxt *Link) defineInternal(p string, t sym.SymKind) loader.Sym {
2894 s := ctxt.loader.CreateSymForUpdate(p, 0)
2895 s.SetType(t)
2896 s.SetSpecial(true)
2897 s.SetLocal(true)
2898 return s.Sym()
2899 }
2900
2901 func (ctxt *Link) xdefine(p string, t sym.SymKind, v int64) loader.Sym {
2902 s := ctxt.defineInternal(p, t)
2903 ctxt.loader.SetSymValue(s, v)
2904 return s
2905 }
2906
2907 func datoff(ldr *loader.Loader, s loader.Sym, addr int64) int64 {
2908 if uint64(addr) >= Segdata.Vaddr {
2909 return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
2910 }
2911 if uint64(addr) >= Segtext.Vaddr {
2912 return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
2913 }
2914 ldr.Errorf(s, "invalid datoff %#x", addr)
2915 return 0
2916 }
2917
2918 func Entryvalue(ctxt *Link) int64 {
2919 a := *flagEntrySymbol
2920 if a[0] >= '0' && a[0] <= '9' {
2921 return atolwhex(a)
2922 }
2923 ldr := ctxt.loader
2924 s := ldr.Lookup(a, 0)
2925 if s == 0 {
2926 Errorf("missing entry symbol %q", a)
2927 return 0
2928 }
2929 st := ldr.SymType(s)
2930 if st == 0 {
2931 return *FlagTextAddr
2932 }
2933 if !ctxt.IsAIX() && !st.IsText() {
2934 ldr.Errorf(s, "entry not text")
2935 }
2936 return ldr.SymValue(s)
2937 }
2938
2939 func (ctxt *Link) callgraph() {
2940 if !*FlagC {
2941 return
2942 }
2943
2944 ldr := ctxt.loader
2945 for _, s := range ctxt.Textp {
2946 relocs := ldr.Relocs(s)
2947 for i := 0; i < relocs.Count(); i++ {
2948 r := relocs.At(i)
2949 rs := r.Sym()
2950 if rs == 0 {
2951 continue
2952 }
2953 if r.Type().IsDirectCall() && ldr.SymType(rs).IsText() {
2954 ctxt.Logf("%s calls %s\n", ldr.SymName(s), ldr.SymName(rs))
2955 }
2956 }
2957 }
2958 }
2959
2960 func Rnd(v int64, r int64) int64 {
2961 if r <= 0 {
2962 return v
2963 }
2964 v += r - 1
2965 c := v % r
2966 if c < 0 {
2967 c += r
2968 }
2969 v -= c
2970 return v
2971 }
2972
2973 func bgetc(r *bio.Reader) int {
2974 c, err := r.ReadByte()
2975 if err != nil {
2976 if err != io.EOF {
2977 log.Fatalf("reading input: %v", err)
2978 }
2979 return -1
2980 }
2981 return int(c)
2982 }
2983
2984 type markKind uint8
2985 const (
2986 _ markKind = iota
2987 visiting
2988 visited
2989 )
2990
2991 func postorder(libs []*sym.Library) []*sym.Library {
2992 order := make([]*sym.Library, 0, len(libs))
2993 mark := make(map[*sym.Library]markKind, len(libs))
2994 for _, lib := range libs {
2995 dfs(lib, mark, &order)
2996 }
2997 return order
2998 }
2999
3000 func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library) {
3001 if mark[lib] == visited {
3002 return
3003 }
3004 if mark[lib] == visiting {
3005 panic("found import cycle while visiting " + lib.Pkg)
3006 }
3007 mark[lib] = visiting
3008 for _, i := range lib.Imports {
3009 dfs(i, mark, order)
3010 }
3011 mark[lib] = visited
3012 *order = append(*order, lib)
3013 }
3014
3015 func ElfSymForReloc(ctxt *Link, s loader.Sym) int32 {
3016
3017
3018 les := ctxt.loader.SymLocalElfSym(s)
3019 if les != 0 {
3020 return les
3021 } else {
3022 return ctxt.loader.SymElfSym(s)
3023 }
3024 }
3025
3026 func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, elfRelocTyp uint32) {
3027 if ldr.SymGot(s) >= 0 {
3028 return
3029 }
3030
3031 Adddynsym(ldr, target, syms, s)
3032 got := ldr.MakeSymbolUpdater(syms.GOT)
3033 ldr.SetGot(s, int32(got.Size()))
3034 got.AddUint(target.Arch, 0)
3035
3036 if target.IsElf() {
3037 if target.Arch.PtrSize == 8 {
3038 rela := ldr.MakeSymbolUpdater(syms.Rela)
3039 rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
3040 rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
3041 rela.AddUint64(target.Arch, 0)
3042 } else {
3043 rel := ldr.MakeSymbolUpdater(syms.Rel)
3044 rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
3045 rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), elfRelocTyp))
3046 }
3047 } else if target.IsDarwin() {
3048 leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
3049 leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
3050 if target.IsPIE() && target.IsInternal() {
3051
3052
3053
3054 MachoAddBind(syms.GOT, int64(ldr.SymGot(s)), s)
3055 }
3056 } else {
3057 ldr.Errorf(s, "addgotsym: unsupported binary format")
3058 }
3059 }
3060
3061 var hostobjcounter int
3062
3063
3064
3065
3066
3067
3068 func captureHostObj(h *Hostobj) {
3069
3070 ofile := fmt.Sprintf("captured-obj-%d.o", hostobjcounter)
3071 ifile := fmt.Sprintf("captured-obj-%d.txt", hostobjcounter)
3072 hostobjcounter++
3073 opath := filepath.Join(*flagCaptureHostObjs, ofile)
3074 ipath := filepath.Join(*flagCaptureHostObjs, ifile)
3075
3076
3077 info := fmt.Sprintf("pkg: %s\npn: %s\nfile: %s\noff: %d\nlen: %d\n",
3078 h.pkg, h.pn, h.file, h.off, h.length)
3079 if err := os.WriteFile(ipath, []byte(info), 0666); err != nil {
3080 log.Fatalf("error writing captured host obj info %s: %v", ipath, err)
3081 }
3082
3083 readObjData := func() []byte {
3084 inf, err := os.Open(h.file)
3085 if err != nil {
3086 log.Fatalf("capturing host obj: open failed on %s: %v", h.pn, err)
3087 }
3088 defer inf.Close()
3089 res := make([]byte, h.length)
3090 if n, err := inf.ReadAt(res, h.off); err != nil || n != int(h.length) {
3091 log.Fatalf("capturing host obj: readat failed on %s: %v", h.pn, err)
3092 }
3093 return res
3094 }
3095
3096
3097 if err := os.WriteFile(opath, readObjData(), 0666); err != nil {
3098 log.Fatalf("error writing captured host object %s: %v", opath, err)
3099 }
3100
3101 fmt.Fprintf(os.Stderr, "link: info: captured host object %s to %s\n",
3102 h.file, opath)
3103 }
3104
3105
3106
3107
3108 func (ctxt *Link) findExtLinkTool(toolname string) string {
3109 var cc []string
3110 cc = append(cc, ctxt.extld()...)
3111 cc = append(cc, hostlinkArchArgs(ctxt.Arch)...)
3112 cc = append(cc, "--print-prog-name", toolname)
3113 out, err := exec.Command(cc[0], cc[1:]...).CombinedOutput()
3114 if err != nil {
3115 Exitf("%s: finding %s failed: %v\n%s", os.Args[0], toolname, err, out)
3116 }
3117 cmdpath := strings.TrimRight(string(out), "\r\n")
3118 return cmdpath
3119 }
3120
3121
3122
3123 func (ctxt *Link) isMSVC() bool {
3124 extld := ctxt.extld()
3125 name, args := extld[0], extld[1:]
3126 args = append(args, trimLinkerArgv(flagExtldflags)...)
3127 args = append(args, "--version")
3128 cmd := exec.Command(name, args...)
3129 if out, err := cmd.CombinedOutput(); err == nil {
3130 if bytes.Contains(out, []byte("-msvc\n")) || bytes.Contains(out, []byte("-msvc\r")) {
3131 return true
3132 }
3133 }
3134 return false
3135 }
3136
View as plain text