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 "time"
51
52 "cmd/internal/bio"
53 "cmd/internal/goobj"
54 "cmd/internal/notsha256"
55 "cmd/internal/objabi"
56 "cmd/internal/sys"
57 "cmd/link/internal/loadelf"
58 "cmd/link/internal/loader"
59 "cmd/link/internal/loadmacho"
60 "cmd/link/internal/loadpe"
61 "cmd/link/internal/loadxcoff"
62 "cmd/link/internal/sym"
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
100 type ArchSyms struct {
101 Rel loader.Sym
102 Rela loader.Sym
103 RelPLT loader.Sym
104 RelaPLT loader.Sym
105
106 LinkEditGOT loader.Sym
107 LinkEditPLT loader.Sym
108
109 TOC loader.Sym
110 DotTOC []loader.Sym
111
112 GOT loader.Sym
113 PLT loader.Sym
114 GOTPLT loader.Sym
115
116 Tlsg loader.Sym
117 Tlsoffset int
118
119 Dynamic loader.Sym
120 DynSym loader.Sym
121 DynStr loader.Sym
122
123 unreachableMethod loader.Sym
124
125
126
127 mainInittasks loader.Sym
128 }
129
130
131 func (ctxt *Link) mkArchSym(name string, ver int, ls *loader.Sym) {
132 *ls = ctxt.loader.LookupOrCreateSym(name, ver)
133 ctxt.loader.SetAttrReachable(*ls, true)
134 }
135
136
137
138 func (ctxt *Link) mkArchSymVec(name string, ver int, ls []loader.Sym) {
139 ls[ver] = ctxt.loader.LookupOrCreateSym(name, ver)
140 ctxt.loader.SetAttrReachable(ls[ver], true)
141 }
142
143
144
145 func (ctxt *Link) setArchSyms() {
146 ctxt.mkArchSym(".got", 0, &ctxt.GOT)
147 ctxt.mkArchSym(".plt", 0, &ctxt.PLT)
148 ctxt.mkArchSym(".got.plt", 0, &ctxt.GOTPLT)
149 ctxt.mkArchSym(".dynamic", 0, &ctxt.Dynamic)
150 ctxt.mkArchSym(".dynsym", 0, &ctxt.DynSym)
151 ctxt.mkArchSym(".dynstr", 0, &ctxt.DynStr)
152 ctxt.mkArchSym("runtime.unreachableMethod", abiInternalVer, &ctxt.unreachableMethod)
153
154 if ctxt.IsPPC64() {
155 ctxt.mkArchSym("TOC", 0, &ctxt.TOC)
156
157 ctxt.DotTOC = make([]loader.Sym, ctxt.MaxVersion()+1)
158 for i := 0; i <= ctxt.MaxVersion(); i++ {
159 if i >= sym.SymVerABICount && i < sym.SymVerStatic {
160 continue
161 }
162 ctxt.mkArchSymVec(".TOC.", i, ctxt.DotTOC)
163 }
164 }
165 if ctxt.IsElf() {
166 ctxt.mkArchSym(".rel", 0, &ctxt.Rel)
167 ctxt.mkArchSym(".rela", 0, &ctxt.Rela)
168 ctxt.mkArchSym(".rel.plt", 0, &ctxt.RelPLT)
169 ctxt.mkArchSym(".rela.plt", 0, &ctxt.RelaPLT)
170 }
171 if ctxt.IsDarwin() {
172 ctxt.mkArchSym(".linkedit.got", 0, &ctxt.LinkEditGOT)
173 ctxt.mkArchSym(".linkedit.plt", 0, &ctxt.LinkEditPLT)
174 }
175 }
176
177 type Arch struct {
178 Funcalign int
179 Maxalign int
180 Minalign int
181 Dwarfregsp int
182 Dwarfreglr int
183
184
185
186
187
188 TrampLimit uint64
189
190
191
192
193
194 CodePad []byte
195
196
197 Plan9Magic uint32
198 Plan9_64Bit bool
199
200 Adddynrel func(*Target, *loader.Loader, *ArchSyms, loader.Sym, loader.Reloc, int) bool
201 Archinit func(*Link)
202
203
204
205
206
207
208
209
210
211
212 Archreloc func(*Target, *loader.Loader, *ArchSyms, loader.Reloc, loader.Sym,
213 int64) (relocatedOffset int64, nExtReloc int, ok bool)
214
215
216
217
218
219
220
221
222 Archrelocvariant func(target *Target, ldr *loader.Loader, rel loader.Reloc,
223 rv sym.RelocVariant, sym loader.Sym, offset int64, data []byte) (relocatedOffset int64)
224
225
226
227 Trampoline func(ctxt *Link, ldr *loader.Loader, ri int, rs, s loader.Sym)
228
229
230
231
232
233
234
235
236 Asmb func(*Link, *loader.Loader)
237 Asmb2 func(*Link, *loader.Loader)
238
239
240
241
242 Extreloc func(*Target, *loader.Loader, loader.Reloc, loader.Sym) (loader.ExtReloc, bool)
243
244 Gentext func(*Link, *loader.Loader)
245 Machoreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
246 MachorelocSize uint32
247 PEreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
248 Xcoffreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
249
250
251
252 GenSymsLate func(*Link, *loader.Loader)
253
254
255
256
257
258
259
260 TLSIEtoLE func(P []byte, off, size int)
261
262
263 AssignAddress func(ldr *loader.Loader, sect *sym.Section, n int, s loader.Sym, va uint64, isTramp bool) (*sym.Section, int, uint64)
264
265
266 ELF ELFArch
267 }
268
269 var (
270 thearch Arch
271 lcSize int32
272 rpath Rpath
273 spSize int32
274 symSize int32
275 )
276
277
278
279 var abiInternalVer = sym.SymVerABIInternal
280
281
282
283 func (ctxt *Link) DynlinkingGo() bool {
284 if !ctxt.Loaded {
285 panic("DynlinkingGo called before all symbols loaded")
286 }
287 return ctxt.BuildMode == BuildModeShared || ctxt.linkShared || ctxt.BuildMode == BuildModePlugin || ctxt.canUsePlugins
288 }
289
290
291 func (ctxt *Link) CanUsePlugins() bool {
292 if !ctxt.Loaded {
293 panic("CanUsePlugins called before all symbols loaded")
294 }
295 return ctxt.canUsePlugins
296 }
297
298
299 func (ctxt *Link) NeedCodeSign() bool {
300 return ctxt.IsDarwin() && ctxt.IsARM64()
301 }
302
303 var (
304 dynlib []string
305 ldflag []string
306 havedynamic int
307 Funcalign int
308 iscgo bool
309 elfglobalsymndx int
310 interpreter string
311
312 debug_s bool
313 HEADR int32
314
315 nerrors int
316 liveness int64
317
318
319 checkStrictDups int
320 strictDupMsgCount int
321 )
322
323 var (
324 Segtext sym.Segment
325 Segrodata sym.Segment
326 Segrelrodata sym.Segment
327 Segdata sym.Segment
328 Segdwarf sym.Segment
329 Segpdata sym.Segment
330 Segxdata sym.Segment
331
332 Segments = []*sym.Segment{&Segtext, &Segrodata, &Segrelrodata, &Segdata, &Segdwarf, &Segpdata, &Segxdata}
333 )
334
335 const pkgdef = "__.PKGDEF"
336
337 var (
338
339
340
341 externalobj = false
342
343
344
345
346 dynimportfail []string
347
348
349
350
351
352 preferlinkext []string
353
354
355
356 unknownObjFormat = false
357
358 theline string
359 )
360
361 func Lflag(ctxt *Link, arg string) {
362 ctxt.Libdir = append(ctxt.Libdir, arg)
363 }
364
365
371 func mayberemoveoutfile() {
372 if fi, err := os.Lstat(*flagOutfile); err == nil && !fi.Mode().IsRegular() {
373 return
374 }
375 os.Remove(*flagOutfile)
376 }
377
378 func libinit(ctxt *Link) {
379 Funcalign = thearch.Funcalign
380
381
382 suffix := ""
383
384 suffixsep := ""
385 if *flagInstallSuffix != "" {
386 suffixsep = "_"
387 suffix = *flagInstallSuffix
388 } else if *flagRace {
389 suffixsep = "_"
390 suffix = "race"
391 } else if *flagMsan {
392 suffixsep = "_"
393 suffix = "msan"
394 } else if *flagAsan {
395 suffixsep = "_"
396 suffix = "asan"
397 }
398
399 if buildcfg.GOROOT != "" {
400 Lflag(ctxt, filepath.Join(buildcfg.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", buildcfg.GOOS, buildcfg.GOARCH, suffixsep, suffix)))
401 }
402
403 mayberemoveoutfile()
404
405 if err := ctxt.Out.Open(*flagOutfile); err != nil {
406 Exitf("cannot create %s: %v", *flagOutfile, err)
407 }
408
409 if *flagEntrySymbol == "" {
410 switch ctxt.BuildMode {
411 case BuildModeCShared, BuildModeCArchive:
412 *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s_lib", buildcfg.GOARCH, buildcfg.GOOS)
413 case BuildModeExe, BuildModePIE:
414 *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s", buildcfg.GOARCH, buildcfg.GOOS)
415 case BuildModeShared, BuildModePlugin:
416
417 default:
418 Errorf(nil, "unknown *flagEntrySymbol for buildmode %v", ctxt.BuildMode)
419 }
420 }
421 }
422
423 func exitIfErrors() {
424 if nerrors != 0 || checkStrictDups > 1 && strictDupMsgCount > 0 {
425 mayberemoveoutfile()
426 Exit(2)
427 }
428
429 }
430
431 func errorexit() {
432 exitIfErrors()
433 Exit(0)
434 }
435
436 func loadinternal(ctxt *Link, name string) *sym.Library {
437 zerofp := goobj.FingerprintType{}
438 if ctxt.linkShared && ctxt.PackageShlib != nil {
439 if shlib := ctxt.PackageShlib[name]; shlib != "" {
440 return addlibpath(ctxt, "internal", "internal", "", name, shlib, zerofp)
441 }
442 }
443 if ctxt.PackageFile != nil {
444 if pname := ctxt.PackageFile[name]; pname != "" {
445 return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
446 }
447 ctxt.Logf("loadinternal: cannot find %s\n", name)
448 return nil
449 }
450
451 for _, libdir := range ctxt.Libdir {
452 if ctxt.linkShared {
453 shlibname := filepath.Join(libdir, name+".shlibname")
454 if ctxt.Debugvlog != 0 {
455 ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
456 }
457 if _, err := os.Stat(shlibname); err == nil {
458 return addlibpath(ctxt, "internal", "internal", "", name, shlibname, zerofp)
459 }
460 }
461 pname := filepath.Join(libdir, name+".a")
462 if ctxt.Debugvlog != 0 {
463 ctxt.Logf("searching for %s.a in %s\n", name, pname)
464 }
465 if _, err := os.Stat(pname); err == nil {
466 return addlibpath(ctxt, "internal", "internal", pname, name, "", zerofp)
467 }
468 }
469
470 if name == "runtime" {
471 Exitf("error: unable to find runtime.a")
472 }
473 ctxt.Logf("warning: unable to find %s.a\n", name)
474 return nil
475 }
476
477
478 func (ctxt *Link) extld() []string {
479 if len(flagExtld) == 0 {
480
481
482
483 switch buildcfg.GOOS {
484 case "darwin", "freebsd", "openbsd":
485 flagExtld = []string{"clang"}
486 default:
487 flagExtld = []string{"gcc"}
488 }
489 }
490 return flagExtld
491 }
492
493
494
495 func (ctxt *Link) findLibPathCmd(cmd, libname string) string {
496 extld := ctxt.extld()
497 name, args := extld[0], extld[1:]
498 args = append(args, hostlinkArchArgs(ctxt.Arch)...)
499 args = append(args, cmd)
500 if ctxt.Debugvlog != 0 {
501 ctxt.Logf("%s %v\n", extld, args)
502 }
503 out, err := exec.Command(name, args...).Output()
504 if err != nil {
505 if ctxt.Debugvlog != 0 {
506 ctxt.Logf("not using a %s file because compiler failed\n%v\n%s\n", libname, err, out)
507 }
508 return "none"
509 }
510 return strings.TrimSpace(string(out))
511 }
512
513
514
515 func (ctxt *Link) findLibPath(libname string) string {
516 return ctxt.findLibPathCmd("--print-file-name="+libname, libname)
517 }
518
519 func (ctxt *Link) loadlib() {
520 var flags uint32
521 if *flagCheckLinkname {
522 flags |= loader.FlagCheckLinkname
523 }
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.memProfileInternal", 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
1278
1279
1280
1281
1282 func cleanTimeStamps(files []string) {
1283 epocht := time.Unix(0, 0)
1284 for _, f := range files {
1285 if err := os.Chtimes(f, epocht, epocht); err != nil {
1286 Exitf("cannot chtimes %s: %v", f, err)
1287 }
1288 }
1289 }
1290
1291
1292
1293 func (ctxt *Link) hostobjCopy() (paths []string) {
1294 var wg sync.WaitGroup
1295 sema := make(chan struct{}, runtime.NumCPU())
1296 for i, h := range hostobj {
1297 h := h
1298 dst := filepath.Join(*flagTmpdir, fmt.Sprintf("%06d.o", i))
1299 paths = append(paths, dst)
1300 if ctxt.Debugvlog != 0 {
1301 ctxt.Logf("host obj copy: %s from pkg %s -> %s\n", h.pn, h.pkg, dst)
1302 }
1303
1304 wg.Add(1)
1305 go func() {
1306 sema <- struct{}{}
1307 defer func() {
1308 <-sema
1309 wg.Done()
1310 }()
1311 f, err := os.Open(h.file)
1312 if err != nil {
1313 Exitf("cannot reopen %s: %v", h.pn, err)
1314 }
1315 defer f.Close()
1316 if _, err := f.Seek(h.off, 0); err != nil {
1317 Exitf("cannot seek %s: %v", h.pn, err)
1318 }
1319
1320 w, err := os.Create(dst)
1321 if err != nil {
1322 Exitf("cannot create %s: %v", dst, err)
1323 }
1324 if _, err := io.CopyN(w, f, h.length); err != nil {
1325 Exitf("cannot write %s: %v", dst, err)
1326 }
1327 if err := w.Close(); err != nil {
1328 Exitf("cannot close %s: %v", dst, err)
1329 }
1330 }()
1331 }
1332 wg.Wait()
1333 return paths
1334 }
1335
1336
1337
1338
1339
1340 func writeGDBLinkerScript() string {
1341 name := "fix_debug_gdb_scripts.ld"
1342 path := filepath.Join(*flagTmpdir, name)
1343 src := `SECTIONS
1344 {
1345 .debug_gdb_scripts BLOCK(__section_alignment__) (NOLOAD) :
1346 {
1347 *(.debug_gdb_scripts)
1348 }
1349 }
1350 INSERT AFTER .debug_types;
1351 `
1352 err := os.WriteFile(path, []byte(src), 0666)
1353 if err != nil {
1354 Errorf(nil, "WriteFile %s failed: %v", name, err)
1355 }
1356 return path
1357 }
1358
1359 type machoUpdateFunc func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error
1360
1361
1362 func (ctxt *Link) archive() {
1363 if ctxt.BuildMode != BuildModeCArchive {
1364 return
1365 }
1366
1367 exitIfErrors()
1368
1369 if *flagExtar == "" {
1370 const printProgName = "--print-prog-name=ar"
1371 cc := ctxt.extld()
1372 *flagExtar = "ar"
1373 if linkerFlagSupported(ctxt.Arch, cc[0], "", printProgName) {
1374 *flagExtar = ctxt.findExtLinkTool("ar")
1375 }
1376 }
1377
1378 mayberemoveoutfile()
1379
1380
1381
1382 if err := ctxt.Out.Close(); err != nil {
1383 Exitf("error closing %v", *flagOutfile)
1384 }
1385
1386 argv := []string{*flagExtar, "-q", "-c", "-s"}
1387 if ctxt.HeadType == objabi.Haix {
1388 argv = append(argv, "-X64")
1389 }
1390 godotopath := filepath.Join(*flagTmpdir, "go.o")
1391 cleanTimeStamps([]string{godotopath})
1392 hostObjCopyPaths := ctxt.hostobjCopy()
1393 cleanTimeStamps(hostObjCopyPaths)
1394
1395 argv = append(argv, *flagOutfile)
1396 argv = append(argv, godotopath)
1397 argv = append(argv, hostObjCopyPaths...)
1398
1399 if ctxt.Debugvlog != 0 {
1400 ctxt.Logf("archive: %s\n", strings.Join(argv, " "))
1401 }
1402
1403
1404
1405
1406
1407
1408 if syscallExecSupported && !ownTmpDir {
1409 runAtExitFuncs()
1410 ctxt.execArchive(argv)
1411 panic("should not get here")
1412 }
1413
1414
1415 if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
1416 Exitf("running %s failed: %v\n%s", argv[0], err, out)
1417 }
1418 }
1419
1420 func (ctxt *Link) hostlink() {
1421 if ctxt.LinkMode != LinkExternal || nerrors > 0 {
1422 return
1423 }
1424 if ctxt.BuildMode == BuildModeCArchive {
1425 return
1426 }
1427
1428 var argv []string
1429 argv = append(argv, ctxt.extld()...)
1430 argv = append(argv, hostlinkArchArgs(ctxt.Arch)...)
1431
1432 if *FlagS || debug_s {
1433 if ctxt.HeadType == objabi.Hdarwin {
1434
1435
1436
1437 } else {
1438 argv = append(argv, "-s")
1439 }
1440 }
1441
1442
1443
1444 combineDwarf := ctxt.IsDarwin() && !*FlagW && machoPlatform == PLATFORM_MACOS
1445
1446 switch ctxt.HeadType {
1447 case objabi.Hdarwin:
1448 if combineDwarf {
1449
1450
1451 argv = append(argv, "-Wl,-headerpad,1144")
1452 }
1453 if ctxt.DynlinkingGo() && buildcfg.GOOS != "ios" {
1454
1455
1456
1457
1458
1459 argv = append(argv, "-Wl,-flat_namespace", "-Wl,-bind_at_load")
1460 }
1461 if !combineDwarf {
1462 argv = append(argv, "-Wl,-S")
1463 if debug_s {
1464
1465
1466
1467 argv = append(argv, "-Wl,-x")
1468 }
1469 }
1470 case objabi.Hopenbsd:
1471 argv = append(argv, "-pthread")
1472 if ctxt.BuildMode != BuildModePIE {
1473 argv = append(argv, "-Wl,-nopie")
1474 }
1475 if linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,-z,nobtcfi") {
1476
1477
1478 argv = append(argv, "-Wl,-z,nobtcfi")
1479 }
1480 if ctxt.Arch.InFamily(sys.ARM64) {
1481
1482
1483
1484 argv = append(argv, "-Wl,--no-execute-only")
1485 }
1486 case objabi.Hwindows:
1487 if windowsgui {
1488 argv = append(argv, "-mwindows")
1489 } else {
1490 argv = append(argv, "-mconsole")
1491 }
1492
1493
1494 argv = append(argv, "-Wl,--tsaware")
1495
1496
1497 argv = append(argv, "-Wl,--nxcompat")
1498
1499 argv = append(argv, fmt.Sprintf("-Wl,--major-os-version=%d", PeMinimumTargetMajorVersion))
1500 argv = append(argv, fmt.Sprintf("-Wl,--minor-os-version=%d", PeMinimumTargetMinorVersion))
1501 argv = append(argv, fmt.Sprintf("-Wl,--major-subsystem-version=%d", PeMinimumTargetMajorVersion))
1502 argv = append(argv, fmt.Sprintf("-Wl,--minor-subsystem-version=%d", PeMinimumTargetMinorVersion))
1503 case objabi.Haix:
1504 argv = append(argv, "-pthread")
1505
1506
1507 argv = append(argv, "-Wl,-bnoobjreorder")
1508
1509
1510 argv = append(argv, "-mcmodel=large")
1511 argv = append(argv, "-Wl,-bbigtoc")
1512 }
1513
1514
1515
1516
1517 if ctxt.IsPPC64() && ctxt.IsElf() && buildcfg.GOPPC64 >= 10 {
1518 if !linkerFlagSupported(ctxt.Arch, argv[0], "", "-mcpu=power10") {
1519 Exitf("The external toolchain does not support -mcpu=power10. " +
1520 " This is required to externally link GOPPC64 >= power10")
1521 }
1522 }
1523
1524
1525 addASLRargs := func(argv []string, val bool) []string {
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541 var dbopt string
1542 var heopt string
1543 dbon := "--dynamicbase"
1544 heon := "--high-entropy-va"
1545 dboff := "--disable-dynamicbase"
1546 heoff := "--disable-high-entropy-va"
1547 if val {
1548 dbopt = dbon
1549 heopt = heon
1550 } else {
1551
1552 newer := linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,"+dboff)
1553 if newer {
1554
1555 dbopt = dboff
1556 heopt = heoff
1557 } else {
1558
1559
1560 dbopt = ""
1561 heopt = ""
1562 }
1563 }
1564 if dbopt != "" {
1565 argv = append(argv, "-Wl,"+dbopt)
1566 }
1567
1568 if ctxt.Arch.PtrSize >= 8 && heopt != "" {
1569 argv = append(argv, "-Wl,"+heopt)
1570 }
1571 return argv
1572 }
1573
1574 switch ctxt.BuildMode {
1575 case BuildModeExe:
1576 if ctxt.HeadType == objabi.Hdarwin {
1577 if machoPlatform == PLATFORM_MACOS && ctxt.IsAMD64() {
1578 argv = append(argv, "-Wl,-no_pie")
1579 }
1580 }
1581 if *flagRace && ctxt.HeadType == objabi.Hwindows {
1582
1583
1584
1585
1586 argv = addASLRargs(argv, false)
1587 }
1588 case BuildModePIE:
1589 switch ctxt.HeadType {
1590 case objabi.Hdarwin, objabi.Haix:
1591 case objabi.Hwindows:
1592 if *flagAslr && *flagRace {
1593
1594
1595
1596 *flagAslr = false
1597 }
1598 argv = addASLRargs(argv, *flagAslr)
1599 default:
1600
1601 if ctxt.UseRelro() {
1602 argv = append(argv, "-Wl,-z,relro")
1603 }
1604 argv = append(argv, "-pie")
1605 }
1606 case BuildModeCShared:
1607 if ctxt.HeadType == objabi.Hdarwin {
1608 argv = append(argv, "-dynamiclib")
1609 } else {
1610 if ctxt.UseRelro() {
1611 argv = append(argv, "-Wl,-z,relro")
1612 }
1613 argv = append(argv, "-shared")
1614 if ctxt.HeadType == objabi.Hwindows {
1615 argv = addASLRargs(argv, *flagAslr)
1616 } else {
1617
1618
1619 argv = append(argv, "-Wl,-z,nodelete")
1620
1621 argv = append(argv, "-Wl,-Bsymbolic")
1622 }
1623 }
1624 case BuildModeShared:
1625 if ctxt.UseRelro() {
1626 argv = append(argv, "-Wl,-z,relro")
1627 }
1628 argv = append(argv, "-shared")
1629 case BuildModePlugin:
1630 if ctxt.HeadType == objabi.Hdarwin {
1631 argv = append(argv, "-dynamiclib")
1632 } else {
1633 if ctxt.UseRelro() {
1634 argv = append(argv, "-Wl,-z,relro")
1635 }
1636 argv = append(argv, "-shared")
1637 }
1638 }
1639
1640 var altLinker string
1641 if ctxt.IsELF && (ctxt.DynlinkingGo() || *flagBindNow) {
1642
1643
1644
1645
1646
1647 argv = append(argv, "-Wl,-z,now")
1648 }
1649
1650 if ctxt.IsELF && ctxt.DynlinkingGo() {
1651
1652
1653
1654 argv = append(argv, "-Wl,-z,nocopyreloc")
1655
1656 if buildcfg.GOOS == "android" {
1657
1658 altLinker = "lld"
1659 }
1660
1661 if ctxt.Arch.InFamily(sys.ARM64) && buildcfg.GOOS == "linux" {
1662
1663
1664
1665
1666
1667 altLinker = "gold"
1668
1669
1670
1671
1672 name, args := flagExtld[0], flagExtld[1:]
1673 args = append(args, "-fuse-ld=gold", "-Wl,--version")
1674 cmd := exec.Command(name, args...)
1675 if out, err := cmd.CombinedOutput(); err == nil {
1676 if !bytes.Contains(out, []byte("GNU gold")) {
1677 log.Fatalf("ARM64 external linker must be gold (issue #15696, 22040), but is not: %s", out)
1678 }
1679 }
1680 }
1681 }
1682 if ctxt.Arch.Family == sys.ARM64 && buildcfg.GOOS == "freebsd" {
1683
1684 altLinker = "bfd"
1685
1686
1687 name, args := flagExtld[0], flagExtld[1:]
1688 args = append(args, "-fuse-ld=bfd", "-Wl,--version")
1689 cmd := exec.Command(name, args...)
1690 if out, err := cmd.CombinedOutput(); err == nil {
1691 if !bytes.Contains(out, []byte("GNU ld")) {
1692 log.Fatalf("ARM64 external linker must be ld.bfd (issue #35197), please install devel/binutils")
1693 }
1694 }
1695 }
1696 if altLinker != "" {
1697 argv = append(argv, "-fuse-ld="+altLinker)
1698 }
1699
1700 if ctxt.IsELF && len(buildinfo) > 0 {
1701 argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
1702 }
1703
1704
1705
1706
1707
1708
1709
1710 outopt := *flagOutfile
1711 if buildcfg.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
1712 outopt += "."
1713 }
1714 argv = append(argv, "-o")
1715 argv = append(argv, outopt)
1716
1717 if rpath.val != "" {
1718 argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
1719 }
1720
1721 if *flagInterpreter != "" {
1722
1723
1724
1725
1726 argv = append(argv, fmt.Sprintf("-Wl,--dynamic-linker,%s", *flagInterpreter))
1727 }
1728
1729
1730 if ctxt.IsELF {
1731 if ctxt.DynlinkingGo() || ctxt.BuildMode == BuildModeCShared || !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "-Wl,--export-dynamic-symbol=main") {
1732 argv = append(argv, "-rdynamic")
1733 } else {
1734 var exports []string
1735 ctxt.loader.ForAllCgoExportDynamic(func(s loader.Sym) {
1736 exports = append(exports, "-Wl,--export-dynamic-symbol="+ctxt.loader.SymExtname(s))
1737 })
1738 sort.Strings(exports)
1739 argv = append(argv, exports...)
1740 }
1741 }
1742 if ctxt.HeadType == objabi.Haix {
1743 fileName := xcoffCreateExportFile(ctxt)
1744 argv = append(argv, "-Wl,-bE:"+fileName)
1745 }
1746
1747 const unusedArguments = "-Qunused-arguments"
1748 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, unusedArguments) {
1749 argv = append(argv, unusedArguments)
1750 }
1751
1752 if ctxt.IsWindows() {
1753
1754
1755
1756
1757 const noTimeStamp = "-Wl,--no-insert-timestamp"
1758 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, noTimeStamp) {
1759 argv = append(argv, noTimeStamp)
1760 }
1761 }
1762
1763 const compressDWARF = "-Wl,--compress-debug-sections=zlib"
1764 if ctxt.compressDWARF && linkerFlagSupported(ctxt.Arch, argv[0], altLinker, compressDWARF) {
1765 argv = append(argv, compressDWARF)
1766 }
1767
1768 hostObjCopyPaths := ctxt.hostobjCopy()
1769 cleanTimeStamps(hostObjCopyPaths)
1770 godotopath := filepath.Join(*flagTmpdir, "go.o")
1771 cleanTimeStamps([]string{godotopath})
1772
1773 argv = append(argv, godotopath)
1774 argv = append(argv, hostObjCopyPaths...)
1775 if ctxt.HeadType == objabi.Haix {
1776
1777
1778 argv = append(argv, "-nostartfiles")
1779 argv = append(argv, "/lib/crt0_64.o")
1780
1781 extld := ctxt.extld()
1782 name, args := extld[0], extld[1:]
1783
1784 getPathFile := func(file string) string {
1785 args := append(args, "-maix64", "--print-file-name="+file)
1786 out, err := exec.Command(name, args...).CombinedOutput()
1787 if err != nil {
1788 log.Fatalf("running %s failed: %v\n%s", extld, err, out)
1789 }
1790 return strings.Trim(string(out), "\n")
1791 }
1792
1793
1794
1795 crtcxa := getPathFile("crtcxa_64.o")
1796 if !filepath.IsAbs(crtcxa) {
1797 crtcxa = getPathFile("crtcxa.o")
1798 }
1799 crtdbase := getPathFile("crtdbase_64.o")
1800 if !filepath.IsAbs(crtdbase) {
1801 crtdbase = getPathFile("crtdbase.o")
1802 }
1803 argv = append(argv, crtcxa)
1804 argv = append(argv, crtdbase)
1805 }
1806
1807 if ctxt.linkShared {
1808 seenDirs := make(map[string]bool)
1809 seenLibs := make(map[string]bool)
1810 addshlib := func(path string) {
1811 dir, base := filepath.Split(path)
1812 if !seenDirs[dir] {
1813 argv = append(argv, "-L"+dir)
1814 if !rpath.set {
1815 argv = append(argv, "-Wl,-rpath="+dir)
1816 }
1817 seenDirs[dir] = true
1818 }
1819 base = strings.TrimSuffix(base, ".so")
1820 base = strings.TrimPrefix(base, "lib")
1821 if !seenLibs[base] {
1822 argv = append(argv, "-l"+base)
1823 seenLibs[base] = true
1824 }
1825 }
1826 for _, shlib := range ctxt.Shlibs {
1827 addshlib(shlib.Path)
1828 for _, dep := range shlib.Deps {
1829 if dep == "" {
1830 continue
1831 }
1832 libpath := findshlib(ctxt, dep)
1833 if libpath != "" {
1834 addshlib(libpath)
1835 }
1836 }
1837 }
1838 }
1839
1840
1841
1842
1843
1844
1845
1846
1847 checkStatic := func(arg string) {
1848 if ctxt.IsELF && arg == "-static" {
1849 for i := range argv {
1850 if argv[i] == "-rdynamic" || strings.HasPrefix(argv[i], "-Wl,--dynamic-linker,") {
1851 argv[i] = "-static"
1852 }
1853 }
1854 }
1855 }
1856
1857 for _, p := range ldflag {
1858 argv = append(argv, p)
1859 checkStatic(p)
1860 }
1861
1862
1863
1864
1865
1866
1867
1868
1869 if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared && !(ctxt.IsDarwin() && ctxt.IsARM64()) {
1870
1871 for _, nopie := range []string{"-no-pie", "-nopie"} {
1872 if linkerFlagSupported(ctxt.Arch, argv[0], altLinker, nopie) {
1873 argv = append(argv, nopie)
1874 break
1875 }
1876 }
1877 }
1878
1879 for _, p := range flagExtldflags {
1880 argv = append(argv, p)
1881 checkStatic(p)
1882 }
1883 if ctxt.HeadType == objabi.Hwindows {
1884
1885
1886 extld := ctxt.extld()
1887 name, args := extld[0], extld[1:]
1888 args = append(args, trimLinkerArgv(flagExtldflags)...)
1889 args = append(args, "-Wl,--version")
1890 cmd := exec.Command(name, args...)
1891 usingLLD := false
1892 if out, err := cmd.CombinedOutput(); err == nil {
1893 if bytes.Contains(out, []byte("LLD ")) {
1894 usingLLD = true
1895 }
1896 }
1897
1898
1899
1900 if !usingLLD {
1901 p := writeGDBLinkerScript()
1902 argv = append(argv, "-Wl,-T,"+p)
1903 }
1904 if *flagRace {
1905 if p := ctxt.findLibPath("libsynchronization.a"); p != "libsynchronization.a" {
1906 argv = append(argv, "-lsynchronization")
1907 }
1908 }
1909
1910
1911 argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
1912 argv = append(argv, peimporteddlls()...)
1913 }
1914
1915 argv = ctxt.passLongArgsInResponseFile(argv, altLinker)
1916
1917 if ctxt.Debugvlog != 0 {
1918 ctxt.Logf("host link:")
1919 for _, v := range argv {
1920 ctxt.Logf(" %q", v)
1921 }
1922 ctxt.Logf("\n")
1923 }
1924
1925 cmd := exec.Command(argv[0], argv[1:]...)
1926 out, err := cmd.CombinedOutput()
1927 if err != nil {
1928 Exitf("running %s failed: %v\n%s\n%s", argv[0], err, cmd, out)
1929 }
1930
1931
1932
1933 var save [][]byte
1934 var skipLines int
1935 for _, line := range bytes.SplitAfter(out, []byte("\n")) {
1936
1937 if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
1938 continue
1939 }
1940
1941 if skipLines > 0 {
1942 skipLines--
1943 continue
1944 }
1945
1946
1947 if bytes.Contains(line, []byte("ld: 0711-783")) {
1948 skipLines = 2
1949 continue
1950 }
1951
1952 save = append(save, line)
1953 }
1954 out = bytes.Join(save, nil)
1955
1956 if len(out) > 0 {
1957
1958
1959 if ctxt.IsDarwin() && ctxt.IsAMD64() {
1960 const noPieWarning = "ld: warning: -no_pie is deprecated when targeting new OS versions\n"
1961 if i := bytes.Index(out, []byte(noPieWarning)); i >= 0 {
1962
1963 out = append(out[:i], out[i+len(noPieWarning):]...)
1964 }
1965 }
1966 if ctxt.IsDarwin() {
1967 const bindAtLoadWarning = "ld: warning: -bind_at_load is deprecated on macOS\n"
1968 if i := bytes.Index(out, []byte(bindAtLoadWarning)); i >= 0 {
1969
1970
1971
1972
1973 out = append(out[:i], out[i+len(bindAtLoadWarning):]...)
1974 }
1975 }
1976 ctxt.Logf("%s", out)
1977 }
1978
1979
1980
1981 updateMachoOutFile := func(op string, updateFunc machoUpdateFunc) {
1982
1983 rewrittenOutput := *flagOutfile + "~"
1984 exef, err := os.Open(*flagOutfile)
1985 if err != nil {
1986 Exitf("%s: %s failed: %v", os.Args[0], op, err)
1987 }
1988 defer exef.Close()
1989 exem, err := macho.NewFile(exef)
1990 if err != nil {
1991 Exitf("%s: parsing Mach-O header failed: %v", os.Args[0], err)
1992 }
1993 if err := updateFunc(ctxt, exef, exem, rewrittenOutput); err != nil {
1994 Exitf("%s: %s failed: %v", os.Args[0], op, err)
1995 }
1996 os.Remove(*flagOutfile)
1997 if err := os.Rename(rewrittenOutput, *flagOutfile); err != nil {
1998 Exitf("%s: %v", os.Args[0], err)
1999 }
2000 }
2001
2002 uuidUpdated := false
2003 if combineDwarf {
2004
2005 dsymutilCmd := ctxt.findExtLinkTool("dsymutil")
2006 stripCmd := ctxt.findExtLinkTool("strip")
2007
2008 dsym := filepath.Join(*flagTmpdir, "go.dwarf")
2009 cmd := exec.Command(dsymutilCmd, "-f", *flagOutfile, "-o", dsym)
2010
2011
2012
2013
2014
2015 dsymDir := filepath.Join(*flagTmpdir, "dsymutil")
2016 err := os.MkdirAll(dsymDir, 0777)
2017 if err != nil {
2018 Exitf("fail to create temp dir: %v", err)
2019 }
2020 cmd.Env = append(os.Environ(), "DSYMUTIL_REPRODUCER_PATH="+dsymDir)
2021 if ctxt.Debugvlog != 0 {
2022 ctxt.Logf("host link dsymutil:")
2023 for _, v := range cmd.Args {
2024 ctxt.Logf(" %q", v)
2025 }
2026 ctxt.Logf("\n")
2027 }
2028 if out, err := cmd.CombinedOutput(); err != nil {
2029 Exitf("%s: running dsymutil failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
2030 }
2031
2032
2033 var stripArgs = []string{"-S"}
2034 if debug_s {
2035
2036
2037
2038 stripArgs = append(stripArgs, "-x")
2039 }
2040 stripArgs = append(stripArgs, *flagOutfile)
2041 if ctxt.Debugvlog != 0 {
2042 ctxt.Logf("host link strip: %q", stripCmd)
2043 for _, v := range stripArgs {
2044 ctxt.Logf(" %q", v)
2045 }
2046 ctxt.Logf("\n")
2047 }
2048 cmd = exec.Command(stripCmd, stripArgs...)
2049 if out, err := cmd.CombinedOutput(); err != nil {
2050 Exitf("%s: running strip failed: %v\n%s\n%s", os.Args[0], err, cmd, out)
2051 }
2052
2053 if _, err := os.Stat(dsym); err == nil {
2054 updateMachoOutFile("combining dwarf",
2055 func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
2056 return machoCombineDwarf(ctxt, exef, exem, dsym, outexe)
2057 })
2058 uuidUpdated = true
2059 }
2060 }
2061 if ctxt.IsDarwin() && !uuidUpdated && *flagBuildid != "" {
2062 updateMachoOutFile("rewriting uuid",
2063 func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
2064 return machoRewriteUuid(ctxt, exef, exem, outexe)
2065 })
2066 }
2067 if ctxt.NeedCodeSign() {
2068 err := machoCodeSign(ctxt, *flagOutfile)
2069 if err != nil {
2070 Exitf("%s: code signing failed: %v", os.Args[0], err)
2071 }
2072 }
2073 }
2074
2075
2076
2077 func (ctxt *Link) passLongArgsInResponseFile(argv []string, altLinker string) []string {
2078 c := 0
2079 for _, arg := range argv {
2080 c += len(arg)
2081 }
2082
2083 if c < sys.ExecArgLengthLimit {
2084 return argv
2085 }
2086
2087
2088 response := filepath.Join(*flagTmpdir, "response")
2089 if err := os.WriteFile(response, nil, 0644); err != nil {
2090 log.Fatalf("failed while testing response file: %v", err)
2091 }
2092 if !linkerFlagSupported(ctxt.Arch, argv[0], altLinker, "@"+response) {
2093 if ctxt.Debugvlog != 0 {
2094 ctxt.Logf("not using response file because linker does not support one")
2095 }
2096 return argv
2097 }
2098
2099 var buf bytes.Buffer
2100 for _, arg := range argv[1:] {
2101
2102 fmt.Fprintf(&buf, "%q\n", arg)
2103 }
2104 if err := os.WriteFile(response, buf.Bytes(), 0644); err != nil {
2105 log.Fatalf("failed while writing response file: %v", err)
2106 }
2107 if ctxt.Debugvlog != 0 {
2108 ctxt.Logf("response file %s contents:\n%s", response, buf.Bytes())
2109 }
2110 return []string{
2111 argv[0],
2112 "@" + response,
2113 }
2114 }
2115
2116 var createTrivialCOnce sync.Once
2117
2118 func linkerFlagSupported(arch *sys.Arch, linker, altLinker, flag string) bool {
2119 createTrivialCOnce.Do(func() {
2120 src := filepath.Join(*flagTmpdir, "trivial.c")
2121 if err := os.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
2122 Errorf(nil, "WriteFile trivial.c failed: %v", err)
2123 }
2124 })
2125
2126 flags := hostlinkArchArgs(arch)
2127
2128 moreFlags := trimLinkerArgv(append(flagExtldflags, ldflag...))
2129 flags = append(flags, moreFlags...)
2130
2131 if altLinker != "" {
2132 flags = append(flags, "-fuse-ld="+altLinker)
2133 }
2134 trivialPath := filepath.Join(*flagTmpdir, "trivial.c")
2135 outPath := filepath.Join(*flagTmpdir, "a.out")
2136 flags = append(flags, "-o", outPath, flag, trivialPath)
2137
2138 cmd := exec.Command(linker, flags...)
2139 cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
2140 out, err := cmd.CombinedOutput()
2141
2142
2143 return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
2144 }
2145
2146
2147
2148 func trimLinkerArgv(argv []string) []string {
2149 flagsWithNextArgSkip := []string{
2150 "-F",
2151 "-l",
2152 "-L",
2153 "-framework",
2154 "-Wl,-framework",
2155 "-Wl,-rpath",
2156 "-Wl,-undefined",
2157 }
2158 flagsWithNextArgKeep := []string{
2159 "-arch",
2160 "-isysroot",
2161 "--sysroot",
2162 "-target",
2163 }
2164 prefixesToKeep := []string{
2165 "-f",
2166 "-m",
2167 "-p",
2168 "-Wl,",
2169 "-arch",
2170 "-isysroot",
2171 "--sysroot",
2172 "-target",
2173 }
2174
2175 var flags []string
2176 keep := false
2177 skip := false
2178 for _, f := range argv {
2179 if keep {
2180 flags = append(flags, f)
2181 keep = false
2182 } else if skip {
2183 skip = false
2184 } else if f == "" || f[0] != '-' {
2185 } else if contains(flagsWithNextArgSkip, f) {
2186 skip = true
2187 } else if contains(flagsWithNextArgKeep, f) {
2188 flags = append(flags, f)
2189 keep = true
2190 } else {
2191 for _, p := range prefixesToKeep {
2192 if strings.HasPrefix(f, p) {
2193 flags = append(flags, f)
2194 break
2195 }
2196 }
2197 }
2198 }
2199 return flags
2200 }
2201
2202
2203
2204 func hostlinkArchArgs(arch *sys.Arch) []string {
2205 switch arch.Family {
2206 case sys.I386:
2207 return []string{"-m32"}
2208 case sys.AMD64:
2209 if buildcfg.GOOS == "darwin" {
2210 return []string{"-arch", "x86_64", "-m64"}
2211 }
2212 return []string{"-m64"}
2213 case sys.S390X:
2214 return []string{"-m64"}
2215 case sys.ARM:
2216 return []string{"-marm"}
2217 case sys.ARM64:
2218 if buildcfg.GOOS == "darwin" {
2219 return []string{"-arch", "arm64"}
2220 }
2221 case sys.Loong64:
2222 return []string{"-mabi=lp64d"}
2223 case sys.MIPS64:
2224 return []string{"-mabi=64"}
2225 case sys.MIPS:
2226 return []string{"-mabi=32"}
2227 case sys.PPC64:
2228 if buildcfg.GOOS == "aix" {
2229 return []string{"-maix64"}
2230 } else {
2231 return []string{"-m64"}
2232 }
2233
2234 }
2235 return nil
2236 }
2237
2238 var wantHdr = objabi.HeaderString()
2239
2240
2241
2242
2243 func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, file string) *Hostobj {
2244 pkg := objabi.PathToPrefix(lib.Pkg)
2245
2246 eof := f.Offset() + length
2247 start := f.Offset()
2248 c1 := bgetc(f)
2249 c2 := bgetc(f)
2250 c3 := bgetc(f)
2251 c4 := bgetc(f)
2252 f.MustSeek(start, 0)
2253
2254 unit := &sym.CompilationUnit{Lib: lib}
2255 lib.Units = append(lib.Units, unit)
2256
2257 magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
2258 if magic == 0x7f454c46 {
2259 ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2260 textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.Flags)
2261 if err != nil {
2262 Errorf(nil, "%v", err)
2263 return
2264 }
2265 ehdr.Flags = flags
2266 ctxt.Textp = append(ctxt.Textp, textp...)
2267 }
2268 return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
2269 }
2270
2271 if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
2272 ldmacho := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2273 textp, err := loadmacho.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2274 if err != nil {
2275 Errorf(nil, "%v", err)
2276 return
2277 }
2278 ctxt.Textp = append(ctxt.Textp, textp...)
2279 }
2280 return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
2281 }
2282
2283 switch c1<<8 | c2 {
2284 case 0x4c01,
2285 0x6486,
2286 0xc401,
2287 0x64aa:
2288 ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2289 ls, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2290 if err != nil {
2291 Errorf(nil, "%v", err)
2292 return
2293 }
2294 if len(ls.Resources) != 0 {
2295 setpersrc(ctxt, ls.Resources)
2296 }
2297 if ls.PData != 0 {
2298 sehp.pdata = append(sehp.pdata, ls.PData)
2299 }
2300 if ls.XData != 0 {
2301 sehp.xdata = append(sehp.xdata, ls.XData)
2302 }
2303 ctxt.Textp = append(ctxt.Textp, ls.Textp...)
2304 }
2305 return ldhostobj(ldpe, ctxt.HeadType, f, pkg, length, pn, file)
2306 }
2307
2308 if c1 == 0x01 && (c2 == 0xD7 || c2 == 0xF7) {
2309 ldxcoff := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
2310 textp, err := loadxcoff.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
2311 if err != nil {
2312 Errorf(nil, "%v", err)
2313 return
2314 }
2315 ctxt.Textp = append(ctxt.Textp, textp...)
2316 }
2317 return ldhostobj(ldxcoff, ctxt.HeadType, f, pkg, length, pn, file)
2318 }
2319
2320 if c1 != 'g' || c2 != 'o' || c3 != ' ' || c4 != 'o' {
2321
2322
2323
2324 unknownObjFormat = true
2325 return ldhostobj(nil, ctxt.HeadType, f, pkg, length, pn, file)
2326 }
2327
2328
2329 line, err := f.ReadString('\n')
2330 if err != nil {
2331 Errorf(nil, "truncated object file: %s: %v", pn, err)
2332 return nil
2333 }
2334
2335 if !strings.HasPrefix(line, "go object ") {
2336 if strings.HasSuffix(pn, ".go") {
2337 Exitf("%s: uncompiled .go source file", pn)
2338 return nil
2339 }
2340
2341 if line == ctxt.Arch.Name {
2342
2343 Errorf(nil, "%s: stale object file", pn)
2344 return nil
2345 }
2346
2347 Errorf(nil, "%s: not an object file: @%d %q", pn, start, line)
2348 return nil
2349 }
2350
2351
2352 if line != wantHdr {
2353 Errorf(nil, "%s: linked object header mismatch:\nhave %q\nwant %q\n", pn, line, wantHdr)
2354 }
2355
2356
2357
2358
2359
2360
2361
2362
2363 import0 := f.Offset()
2364
2365 c1 = '\n'
2366 c2 = bgetc(f)
2367 c3 = bgetc(f)
2368 markers := 0
2369 for {
2370 if c1 == '\n' {
2371 if markers%2 == 0 && c2 == '!' && c3 == '\n' {
2372 break
2373 }
2374 if c2 == '$' && c3 == '$' {
2375 markers++
2376 }
2377 }
2378
2379 c1 = c2
2380 c2 = c3
2381 c3 = bgetc(f)
2382 if c3 == -1 {
2383 Errorf(nil, "truncated object file: %s", pn)
2384 return nil
2385 }
2386 }
2387
2388 import1 := f.Offset()
2389
2390 f.MustSeek(import0, 0)
2391 ldpkg(ctxt, f, lib, import1-import0-2, pn)
2392 f.MustSeek(import1, 0)
2393
2394 fingerprint := ctxt.loader.Preload(ctxt.IncVersion(), f, lib, unit, eof-f.Offset())
2395 if !fingerprint.IsZero() {
2396
2397
2398
2399
2400
2401 if lib.Fingerprint.IsZero() {
2402 lib.Fingerprint = fingerprint
2403 }
2404 checkFingerprint(lib, fingerprint, lib.Srcref, lib.Fingerprint)
2405 }
2406
2407 addImports(ctxt, lib, pn)
2408 return nil
2409 }
2410
2411
2412
2413
2414
2415 func symbolsAreUnresolved(ctxt *Link, want []string) []bool {
2416 returnAllUndefs := -1
2417 undefs, _ := ctxt.loader.UndefinedRelocTargets(returnAllUndefs)
2418 seen := make(map[loader.Sym]struct{})
2419 rval := make([]bool, len(want))
2420 wantm := make(map[string]int)
2421 for k, w := range want {
2422 wantm[w] = k
2423 }
2424 count := 0
2425 for _, s := range undefs {
2426 if _, ok := seen[s]; ok {
2427 continue
2428 }
2429 seen[s] = struct{}{}
2430 if k, ok := wantm[ctxt.loader.SymName(s)]; ok {
2431 rval[k] = true
2432 count++
2433 if count == len(want) {
2434 return rval
2435 }
2436 }
2437 }
2438 return rval
2439 }
2440
2441
2442
2443
2444 func hostObject(ctxt *Link, objname string, path string) {
2445 if ctxt.Debugvlog > 1 {
2446 ctxt.Logf("hostObject(%s)\n", path)
2447 }
2448 objlib := sym.Library{
2449 Pkg: objname,
2450 }
2451 f, err := bio.Open(path)
2452 if err != nil {
2453 Exitf("cannot open host object %q file %s: %v", objname, path, err)
2454 }
2455 defer f.Close()
2456 h := ldobj(ctxt, f, &objlib, 0, path, path)
2457 if h.ld == nil {
2458 Exitf("unrecognized object file format in %s", path)
2459 }
2460 h.file = path
2461 h.length = f.MustSeek(0, 2)
2462 f.MustSeek(h.off, 0)
2463 h.ld(ctxt, f, h.pkg, h.length, h.pn)
2464 if *flagCaptureHostObjs != "" {
2465 captureHostObj(h)
2466 }
2467 }
2468
2469 func checkFingerprint(lib *sym.Library, libfp goobj.FingerprintType, src string, srcfp goobj.FingerprintType) {
2470 if libfp != srcfp {
2471 Exitf("fingerprint mismatch: %s has %x, import from %s expecting %x", lib, libfp, src, srcfp)
2472 }
2473 }
2474
2475 func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
2476 data := make([]byte, sym.Size)
2477 sect := f.Sections[sym.Section]
2478 if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
2479 Errorf(nil, "reading %s from non-data section", sym.Name)
2480 }
2481 n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
2482 if uint64(n) != sym.Size {
2483 Errorf(nil, "reading contents of %s: %v", sym.Name, err)
2484 }
2485 return data
2486 }
2487
2488 func readwithpad(r io.Reader, sz int32) ([]byte, error) {
2489 data := make([]byte, Rnd(int64(sz), 4))
2490 _, err := io.ReadFull(r, data)
2491 if err != nil {
2492 return nil, err
2493 }
2494 data = data[:sz]
2495 return data, nil
2496 }
2497
2498 func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
2499 for _, sect := range f.Sections {
2500 if sect.Type != elf.SHT_NOTE {
2501 continue
2502 }
2503 r := sect.Open()
2504 for {
2505 var namesize, descsize, noteType int32
2506 err := binary.Read(r, f.ByteOrder, &namesize)
2507 if err != nil {
2508 if err == io.EOF {
2509 break
2510 }
2511 return nil, fmt.Errorf("read namesize failed: %v", err)
2512 }
2513 err = binary.Read(r, f.ByteOrder, &descsize)
2514 if err != nil {
2515 return nil, fmt.Errorf("read descsize failed: %v", err)
2516 }
2517 err = binary.Read(r, f.ByteOrder, ¬eType)
2518 if err != nil {
2519 return nil, fmt.Errorf("read type failed: %v", err)
2520 }
2521 noteName, err := readwithpad(r, namesize)
2522 if err != nil {
2523 return nil, fmt.Errorf("read name failed: %v", err)
2524 }
2525 desc, err := readwithpad(r, descsize)
2526 if err != nil {
2527 return nil, fmt.Errorf("read desc failed: %v", err)
2528 }
2529 if string(name) == string(noteName) && typ == noteType {
2530 return desc, nil
2531 }
2532 }
2533 }
2534 return nil, nil
2535 }
2536
2537 func findshlib(ctxt *Link, shlib string) string {
2538 if filepath.IsAbs(shlib) {
2539 return shlib
2540 }
2541 for _, libdir := range ctxt.Libdir {
2542 libpath := filepath.Join(libdir, shlib)
2543 if _, err := os.Stat(libpath); err == nil {
2544 return libpath
2545 }
2546 }
2547 Errorf(nil, "cannot find shared library: %s", shlib)
2548 return ""
2549 }
2550
2551 func ldshlibsyms(ctxt *Link, shlib string) {
2552 var libpath string
2553 if filepath.IsAbs(shlib) {
2554 libpath = shlib
2555 shlib = filepath.Base(shlib)
2556 } else {
2557 libpath = findshlib(ctxt, shlib)
2558 if libpath == "" {
2559 return
2560 }
2561 }
2562 for _, processedlib := range ctxt.Shlibs {
2563 if processedlib.Path == libpath {
2564 return
2565 }
2566 }
2567 if ctxt.Debugvlog > 1 {
2568 ctxt.Logf("ldshlibsyms: found library with name %s at %s\n", shlib, libpath)
2569 }
2570
2571 f, err := elf.Open(libpath)
2572 if err != nil {
2573 Errorf(nil, "cannot open shared library: %s", libpath)
2574 return
2575 }
2576
2577
2578
2579
2580 hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
2581 if err != nil {
2582 Errorf(nil, "cannot read ABI hash from shared library %s: %v", libpath, err)
2583 return
2584 }
2585
2586 depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
2587 if err != nil {
2588 Errorf(nil, "cannot read dep list from shared library %s: %v", libpath, err)
2589 return
2590 }
2591 var deps []string
2592 for _, dep := range strings.Split(string(depsbytes), "\n") {
2593 if dep == "" {
2594 continue
2595 }
2596 if !filepath.IsAbs(dep) {
2597
2598
2599
2600 abs := filepath.Join(filepath.Dir(libpath), dep)
2601 if _, err := os.Stat(abs); err == nil {
2602 dep = abs
2603 }
2604 }
2605 deps = append(deps, dep)
2606 }
2607
2608 syms, err := f.DynamicSymbols()
2609 if err != nil {
2610 Errorf(nil, "cannot read symbols from shared library: %s", libpath)
2611 return
2612 }
2613
2614 for _, elfsym := range syms {
2615 if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
2616 continue
2617 }
2618
2619
2620
2621 ver := 0
2622 symname := elfsym.Name
2623 if elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC && strings.HasPrefix(elfsym.Name, "type:") {
2624 ver = abiInternalVer
2625 } else if buildcfg.Experiment.RegabiWrappers && elf.ST_TYPE(elfsym.Info) == elf.STT_FUNC {
2626
2627 if strings.HasSuffix(elfsym.Name, ".abiinternal") {
2628 ver = sym.SymVerABIInternal
2629 symname = strings.TrimSuffix(elfsym.Name, ".abiinternal")
2630 } else if strings.HasSuffix(elfsym.Name, ".abi0") {
2631 ver = 0
2632 symname = strings.TrimSuffix(elfsym.Name, ".abi0")
2633 }
2634 }
2635
2636 l := ctxt.loader
2637 s := l.LookupOrCreateSym(symname, ver)
2638
2639
2640
2641
2642
2643 if l.SymType(s) != 0 && l.SymType(s) != sym.SDYNIMPORT {
2644 continue
2645 }
2646 su := l.MakeSymbolUpdater(s)
2647 su.SetType(sym.SDYNIMPORT)
2648 l.SetSymElfType(s, elf.ST_TYPE(elfsym.Info))
2649 su.SetSize(int64(elfsym.Size))
2650 if elfsym.Section != elf.SHN_UNDEF {
2651
2652 l.SetSymPkg(s, libpath)
2653
2654
2655
2656 sname := l.SymName(s)
2657 if strings.HasPrefix(sname, "type:") && !strings.HasPrefix(sname, "type:.") {
2658 su.SetData(readelfsymboldata(ctxt, f, &elfsym))
2659 }
2660 }
2661
2662 if symname != elfsym.Name {
2663 l.SetSymExtname(s, elfsym.Name)
2664 }
2665 }
2666 ctxt.Shlibs = append(ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f})
2667 }
2668
2669 func addsection(ldr *loader.Loader, arch *sys.Arch, seg *sym.Segment, name string, rwx int) *sym.Section {
2670 sect := ldr.NewSection()
2671 sect.Rwx = uint8(rwx)
2672 sect.Name = name
2673 sect.Seg = seg
2674 sect.Align = int32(arch.PtrSize)
2675 seg.Sections = append(seg.Sections, sect)
2676 return sect
2677 }
2678
2679 func usage() {
2680 fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
2681 objabi.Flagprint(os.Stderr)
2682 Exit(2)
2683 }
2684
2685 type SymbolType int8
2686
2687 const (
2688
2689 TextSym SymbolType = 'T'
2690 DataSym SymbolType = 'D'
2691 BSSSym SymbolType = 'B'
2692 UndefinedSym SymbolType = 'U'
2693 TLSSym SymbolType = 't'
2694 FrameSym SymbolType = 'm'
2695 ParamSym SymbolType = 'p'
2696 AutoSym SymbolType = 'a'
2697
2698
2699 DeletedAutoSym = 'x'
2700 )
2701
2702
2703 func (ctxt *Link) defineInternal(p string, t sym.SymKind) loader.Sym {
2704 s := ctxt.loader.CreateSymForUpdate(p, 0)
2705 s.SetType(t)
2706 s.SetSpecial(true)
2707 s.SetLocal(true)
2708 return s.Sym()
2709 }
2710
2711 func (ctxt *Link) xdefine(p string, t sym.SymKind, v int64) loader.Sym {
2712 s := ctxt.defineInternal(p, t)
2713 ctxt.loader.SetSymValue(s, v)
2714 return s
2715 }
2716
2717 func datoff(ldr *loader.Loader, s loader.Sym, addr int64) int64 {
2718 if uint64(addr) >= Segdata.Vaddr {
2719 return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
2720 }
2721 if uint64(addr) >= Segtext.Vaddr {
2722 return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
2723 }
2724 ldr.Errorf(s, "invalid datoff %#x", addr)
2725 return 0
2726 }
2727
2728 func Entryvalue(ctxt *Link) int64 {
2729 a := *flagEntrySymbol
2730 if a[0] >= '0' && a[0] <= '9' {
2731 return atolwhex(a)
2732 }
2733 ldr := ctxt.loader
2734 s := ldr.Lookup(a, 0)
2735 if s == 0 {
2736 Errorf(nil, "missing entry symbol %q", a)
2737 return 0
2738 }
2739 st := ldr.SymType(s)
2740 if st == 0 {
2741 return *FlagTextAddr
2742 }
2743 if !ctxt.IsAIX() && st != sym.STEXT {
2744 ldr.Errorf(s, "entry not text")
2745 }
2746 return ldr.SymValue(s)
2747 }
2748
2749 func (ctxt *Link) callgraph() {
2750 if !*FlagC {
2751 return
2752 }
2753
2754 ldr := ctxt.loader
2755 for _, s := range ctxt.Textp {
2756 relocs := ldr.Relocs(s)
2757 for i := 0; i < relocs.Count(); i++ {
2758 r := relocs.At(i)
2759 rs := r.Sym()
2760 if rs == 0 {
2761 continue
2762 }
2763 if r.Type().IsDirectCall() && ldr.SymType(rs) == sym.STEXT {
2764 ctxt.Logf("%s calls %s\n", ldr.SymName(s), ldr.SymName(rs))
2765 }
2766 }
2767 }
2768 }
2769
2770 func Rnd(v int64, r int64) int64 {
2771 if r <= 0 {
2772 return v
2773 }
2774 v += r - 1
2775 c := v % r
2776 if c < 0 {
2777 c += r
2778 }
2779 v -= c
2780 return v
2781 }
2782
2783 func bgetc(r *bio.Reader) int {
2784 c, err := r.ReadByte()
2785 if err != nil {
2786 if err != io.EOF {
2787 log.Fatalf("reading input: %v", err)
2788 }
2789 return -1
2790 }
2791 return int(c)
2792 }
2793
2794 type markKind uint8
2795 const (
2796 _ markKind = iota
2797 visiting
2798 visited
2799 )
2800
2801 func postorder(libs []*sym.Library) []*sym.Library {
2802 order := make([]*sym.Library, 0, len(libs))
2803 mark := make(map[*sym.Library]markKind, len(libs))
2804 for _, lib := range libs {
2805 dfs(lib, mark, &order)
2806 }
2807 return order
2808 }
2809
2810 func dfs(lib *sym.Library, mark map[*sym.Library]markKind, order *[]*sym.Library) {
2811 if mark[lib] == visited {
2812 return
2813 }
2814 if mark[lib] == visiting {
2815 panic("found import cycle while visiting " + lib.Pkg)
2816 }
2817 mark[lib] = visiting
2818 for _, i := range lib.Imports {
2819 dfs(i, mark, order)
2820 }
2821 mark[lib] = visited
2822 *order = append(*order, lib)
2823 }
2824
2825 func ElfSymForReloc(ctxt *Link, s loader.Sym) int32 {
2826
2827
2828 les := ctxt.loader.SymLocalElfSym(s)
2829 if les != 0 {
2830 return les
2831 } else {
2832 return ctxt.loader.SymElfSym(s)
2833 }
2834 }
2835
2836 func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, elfRelocTyp uint32) {
2837 if ldr.SymGot(s) >= 0 {
2838 return
2839 }
2840
2841 Adddynsym(ldr, target, syms, s)
2842 got := ldr.MakeSymbolUpdater(syms.GOT)
2843 ldr.SetGot(s, int32(got.Size()))
2844 got.AddUint(target.Arch, 0)
2845
2846 if target.IsElf() {
2847 if target.Arch.PtrSize == 8 {
2848 rela := ldr.MakeSymbolUpdater(syms.Rela)
2849 rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
2850 rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
2851 rela.AddUint64(target.Arch, 0)
2852 } else {
2853 rel := ldr.MakeSymbolUpdater(syms.Rel)
2854 rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
2855 rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), elfRelocTyp))
2856 }
2857 } else if target.IsDarwin() {
2858 leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
2859 leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
2860 if target.IsPIE() && target.IsInternal() {
2861
2862
2863
2864 MachoAddBind(int64(ldr.SymGot(s)), s)
2865 }
2866 } else {
2867 ldr.Errorf(s, "addgotsym: unsupported binary format")
2868 }
2869 }
2870
2871 var hostobjcounter int
2872
2873
2874
2875
2876
2877
2878 func captureHostObj(h *Hostobj) {
2879
2880 ofile := fmt.Sprintf("captured-obj-%d.o", hostobjcounter)
2881 ifile := fmt.Sprintf("captured-obj-%d.txt", hostobjcounter)
2882 hostobjcounter++
2883 opath := filepath.Join(*flagCaptureHostObjs, ofile)
2884 ipath := filepath.Join(*flagCaptureHostObjs, ifile)
2885
2886
2887 info := fmt.Sprintf("pkg: %s\npn: %s\nfile: %s\noff: %d\nlen: %d\n",
2888 h.pkg, h.pn, h.file, h.off, h.length)
2889 if err := os.WriteFile(ipath, []byte(info), 0666); err != nil {
2890 log.Fatalf("error writing captured host obj info %s: %v", ipath, err)
2891 }
2892
2893 readObjData := func() []byte {
2894 inf, err := os.Open(h.file)
2895 if err != nil {
2896 log.Fatalf("capturing host obj: open failed on %s: %v", h.pn, err)
2897 }
2898 defer inf.Close()
2899 res := make([]byte, h.length)
2900 if n, err := inf.ReadAt(res, h.off); err != nil || n != int(h.length) {
2901 log.Fatalf("capturing host obj: readat failed on %s: %v", h.pn, err)
2902 }
2903 return res
2904 }
2905
2906
2907 if err := os.WriteFile(opath, readObjData(), 0666); err != nil {
2908 log.Fatalf("error writing captured host object %s: %v", opath, err)
2909 }
2910
2911 fmt.Fprintf(os.Stderr, "link: info: captured host object %s to %s\n",
2912 h.file, opath)
2913 }
2914
2915
2916
2917
2918 func (ctxt *Link) findExtLinkTool(toolname string) string {
2919 var cc []string
2920 cc = append(cc, ctxt.extld()...)
2921 cc = append(cc, hostlinkArchArgs(ctxt.Arch)...)
2922 cc = append(cc, "--print-prog-name", toolname)
2923 out, err := exec.Command(cc[0], cc[1:]...).CombinedOutput()
2924 if err != nil {
2925 Exitf("%s: finding %s failed: %v\n%s", os.Args[0], toolname, err, out)
2926 }
2927 cmdpath := strings.TrimRight(string(out), "\r\n")
2928 return cmdpath
2929 }
2930
View as plain text