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