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