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