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