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