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