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 "bufio"
35 "cmd/internal/goobj"
36 "cmd/internal/objabi"
37 "cmd/internal/quoted"
38 "cmd/internal/sys"
39 "cmd/internal/telemetry/counter"
40 "cmd/link/internal/benchmark"
41 "flag"
42 "internal/buildcfg"
43 "log"
44 "os"
45 "runtime"
46 "runtime/pprof"
47 "strconv"
48 "strings"
49 )
50
51 var (
52 pkglistfornote []byte
53 windowsgui bool
54 ownTmpDir bool
55 )
56
57 func init() {
58 flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...")
59 flag.Var(&flagExtld, "extld", "use `linker` when linking in external mode")
60 flag.Var(&flagExtldflags, "extldflags", "pass `flags` to external linker")
61 flag.Var(&flagW, "w", "disable DWARF generation")
62 }
63
64
65 var (
66 flagBuildid = flag.String("buildid", "", "record `id` as Go toolchain build id")
67 flagBindNow = flag.Bool("bindnow", false, "mark a dynamically linked ELF object for immediate function binding")
68
69 flagOutfile = flag.String("o", "", "write output to `file`")
70 flagPluginPath = flag.String("pluginpath", "", "full path name for plugin")
71 flagFipso = flag.String("fipso", "", "write fips module to `file`")
72
73 flagInstallSuffix = flag.String("installsuffix", "", "set package directory `suffix`")
74 flagDumpDep = flag.Bool("dumpdep", false, "dump symbol dependency graph")
75 flagRace = flag.Bool("race", false, "enable race detector")
76 flagMsan = flag.Bool("msan", false, "enable MSan interface")
77 flagAsan = flag.Bool("asan", false, "enable ASan interface")
78 flagAslr = flag.Bool("aslr", true, "enable ASLR for buildmode=c-shared on windows")
79
80 flagFieldTrack = flag.String("k", "", "set field tracking `symbol`")
81 flagLibGCC = flag.String("libgcc", "", "compiler support lib for internal linking; use \"none\" to disable")
82 flagTmpdir = flag.String("tmpdir", "", "use `directory` for temporary files")
83
84 flagExtld quoted.Flag
85 flagExtldflags quoted.Flag
86 flagExtar = flag.String("extar", "", "archive program for buildmode=c-archive")
87
88 flagCaptureHostObjs = flag.String("capturehostobjs", "", "capture host object files loaded during internal linking to specified dir")
89
90 flagA = flag.Bool("a", false, "no-op (deprecated)")
91 FlagC = flag.Bool("c", false, "dump call graph")
92 FlagD = flag.Bool("d", false, "disable dynamic executable")
93 flagF = flag.Bool("f", false, "ignore version mismatch")
94 flagG = flag.Bool("g", false, "disable go package data checks")
95 flagH = flag.Bool("h", false, "halt on error")
96 flagN = flag.Bool("n", false, "no-op (deprecated)")
97 FlagS = flag.Bool("s", false, "disable symbol table")
98 flag8 bool
99 flagHostBuildid = flag.String("B", "", "set ELF NT_GNU_BUILD_ID `note` or Mach-O UUID; use \"gobuildid\" to generate it from the Go build ID; \"none\" to disable")
100 flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
101 flagCheckLinkname = flag.Bool("checklinkname", true, "check linkname symbol references")
102 FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines")
103 FlagDebugTextSize = flag.Int("debugtextsize", 0, "debug text section max size")
104 flagDebugNosplit = flag.Bool("debugnosplit", false, "dump nosplit call graph")
105 FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
106 FlagRound = flag.Int64("R", -1, "set address rounding `quantum`")
107 FlagTextAddr = flag.Int64("T", -1, "set the start address of text symbols")
108 flagEntrySymbol = flag.String("E", "", "set `entry` symbol name")
109 flagPruneWeakMap = flag.Bool("pruneweakmap", true, "prune weak mapinit refs")
110 flagRandLayout = flag.Int64("randlayout", 0, "randomize function layout")
111 cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
112 memprofile = flag.String("memprofile", "", "write memory profile to `file`")
113 memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
114 benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking")
115 benchmarkFileFlag = flag.String("benchmarkprofile", "", "emit phase profiles to `base`_phase.{cpu,mem}prof")
116
117 flagW ternaryFlag
118 FlagW = new(bool)
119 )
120
121
122
123
124
125 type ternaryFlag int
126
127 const (
128 ternaryFlagUnset ternaryFlag = iota
129 ternaryFlagFalse
130 ternaryFlagTrue
131 )
132
133 func (t *ternaryFlag) Set(s string) error {
134 v, err := strconv.ParseBool(s)
135 if err != nil {
136 return err
137 }
138 if v {
139 *t = ternaryFlagTrue
140 } else {
141 *t = ternaryFlagFalse
142 }
143 return nil
144 }
145
146 func (t *ternaryFlag) String() string {
147 switch *t {
148 case ternaryFlagFalse:
149 return "false"
150 case ternaryFlagTrue:
151 return "true"
152 }
153 return "unset"
154 }
155
156 func (t *ternaryFlag) IsBoolFlag() bool { return true }
157
158
159 func Main(arch *sys.Arch, theArch Arch) {
160 log.SetPrefix("link: ")
161 log.SetFlags(0)
162 counter.Open()
163 counter.Inc("link/invocations")
164
165 thearch = theArch
166 ctxt := linknew(arch)
167 ctxt.Bso = bufio.NewWriter(os.Stdout)
168
169
170
171
172 for _, arg := range os.Args {
173 if arg == "-crash_for_testing" {
174 os.Exit(2)
175 }
176 }
177
178 if buildcfg.GOROOT == "" {
179
180
181
182 } else {
183 addstrdata1(ctxt, "runtime.defaultGOROOT="+buildcfg.GOROOT)
184 }
185
186 buildVersion := buildcfg.Version
187 if goexperiment := buildcfg.Experiment.String(); goexperiment != "" {
188 buildVersion += " X:" + goexperiment
189 }
190 addstrdata1(ctxt, "runtime.buildVersion="+buildVersion)
191
192
193 if ctxt.Arch.Family == sys.AMD64 && buildcfg.GOOS == "plan9" {
194 flag.BoolVar(&flag8, "8", false, "use 64-bit addresses in symbol table")
195 }
196 flagHeadType := flag.String("H", "", "set header `type`")
197 flag.BoolVar(&ctxt.linkShared, "linkshared", false, "link against installed Go shared libraries")
198 flag.Var(&ctxt.LinkMode, "linkmode", "set link `mode`")
199 flag.Var(&ctxt.BuildMode, "buildmode", "set build `mode`")
200 flag.BoolVar(&ctxt.compressDWARF, "compressdwarf", true, "compress DWARF if possible")
201 objabi.Flagfn1("L", "add specified `directory` to library path", func(a string) { Lflag(ctxt, a) })
202 objabi.AddVersionFlag()
203 objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) })
204 objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog)
205 objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg)
206
207 objabi.Flagparse(usage)
208 counter.CountFlags("link/flag:", *flag.CommandLine)
209
210 if ctxt.Debugvlog > 0 {
211
212 defer func() { ctxt.loader.Dump() }()
213 }
214 if ctxt.Debugvlog > 1 {
215
216 AtExit(func() {
217 if nerrors > 0 {
218 ctxt.loader.Dump()
219 }
220 })
221 }
222
223 switch *flagHeadType {
224 case "":
225 case "windowsgui":
226 ctxt.HeadType = objabi.Hwindows
227 windowsgui = true
228 default:
229 if err := ctxt.HeadType.Set(*flagHeadType); err != nil {
230 Errorf("%v", err)
231 usage()
232 }
233 }
234 if ctxt.HeadType == objabi.Hunknown {
235 ctxt.HeadType.Set(buildcfg.GOOS)
236 }
237
238 if !*flagAslr && ctxt.BuildMode != BuildModeCShared {
239 Errorf("-aslr=false is only allowed for -buildmode=c-shared")
240 usage()
241 }
242
243 if *FlagD && ctxt.UsesLibc() {
244 Exitf("dynamic linking required on %s; -d flag cannot be used", buildcfg.GOOS)
245 }
246
247 isPowerOfTwo := func(n int64) bool {
248 return n > 0 && n&(n-1) == 0
249 }
250 if *FlagRound != -1 && (*FlagRound < 4096 || !isPowerOfTwo(*FlagRound)) {
251 Exitf("invalid -R value 0x%x", *FlagRound)
252 }
253
254 checkStrictDups = *FlagStrictDups
255
256 switch flagW {
257 case ternaryFlagFalse:
258 *FlagW = false
259 case ternaryFlagTrue:
260 *FlagW = true
261 case ternaryFlagUnset:
262 *FlagW = *FlagS
263 if ctxt.IsDarwin() && ctxt.BuildMode == BuildModeCShared {
264 *FlagW = true
265 }
266 }
267
268 if !buildcfg.Experiment.RegabiWrappers {
269 abiInternalVer = 0
270 }
271
272 startProfile()
273 if ctxt.BuildMode == BuildModeUnset {
274 ctxt.BuildMode.Set("exe")
275 }
276
277 if ctxt.BuildMode != BuildModeShared && flag.NArg() != 1 {
278 usage()
279 }
280
281 if *flagOutfile == "" {
282 *flagOutfile = "a.out"
283 if ctxt.HeadType == objabi.Hwindows {
284 *flagOutfile += ".exe"
285 }
286 }
287
288 interpreter = *flagInterpreter
289
290 if *flagBuildid == "" && ctxt.Target.IsOpenbsd() {
291
292
293
294
295 *flagBuildid = "go-openbsd"
296 }
297
298 if *flagHostBuildid == "" && *flagBuildid != "" {
299 *flagHostBuildid = "gobuildid"
300 }
301 addbuildinfo(ctxt)
302
303
304 var bench *benchmark.Metrics
305 if len(*benchmarkFlag) != 0 {
306 if *benchmarkFlag == "mem" {
307 bench = benchmark.New(benchmark.GC, *benchmarkFileFlag)
308 } else if *benchmarkFlag == "cpu" {
309 bench = benchmark.New(benchmark.NoGC, *benchmarkFileFlag)
310 } else {
311 Errorf("unknown benchmark flag: %q", *benchmarkFlag)
312 usage()
313 }
314 }
315
316 bench.Start("libinit")
317 libinit(ctxt)
318 bench.Start("computeTLSOffset")
319 ctxt.computeTLSOffset()
320 bench.Start("Archinit")
321 thearch.Archinit(ctxt)
322
323 if ctxt.linkShared && !ctxt.IsELF {
324 Exitf("-linkshared can only be used on elf systems")
325 }
326
327 if ctxt.Debugvlog != 0 {
328 onOff := func(b bool) string {
329 if b {
330 return "on"
331 }
332 return "off"
333 }
334 ctxt.Logf("build mode: %s, symbol table: %s, DWARF: %s\n", ctxt.BuildMode, onOff(!*FlagS), onOff(dwarfEnabled(ctxt)))
335 ctxt.Logf("HEADER = -H%d -T0x%x -R0x%x\n", ctxt.HeadType, uint64(*FlagTextAddr), uint32(*FlagRound))
336 }
337
338 zerofp := goobj.FingerprintType{}
339 switch ctxt.BuildMode {
340 case BuildModeShared:
341 for i := 0; i < flag.NArg(); i++ {
342 arg := flag.Arg(i)
343 parts := strings.SplitN(arg, "=", 2)
344 var pkgpath, file string
345 if len(parts) == 1 {
346 pkgpath, file = "main", arg
347 } else {
348 pkgpath, file = parts[0], parts[1]
349 }
350 pkglistfornote = append(pkglistfornote, pkgpath...)
351 pkglistfornote = append(pkglistfornote, '\n')
352 addlibpath(ctxt, "command line", "command line", file, pkgpath, "", zerofp)
353 }
354 case BuildModePlugin:
355 addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "", zerofp)
356 default:
357 addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "", zerofp)
358 }
359 bench.Start("loadlib")
360 ctxt.loadlib()
361
362 bench.Start("inittasks")
363 ctxt.inittasks()
364
365 bench.Start("deadcode")
366 deadcode(ctxt)
367
368 bench.Start("linksetup")
369 ctxt.linksetup()
370
371 bench.Start("dostrdata")
372 ctxt.dostrdata()
373 if buildcfg.Experiment.FieldTrack {
374 bench.Start("fieldtrack")
375 fieldtrack(ctxt.Arch, ctxt.loader)
376 }
377
378 bench.Start("dwarfGenerateDebugInfo")
379 dwarfGenerateDebugInfo(ctxt)
380
381 bench.Start("callgraph")
382 ctxt.callgraph()
383
384 bench.Start("doStackCheck")
385 ctxt.doStackCheck()
386
387 bench.Start("mangleTypeSym")
388 ctxt.mangleTypeSym()
389
390 if ctxt.IsELF {
391 bench.Start("doelf")
392 ctxt.doelf()
393 }
394 if ctxt.IsDarwin() {
395 bench.Start("domacho")
396 ctxt.domacho()
397 }
398 if ctxt.IsWindows() {
399 bench.Start("dope")
400 ctxt.dope()
401 bench.Start("windynrelocsyms")
402 ctxt.windynrelocsyms()
403 }
404 if ctxt.IsAIX() {
405 bench.Start("doxcoff")
406 ctxt.doxcoff()
407 }
408
409 bench.Start("textbuildid")
410 ctxt.textbuildid()
411 bench.Start("addexport")
412 ctxt.setArchSyms()
413 ctxt.addexport()
414 bench.Start("Gentext")
415 thearch.Gentext(ctxt, ctxt.loader)
416
417 bench.Start("textaddress")
418 ctxt.textaddress()
419 bench.Start("typelink")
420 ctxt.typelink()
421 bench.Start("buildinfo")
422 ctxt.buildinfo()
423 bench.Start("pclntab")
424 containers := ctxt.findContainerSyms()
425 pclnState := ctxt.pclntab(containers)
426 bench.Start("findfunctab")
427 ctxt.findfunctab(pclnState, containers)
428 bench.Start("dwarfGenerateDebugSyms")
429 dwarfGenerateDebugSyms(ctxt)
430 bench.Start("symtab")
431 symGroupType := ctxt.symtab(pclnState)
432 bench.Start("dodata")
433 ctxt.dodata(symGroupType)
434 bench.Start("address")
435 order := ctxt.address()
436 bench.Start("dwarfcompress")
437 dwarfcompress(ctxt)
438 bench.Start("layout")
439 filesize := ctxt.layout(order)
440
441
442
443
444
445
446
447 if ctxt.Arch.Family != sys.Wasm {
448
449
450 if err := ctxt.Out.Mmap(filesize); err != nil {
451 Exitf("mapping output file failed: %v", err)
452 }
453 }
454
455
456 bench.Start("Asmb")
457 asmb(ctxt)
458 exitIfErrors()
459
460
461
462 bench.Start("GenSymsLate")
463 if thearch.GenSymsLate != nil {
464 thearch.GenSymsLate(ctxt, ctxt.loader)
465 }
466
467 asmbfips(ctxt, *flagFipso)
468
469 bench.Start("Asmb2")
470 asmb2(ctxt)
471
472 bench.Start("Munmap")
473 ctxt.Out.Close()
474
475 bench.Start("hostlink")
476 ctxt.hostlink()
477 if ctxt.Debugvlog != 0 {
478 ctxt.Logf("%s", ctxt.loader.Stat())
479 ctxt.Logf("%d liveness data\n", liveness)
480 }
481 bench.Start("Flush")
482 ctxt.Bso.Flush()
483 bench.Start("archive")
484 ctxt.archive()
485 bench.Report(os.Stdout)
486
487 errorexit()
488 }
489
490 type Rpath struct {
491 set bool
492 val string
493 }
494
495 func (r *Rpath) Set(val string) error {
496 r.set = true
497 r.val = val
498 return nil
499 }
500
501 func (r *Rpath) String() string {
502 return r.val
503 }
504
505 func startProfile() {
506 if *cpuprofile != "" {
507 f, err := os.Create(*cpuprofile)
508 if err != nil {
509 log.Fatalf("%v", err)
510 }
511 if err := pprof.StartCPUProfile(f); err != nil {
512 log.Fatalf("%v", err)
513 }
514 AtExit(func() {
515 pprof.StopCPUProfile()
516 if err = f.Close(); err != nil {
517 log.Fatalf("error closing cpu profile: %v", err)
518 }
519 })
520 }
521 if *memprofile != "" {
522 if *memprofilerate != 0 {
523 runtime.MemProfileRate = int(*memprofilerate)
524 }
525 f, err := os.Create(*memprofile)
526 if err != nil {
527 log.Fatalf("%v", err)
528 }
529 AtExit(func() {
530
531 runtime.GC()
532
533
534
535 const writeLegacyFormat = 1
536 if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil {
537 log.Fatalf("%v", err)
538 }
539
540 if err := f.Close(); err != nil {
541 log.Fatalf("could not close %v: %v", *memprofile, err)
542 }
543 })
544 }
545 }
546
View as plain text