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